From bd822da70b89ad9ab6a4ffb20e60fe09c76e97e0 Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Mon, 15 Sep 2025 09:37:01 +0100 Subject: [PATCH 01/12] add dodgy transaction data and set up logger --- data/DodgyTransactions2015.csv | 52 ++++++++++++++++++++++++++ package-lock.json | 68 +++++++++++++++++++++++++++++++--- package.json | 1 + utils/setUpLogger.ts | 6 +++ 4 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 data/DodgyTransactions2015.csv create mode 100644 utils/setUpLogger.ts diff --git a/data/DodgyTransactions2015.csv b/data/DodgyTransactions2015.csv new file mode 100644 index 0000000..e443ddf --- /dev/null +++ b/data/DodgyTransactions2015.csv @@ -0,0 +1,52 @@ +Date,From,To,Narrative,Amount +01/01/2015,Laura B,Sarah T,Misc Morale,10.54 +04/01/2015,Stephen S,Gergana I,Lunch,3.22 +07/01/2015,Ben B,Jon A,Fantasy Football,9.93 +11/01/2015,Ben B,Todd,Lunch,7.33 +12/01/2015,Laura B,Ben B,Beers,8.94 +15/01/2015,Todd,Rob S,Beers,10.19 +16/01/2015,Laura B,Jon A,Lego Assistance,0.69 +18/01/2015,Jon A,Sarah T,Coffee,10.73 +22/01/2015,Gergana I,Todd,Coffee,0.8 +24/01/2015,Gergana I,Chris W,Coffee,8.49 +27/01/2015,Laura B,Tim L,Jenkins Fees,0.52 +29/01/2015,Sam N,Chris W,Lunch,9.01 +01/02/2015,Stephen S,Laura B,Coffee,7.53 +02/02/2015,Stephen S,Rob S,Fantasy Football,7.43 +04/02/2015,Rob S,Stephen S,Fantasy Football,5.78 +06/02/2015,Dan W,Gergana I,Automated Testing Services,10.29 +07/02/2015,Jon A,Chris W,Rails Consultancy,7.37 +10/02/2015,Sam N,Gergana I,Sandbox Help,9.84 +11/02/2015,Chris W,Stephen S,Misc Morale,0.68 +13/02/2015,Laura B,Gergana I,Beers,6.56 +16/02/2015,Chris W,Dan W,Jenkins Fees,1.28 +17/02/2015,Sarah T,Dan W,Sandbox Help,11.48 +18/02/2015,Stephen S,Rob S,Lego Assistance,4.83 +21/02/2015,Dan W,Ben B,Pokemon Training,0.5 +24/02/2015,Todd,Gergana I,Coffee,9.08 +26/02/2015,Stephen S,Jon A,Pokemon Training,4.23 +01/03/2015,Ben B,Sam N,Lunch,One Cheeseburger +02/03/2015,Todd,Chris W,Sandbox Help,1.92 +04/03/2015,Laura B,Jon A,Sandcastle Help,9.09 +06/03/2015,Stephen S,Gergana I,Lego Assistance,9.4 +08/03/2015,Ben B,Sam N,Pokemon Training,11.32 +11/03/2015,Stephen S,Jon A,Sandcastle Help,11.57 +15/03/2015,Todd,Sam N,Pokemon Training,2.29 +19/03/2015,Laura B,Chris W,Coffee,9.96 +21/03/2015,Jon A,Gergana I,Beers,7.54 +25/03/2015,Gergana I,Ben B,Automated Testing Services,2.39 +28/03/2015,Stephen S,Tim L,Lunch,5.83 +29/03/2015,Gergana I,Ben B,Audit and Other Financial Services,10.85 +30/03/2015,Tim L,Todd,Pokemon Training,8.6 +02/04/2015,Stephen S,Chris W,Pokemon Training,1.11 +05/04/2015,Chris W,Ben B,Lunch,0.96 +09/04/2015,Chris W,Rob S,Audit and Other Financial Services,11.79 +12/04/2015,Gergana I,Laura B,Stationary Items,8.37 +13/04/2015,Laura B,Tim L,Services Rendered,1.27 +15/04/2015,Ben B,Sam N,Lego Assistance,8.5 +19/04/2015,Stephen S,Chris W,White Water Rafting,8.91 +23/04/2015,Tim L,Todd,Misc Morale,8.1 +24/04/2015,Tim L,Sarah T,Arcade Social,6.38 +26/04/2015,Jon A,Todd,Stationary Items,8.44 +27/04/2015,Ben B,Jon A,Pokemon Training,10.91 +Last Thursday,Sarah T,Dan W,Beers,5.42 diff --git a/package-lock.json b/package-lock.json index 56296b4..ec905b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "csv-parse": "^6.1.0", "date-fns": "^4.1.0", + "log4js": "^6.9.1", "lodash": "^4.17.21", "ts-node": "^10.9.2" }, @@ -593,6 +594,32 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -644,18 +671,18 @@ "@esbuild/win32-x64": "0.25.9" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "license": "ISC" }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/prettier": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", @@ -672,6 +699,26 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "license": "MIT", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -734,6 +781,15 @@ "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", "license": "MIT" }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/package.json b/package.json index 0714127..6111f27 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "dependencies": { "csv-parse": "^6.1.0", "date-fns": "^4.1.0", + "log4js": "^6.9.1", "lodash": "^4.17.21", "ts-node": "^10.9.2" } diff --git a/utils/setUpLogger.ts b/utils/setUpLogger.ts new file mode 100644 index 0000000..3b2a643 --- /dev/null +++ b/utils/setUpLogger.ts @@ -0,0 +1,6 @@ +import { configure } from "log4js"; + +export default configure({ + appenders: { cheese: { type: "file", filename: "cheese.log" } }, + categories: { default: { appenders: ["cheese"], level: "error" } }, +}); From bf00b5c5d72fc802b41b71bcc52c774f75c7fcca Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Mon, 15 Sep 2025 09:39:12 +0100 Subject: [PATCH 02/12] separate data parsing logic from csv parser --- import/getTransactionDataFromCSV.ts | 23 +++++++++++ interface/menu.ts | 2 +- types/fileDataRecord.ts | 7 ++++ utils/getTransactionData.ts | 52 ------------------------- utils/parseObjectToTransactionRecord.ts | 25 ++++++++++++ 5 files changed, 56 insertions(+), 53 deletions(-) create mode 100644 import/getTransactionDataFromCSV.ts create mode 100644 types/fileDataRecord.ts delete mode 100644 utils/getTransactionData.ts create mode 100644 utils/parseObjectToTransactionRecord.ts diff --git a/import/getTransactionDataFromCSV.ts b/import/getTransactionDataFromCSV.ts new file mode 100644 index 0000000..bdf222e --- /dev/null +++ b/import/getTransactionDataFromCSV.ts @@ -0,0 +1,23 @@ +import { readFileSync } from "fs"; +import { parse } from "csv-parse/sync"; +import type { TransactionRecord } from "../types/transactionRecord"; +import type { FileDataRecord } from "../types/fileDataRecord"; +import { parseObjectsToTransactionRecords } from "../utils/parseObjectToTransactionRecord"; + +const HEADERS = ["Date", "From", "To", "Narrative", "Amount"]; + +export const getTransactionData = (filePath: string): TransactionRecord[] => { + let transactionRecords: TransactionRecord[] = []; + + const fileContent = readFileSync(filePath, { encoding: "utf-8" }); + + const records = parse(fileContent, { + delimiter: ",", + columns: HEADERS, + from_line: 2, + }); + + parseObjectsToTransactionRecords(transactionRecords, records as FileDataRecord[]); + + return transactionRecords; +}; diff --git a/interface/menu.ts b/interface/menu.ts index 02582ea..193b9ab 100644 --- a/interface/menu.ts +++ b/interface/menu.ts @@ -1,5 +1,5 @@ import { AccountManager } from "../account/accountManager"; -import { getTransactionData } from "../utils/getTransactionData"; +import { getTransactionData } from "../import/getTransactionDataFromCSV"; import { convertPenceToPounds } from "../utils/penceConverter"; import { getUserInput } from "../utils/getUserInput"; import type { TransactionRecord } from "../types/transactionRecord"; diff --git a/types/fileDataRecord.ts b/types/fileDataRecord.ts new file mode 100644 index 0000000..a4f1fce --- /dev/null +++ b/types/fileDataRecord.ts @@ -0,0 +1,7 @@ +export interface FileDataRecord { + Date: string; + From: string; + To: string; + Narrative: string; + Amount: string; +} \ No newline at end of file diff --git a/utils/getTransactionData.ts b/utils/getTransactionData.ts deleted file mode 100644 index e040c05..0000000 --- a/utils/getTransactionData.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { readFileSync } from "fs"; -import { parse } from "csv-parse/sync"; -import type { TransactionRecord } from "../types/transactionRecord"; -import { parse as dateParseFns } from "date-fns"; -import { convertPoundsToPence } from "./penceConverter"; - -const HEADERS = ["Date", "From", "To", "Narrative", "Amount"]; - -interface CsvRow { - Date: string; - From: string; - To: string; - Narrative: string; - Amount: string; -} - -function parseDate(dateStr: string): Date { - return dateParseFns(dateStr, "d/M/y", new Date()); -} - -const setTransactionRecordsFromCsvRows = ( - transactionRecords: TransactionRecord[], - csvRows: CsvRow[], -) => { - csvRows.forEach((row: CsvRow) => { - const amountInPence = convertPoundsToPence(parseFloat(row.Amount)); - const record: TransactionRecord = { - Date: parseDate(row.Date), - From: row.From, - To: row.To, - Narrative: row.Narrative, - Amount: amountInPence, - }; - transactionRecords.push(record); - }); -}; - -export const getTransactionData = (filePath: string): TransactionRecord[] => { - let transactionRecords: TransactionRecord[] = []; - - const fileContent = readFileSync(filePath, { encoding: "utf-8" }); - - const records = parse(fileContent, { - delimiter: ",", - columns: HEADERS, - from_line: 2, - }); - - setTransactionRecordsFromCsvRows(transactionRecords, records as CsvRow[]); - - return transactionRecords; -}; diff --git a/utils/parseObjectToTransactionRecord.ts b/utils/parseObjectToTransactionRecord.ts new file mode 100644 index 0000000..b100f59 --- /dev/null +++ b/utils/parseObjectToTransactionRecord.ts @@ -0,0 +1,25 @@ +import type { TransactionRecord } from "../types/transactionRecord"; +import type { FileDataRecord } from "../types/fileDataRecord"; +import { parse as dateParseFns } from "date-fns"; +import { convertPoundsToPence } from "./penceConverter"; + +function parseDate(dateStr: string): Date { + return dateParseFns(dateStr, "d/M/y", new Date()); +} + +export function parseObjectsToTransactionRecords( + transactionRecords: TransactionRecord[], + dataRecords: FileDataRecord[], +){ + dataRecords.forEach((row: FileDataRecord) => { + const amount_in_pence = convertPoundsToPence(parseFloat(row.Amount)); + const record: TransactionRecord = { + Date: parseDate(row.Date), + From: row.From, + To: row.To, + Narrative: row.Narrative, + Amount: amount_in_pence, + }; + transactionRecords.push(record); + }); +}; From 4b5dcbeabff807d2f601d89014bd3b2d073df61a Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Mon, 15 Sep 2025 14:52:30 +0100 Subject: [PATCH 03/12] change module type to commonjs to support log4js --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6111f27..ec3c3cd 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,10 @@ }, "license": "ISC", "author": "", - "type": "module", + "type": "commonjs", "main": "index.ts", "scripts": { - "start": "tsc && esbuild index.ts --bundle --format=esm --platform=node --outfile=dist/bundle.js && node dist/bundle.js", + "start": "tsc && esbuild index.ts --bundle --format=cjs --platform=node --outfile=dist/bundle.js && node dist/bundle.js", "test": "echo \"Error: no test specified\" && exit 1", "format": "prettier . --write" }, From 6901595fee7759c59146b2de22e2c41eff8916a2 Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Mon, 15 Sep 2025 14:52:41 +0100 Subject: [PATCH 04/12] add .log files to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b2d59d1..c3e0bb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /node_modules -/dist \ No newline at end of file +/dist +*.log \ No newline at end of file From 7cca4fdf373390745294f31dc2b97e9217b826c4 Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Mon, 15 Sep 2025 14:53:13 +0100 Subject: [PATCH 05/12] add import data checks and warning logs --- import/getTransactionDataFromCSV.ts | 6 +- interface/menu.ts | 5 +- utils/parseObjectToTransactionRecord.ts | 99 +++++++++++++++++++++---- utils/setUpLogger.ts | 9 ++- 4 files changed, 96 insertions(+), 23 deletions(-) diff --git a/import/getTransactionDataFromCSV.ts b/import/getTransactionDataFromCSV.ts index bdf222e..08e516f 100644 --- a/import/getTransactionDataFromCSV.ts +++ b/import/getTransactionDataFromCSV.ts @@ -2,13 +2,11 @@ import { readFileSync } from "fs"; import { parse } from "csv-parse/sync"; import type { TransactionRecord } from "../types/transactionRecord"; import type { FileDataRecord } from "../types/fileDataRecord"; -import { parseObjectsToTransactionRecords } from "../utils/parseObjectToTransactionRecord"; +import { getParsedObjectsToTransactionRecords } from "../utils/parseObjectToTransactionRecord"; const HEADERS = ["Date", "From", "To", "Narrative", "Amount"]; export const getTransactionData = (filePath: string): TransactionRecord[] => { - let transactionRecords: TransactionRecord[] = []; - const fileContent = readFileSync(filePath, { encoding: "utf-8" }); const records = parse(fileContent, { @@ -17,7 +15,7 @@ export const getTransactionData = (filePath: string): TransactionRecord[] => { from_line: 2, }); - parseObjectsToTransactionRecords(transactionRecords, records as FileDataRecord[]); + let transactionRecords: TransactionRecord[] = getParsedObjectsToTransactionRecords(records as FileDataRecord[]); return transactionRecords; }; diff --git a/interface/menu.ts b/interface/menu.ts index 193b9ab..15b3a42 100644 --- a/interface/menu.ts +++ b/interface/menu.ts @@ -83,8 +83,11 @@ export class Menu { }; #loadTransactionRecords = () => { + // const transaction_records = getTransactionData( + // "./data/Transactions2014.csv", + // ); const transactionRecords = getTransactionData( - "./data/Transactions2014.csv", + "./data/DodgyTransactions2015.csv", ); transactionRecords.forEach((record) => { this.accountManager.addTransactionRecord(record); diff --git a/utils/parseObjectToTransactionRecord.ts b/utils/parseObjectToTransactionRecord.ts index b100f59..cb028f1 100644 --- a/utils/parseObjectToTransactionRecord.ts +++ b/utils/parseObjectToTransactionRecord.ts @@ -1,25 +1,92 @@ import type { TransactionRecord } from "../types/transactionRecord"; import type { FileDataRecord } from "../types/fileDataRecord"; -import { parse as dateParseFns } from "date-fns"; -import { convertPoundsToPence } from "./penceConverter"; +import { parse as dateParseFns, isValid as isValidDateFns } from "date-fns"; +import { convertPoundsToPence, convertPenceToPounds } from "./penceConverter"; +import setUpLogger from "./setUpLogger"; + +const logger = setUpLogger.getLogger("parseObjectToTransactionRecord"); +logger.level = "debug"; + +function get_TransactionRecord_validity_warnings(original_record:FileDataRecord,transactionRecord:TransactionRecord):string[]{ + const warningMessages: string[] = [] + + if (!isValidDateFns(transactionRecord.Date)){ + warningMessages.push(`Invalid Date: ${transactionRecord.Date} is not valid.`) + } + + if (transactionRecord.From.trim() === ""){ + warningMessages.push(`From - Field must not be empty`) + } + + if (transactionRecord.To.trim() === ""){ + warningMessages.push(`To - Field must not be empty`) + } + + if (transactionRecord.Narrative.trim() === ""){ + warningMessages.push(`Narrative - Field must not be empty`) + } + + if (convertPenceToPounds(transactionRecord.Amount).toString() !== original_record.Amount.trim()){ + warningMessages.push(`Amount - There was a error parsing the amount`) + } + + return warningMessages +} -function parseDate(dateStr: string): Date { +function parseDate(dateStr: string): Date{ return dateParseFns(dateStr, "d/M/y", new Date()); } -export function parseObjectsToTransactionRecords( - transactionRecords: TransactionRecord[], - dataRecords: FileDataRecord[], -){ - dataRecords.forEach((row: FileDataRecord) => { - const amount_in_pence = convertPoundsToPence(parseFloat(row.Amount)); - const record: TransactionRecord = { - Date: parseDate(row.Date), - From: row.From, - To: row.To, - Narrative: row.Narrative, +function parseDataRecordToTransactionRecords(Record:FileDataRecord, line_index_number:number): TransactionRecord | null{ + const parsedDate = parseDate(Record.Date) + const amount_in_pence = convertPoundsToPence(parseFloat(Record.Amount)); + + const newTransactionRecord: TransactionRecord = { + Date: parsedDate, + From: Record.From, + To: Record.To, + Narrative: Record.Narrative, Amount: amount_in_pence, }; - transactionRecords.push(record); - }); + + const warnings = get_TransactionRecord_validity_warnings(Record, newTransactionRecord); + if (warnings.length === 0) + return newTransactionRecord; + + logger.warn(`Warnings present on line ${line_index_number + 1}`) + warnings.forEach(warning =>{ + logger.warn(warning) + }) + + return null +} + +export function getParsedObjectsToTransactionRecords( + dataRecords: FileDataRecord[], +){ + const parsedDataRecords: TransactionRecord[] = [] + + let isAllValid = true + + for(let i = 0; i < dataRecords.length; i++){ + const row = dataRecords[i] + if (row == null || row === undefined){ + logger.warn(`No record found on line ${i + 1}`) + isAllValid = false + continue + } + const parsedRecord = parseDataRecordToTransactionRecords(row, i) + if (parsedRecord != null){ + parsedDataRecords.push(parsedRecord) + isAllValid = false + } + } + + if (!isAllValid){ + logger.warn("The above warnings were found while parsing the records. Please fix the issues and try again.") + process.exit(1); + } + + logger.info(`Successfully parsed ${parsedDataRecords.length} valid records out of ${dataRecords.length} total records.`) + return parsedDataRecords }; diff --git a/utils/setUpLogger.ts b/utils/setUpLogger.ts index 3b2a643..a40344a 100644 --- a/utils/setUpLogger.ts +++ b/utils/setUpLogger.ts @@ -1,6 +1,11 @@ import { configure } from "log4js"; export default configure({ - appenders: { cheese: { type: "file", filename: "cheese.log" } }, - categories: { default: { appenders: ["cheese"], level: "error" } }, + appenders: { + file: { type: "file", filename: "logs.log" }, + out: { type: "stdout" } + }, + categories: { + default: { appenders: ["file", "out"], level: "error" } + } }); From 035b148aba2595d5079fb2d54a40da7db97b54d5 Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Mon, 15 Sep 2025 14:59:42 +0100 Subject: [PATCH 06/12] fix formatting of files --- import/getTransactionDataFromCSV.ts | 3 +- types/fileDataRecord.ts | 2 +- utils/parseObjectToTransactionRecord.ts | 153 +++++++++++++----------- utils/setUpLogger.ts | 6 +- 4 files changed, 91 insertions(+), 73 deletions(-) diff --git a/import/getTransactionDataFromCSV.ts b/import/getTransactionDataFromCSV.ts index 08e516f..9af5453 100644 --- a/import/getTransactionDataFromCSV.ts +++ b/import/getTransactionDataFromCSV.ts @@ -15,7 +15,8 @@ export const getTransactionData = (filePath: string): TransactionRecord[] => { from_line: 2, }); - let transactionRecords: TransactionRecord[] = getParsedObjectsToTransactionRecords(records as FileDataRecord[]); + let transactionRecords: TransactionRecord[] = + getParsedObjectsToTransactionRecords(records as FileDataRecord[]); return transactionRecords; }; diff --git a/types/fileDataRecord.ts b/types/fileDataRecord.ts index a4f1fce..eea5aca 100644 --- a/types/fileDataRecord.ts +++ b/types/fileDataRecord.ts @@ -4,4 +4,4 @@ export interface FileDataRecord { To: string; Narrative: string; Amount: string; -} \ No newline at end of file +} diff --git a/utils/parseObjectToTransactionRecord.ts b/utils/parseObjectToTransactionRecord.ts index cb028f1..221cd4a 100644 --- a/utils/parseObjectToTransactionRecord.ts +++ b/utils/parseObjectToTransactionRecord.ts @@ -7,86 +7,103 @@ import setUpLogger from "./setUpLogger"; const logger = setUpLogger.getLogger("parseObjectToTransactionRecord"); logger.level = "debug"; -function get_TransactionRecord_validity_warnings(original_record:FileDataRecord,transactionRecord:TransactionRecord):string[]{ - const warningMessages: string[] = [] +function get_TransactionRecord_validity_warnings( + original_record: FileDataRecord, + transactionRecord: TransactionRecord, +): string[] { + const warningMessages: string[] = []; - if (!isValidDateFns(transactionRecord.Date)){ - warningMessages.push(`Invalid Date: ${transactionRecord.Date} is not valid.`) - } - - if (transactionRecord.From.trim() === ""){ - warningMessages.push(`From - Field must not be empty`) - } + if (!isValidDateFns(transactionRecord.Date)) { + warningMessages.push( + `Invalid Date: ${transactionRecord.Date} is not valid.`, + ); + } - if (transactionRecord.To.trim() === ""){ - warningMessages.push(`To - Field must not be empty`) - } + if (transactionRecord.From.trim() === "") { + warningMessages.push(`From - Field must not be empty`); + } - if (transactionRecord.Narrative.trim() === ""){ - warningMessages.push(`Narrative - Field must not be empty`) - } + if (transactionRecord.To.trim() === "") { + warningMessages.push(`To - Field must not be empty`); + } - if (convertPenceToPounds(transactionRecord.Amount).toString() !== original_record.Amount.trim()){ - warningMessages.push(`Amount - There was a error parsing the amount`) - } + if (transactionRecord.Narrative.trim() === "") { + warningMessages.push(`Narrative - Field must not be empty`); + } - return warningMessages + if ( + convertPenceToPounds(transactionRecord.Amount).toString() !== + original_record.Amount.trim() + ) { + warningMessages.push(`Amount - There was a error parsing the amount`); + } + + return warningMessages; } - -function parseDate(dateStr: string): Date{ + +function parseDate(dateStr: string): Date { return dateParseFns(dateStr, "d/M/y", new Date()); } -function parseDataRecordToTransactionRecords(Record:FileDataRecord, line_index_number:number): TransactionRecord | null{ - const parsedDate = parseDate(Record.Date) - const amount_in_pence = convertPoundsToPence(parseFloat(Record.Amount)); - - const newTransactionRecord: TransactionRecord = { - Date: parsedDate, - From: Record.From, - To: Record.To, - Narrative: Record.Narrative, - Amount: amount_in_pence, - }; - - const warnings = get_TransactionRecord_validity_warnings(Record, newTransactionRecord); - if (warnings.length === 0) - return newTransactionRecord; - - logger.warn(`Warnings present on line ${line_index_number + 1}`) - warnings.forEach(warning =>{ - logger.warn(warning) - }) - - return null +function parseDataRecordToTransactionRecords( + Record: FileDataRecord, + line_index_number: number, +): TransactionRecord | null { + const parsedDate = parseDate(Record.Date); + const amount_in_pence = convertPoundsToPence(parseFloat(Record.Amount)); + + const newTransactionRecord: TransactionRecord = { + Date: parsedDate, + From: Record.From, + To: Record.To, + Narrative: Record.Narrative, + Amount: amount_in_pence, + }; + + const warnings = get_TransactionRecord_validity_warnings( + Record, + newTransactionRecord, + ); + if (warnings.length === 0) return newTransactionRecord; + + logger.warn(`Warnings present on line ${line_index_number + 1}`); + warnings.forEach((warning) => { + logger.warn(warning); + }); + + return null; } export function getParsedObjectsToTransactionRecords( dataRecords: FileDataRecord[], -){ - const parsedDataRecords: TransactionRecord[] = [] - - let isAllValid = true - - for(let i = 0; i < dataRecords.length; i++){ - const row = dataRecords[i] - if (row == null || row === undefined){ - logger.warn(`No record found on line ${i + 1}`) - isAllValid = false - continue - } - const parsedRecord = parseDataRecordToTransactionRecords(row, i) - if (parsedRecord != null){ - parsedDataRecords.push(parsedRecord) - isAllValid = false - } - } +) { + const parsedDataRecords: TransactionRecord[] = []; + + let isAllValid = true; - if (!isAllValid){ - logger.warn("The above warnings were found while parsing the records. Please fix the issues and try again.") - process.exit(1); + for (let i = 0; i < dataRecords.length; i++) { + const row = dataRecords[i]; + if (row == null || row === undefined) { + logger.warn(`No record found on line ${i + 1}`); + isAllValid = false; + continue; } - - logger.info(`Successfully parsed ${parsedDataRecords.length} valid records out of ${dataRecords.length} total records.`) - return parsedDataRecords -}; + const parsedRecord = parseDataRecordToTransactionRecords(row, i); + if (parsedRecord != null) { + parsedDataRecords.push(parsedRecord); + isAllValid = false; + } + } + + if (!isAllValid) { + logger.warn( + "The above warnings were found while parsing the records. Please fix the issues and try again.", + ); + process.exit(1); + } + + logger.info( + `Successfully parsed ${parsedDataRecords.length} valid records out of ${dataRecords.length} total records.`, + ); + return parsedDataRecords; +} diff --git a/utils/setUpLogger.ts b/utils/setUpLogger.ts index a40344a..6982526 100644 --- a/utils/setUpLogger.ts +++ b/utils/setUpLogger.ts @@ -3,9 +3,9 @@ import { configure } from "log4js"; export default configure({ appenders: { file: { type: "file", filename: "logs.log" }, - out: { type: "stdout" } + out: { type: "stdout" }, }, categories: { - default: { appenders: ["file", "out"], level: "error" } - } + default: { appenders: ["file", "out"], level: "error" }, + }, }); From 380325e927a1417ef893af5208672814648c9faf Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Mon, 15 Sep 2025 16:48:43 +0100 Subject: [PATCH 07/12] fix package.json and exit after warning logic --- interface/menu.ts | 2 +- package-lock.json | 59 ++++++++++++++++++++++++- utils/parseObjectToTransactionRecord.ts | 6 ++- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/interface/menu.ts b/interface/menu.ts index 15b3a42..ac4d329 100644 --- a/interface/menu.ts +++ b/interface/menu.ts @@ -83,7 +83,7 @@ export class Menu { }; #loadTransactionRecords = () => { - // const transaction_records = getTransactionData( + // const transactionRecords = getTransactionData( // "./data/Transactions2014.csv", // ); const transactionRecords = getTransactionData( diff --git a/package-lock.json b/package-lock.json index ec905b8..ca255a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,8 @@ "dependencies": { "csv-parse": "^6.1.0", "date-fns": "^4.1.0", - "log4js": "^6.9.1", "lodash": "^4.17.21", + "log4js": "^6.9.1", "ts-node": "^10.9.2" }, "devDependencies": { @@ -671,6 +671,63 @@ "@esbuild/win32-x64": "0.25.9" } }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "license": "ISC" + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "license": "Apache-2.0", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", diff --git a/utils/parseObjectToTransactionRecord.ts b/utils/parseObjectToTransactionRecord.ts index 221cd4a..9facc16 100644 --- a/utils/parseObjectToTransactionRecord.ts +++ b/utils/parseObjectToTransactionRecord.ts @@ -89,10 +89,12 @@ export function getParsedObjectsToTransactionRecords( continue; } const parsedRecord = parseDataRecordToTransactionRecords(row, i); - if (parsedRecord != null) { - parsedDataRecords.push(parsedRecord); + if (parsedRecord === null) { isAllValid = false; + continue; } + parsedDataRecords.push(parsedRecord); + } if (!isAllValid) { From 5e415792651c4ab8579ccf824107d267136a7da0 Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Tue, 16 Sep 2025 17:30:52 +0100 Subject: [PATCH 08/12] replace getTransactionData with csvService and improve logger implementation --- ...TransactionDataFromCSV.ts => csvService.ts} | 2 +- interface/menu.ts | 4 ++-- utils/logger.ts | 18 ++++++++++++++++++ utils/parseObjectToTransactionRecord.ts | 4 ++-- utils/setUpLogger.ts | 11 ----------- 5 files changed, 23 insertions(+), 16 deletions(-) rename import/{getTransactionDataFromCSV.ts => csvService.ts} (89%) create mode 100644 utils/logger.ts delete mode 100644 utils/setUpLogger.ts diff --git a/import/getTransactionDataFromCSV.ts b/import/csvService.ts similarity index 89% rename from import/getTransactionDataFromCSV.ts rename to import/csvService.ts index 9af5453..1d5baf0 100644 --- a/import/getTransactionDataFromCSV.ts +++ b/import/csvService.ts @@ -6,7 +6,7 @@ import { getParsedObjectsToTransactionRecords } from "../utils/parseObjectToTran const HEADERS = ["Date", "From", "To", "Narrative", "Amount"]; -export const getTransactionData = (filePath: string): TransactionRecord[] => { +export const csvService = (filePath: string): TransactionRecord[] => { const fileContent = readFileSync(filePath, { encoding: "utf-8" }); const records = parse(fileContent, { diff --git a/interface/menu.ts b/interface/menu.ts index ac4d329..06dc467 100644 --- a/interface/menu.ts +++ b/interface/menu.ts @@ -1,5 +1,5 @@ import { AccountManager } from "../account/accountManager"; -import { getTransactionData } from "../import/getTransactionDataFromCSV"; +import { csvService } from "../import/csvService"; import { convertPenceToPounds } from "../utils/penceConverter"; import { getUserInput } from "../utils/getUserInput"; import type { TransactionRecord } from "../types/transactionRecord"; @@ -86,7 +86,7 @@ export class Menu { // const transactionRecords = getTransactionData( // "./data/Transactions2014.csv", // ); - const transactionRecords = getTransactionData( + const transactionRecords = csvService( "./data/DodgyTransactions2015.csv", ); transactionRecords.forEach((record) => { diff --git a/utils/logger.ts b/utils/logger.ts new file mode 100644 index 0000000..96e2a71 --- /dev/null +++ b/utils/logger.ts @@ -0,0 +1,18 @@ +import { configure } from "log4js"; + +var loggerConfiguration = configure({ + appenders: { + file: { type: "file", filename: "logs.log" }, + out: { type: "stdout" }, + }, + categories: { + default: { appenders: ["file", "out"], level: "error" }, + }, +}) + +export function getLogger(filename: string): ReturnType +{ + const logger = loggerConfiguration.getLogger(filename); + logger.level = "debug"; + return logger; +} \ No newline at end of file diff --git a/utils/parseObjectToTransactionRecord.ts b/utils/parseObjectToTransactionRecord.ts index 9facc16..31cbd61 100644 --- a/utils/parseObjectToTransactionRecord.ts +++ b/utils/parseObjectToTransactionRecord.ts @@ -2,9 +2,9 @@ import type { TransactionRecord } from "../types/transactionRecord"; import type { FileDataRecord } from "../types/fileDataRecord"; import { parse as dateParseFns, isValid as isValidDateFns } from "date-fns"; import { convertPoundsToPence, convertPenceToPounds } from "./penceConverter"; -import setUpLogger from "./setUpLogger"; +import { getLogger } from "./logger"; -const logger = setUpLogger.getLogger("parseObjectToTransactionRecord"); +const logger = getLogger("parseObjectToTransactionRecord"); logger.level = "debug"; function get_TransactionRecord_validity_warnings( diff --git a/utils/setUpLogger.ts b/utils/setUpLogger.ts deleted file mode 100644 index 6982526..0000000 --- a/utils/setUpLogger.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { configure } from "log4js"; - -export default configure({ - appenders: { - file: { type: "file", filename: "logs.log" }, - out: { type: "stdout" }, - }, - categories: { - default: { appenders: ["file", "out"], level: "error" }, - }, -}); From 7bf11edc026761fa3a44d1b3d835703f77fff334 Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Tue, 16 Sep 2025 17:33:50 +0100 Subject: [PATCH 09/12] improve import of date-fns --- utils/parseObjectToTransactionRecord.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/parseObjectToTransactionRecord.ts b/utils/parseObjectToTransactionRecord.ts index 31cbd61..6a0d811 100644 --- a/utils/parseObjectToTransactionRecord.ts +++ b/utils/parseObjectToTransactionRecord.ts @@ -1,6 +1,6 @@ import type { TransactionRecord } from "../types/transactionRecord"; import type { FileDataRecord } from "../types/fileDataRecord"; -import { parse as dateParseFns, isValid as isValidDateFns } from "date-fns"; +import * as datefns from "date-fns" import { convertPoundsToPence, convertPenceToPounds } from "./penceConverter"; import { getLogger } from "./logger"; @@ -13,7 +13,7 @@ function get_TransactionRecord_validity_warnings( ): string[] { const warningMessages: string[] = []; - if (!isValidDateFns(transactionRecord.Date)) { + if (!datefns.isValid(transactionRecord.Date)) { warningMessages.push( `Invalid Date: ${transactionRecord.Date} is not valid.`, ); @@ -42,7 +42,7 @@ function get_TransactionRecord_validity_warnings( } function parseDate(dateStr: string): Date { - return dateParseFns(dateStr, "d/M/y", new Date()); + return datefns.parse(dateStr, "d/M/y", new Date()); } function parseDataRecordToTransactionRecords( From d714405ae2c510063a047f9a3293d7a3a1ce60a3 Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Tue, 16 Sep 2025 17:35:20 +0100 Subject: [PATCH 10/12] remove remaining snake case variables --- utils/parseObjectToTransactionRecord.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/utils/parseObjectToTransactionRecord.ts b/utils/parseObjectToTransactionRecord.ts index 6a0d811..28a10e3 100644 --- a/utils/parseObjectToTransactionRecord.ts +++ b/utils/parseObjectToTransactionRecord.ts @@ -7,8 +7,8 @@ import { getLogger } from "./logger"; const logger = getLogger("parseObjectToTransactionRecord"); logger.level = "debug"; -function get_TransactionRecord_validity_warnings( - original_record: FileDataRecord, +function getTransactionRecordValidityWarnings( + originalRecord: FileDataRecord, transactionRecord: TransactionRecord, ): string[] { const warningMessages: string[] = []; @@ -33,7 +33,7 @@ function get_TransactionRecord_validity_warnings( if ( convertPenceToPounds(transactionRecord.Amount).toString() !== - original_record.Amount.trim() + originalRecord.Amount.trim() ) { warningMessages.push(`Amount - There was a error parsing the amount`); } @@ -47,26 +47,26 @@ function parseDate(dateStr: string): Date { function parseDataRecordToTransactionRecords( Record: FileDataRecord, - line_index_number: number, + lineIndexNumber: number, ): TransactionRecord | null { const parsedDate = parseDate(Record.Date); - const amount_in_pence = convertPoundsToPence(parseFloat(Record.Amount)); + const amountInPence = convertPoundsToPence(parseFloat(Record.Amount)); const newTransactionRecord: TransactionRecord = { Date: parsedDate, From: Record.From, To: Record.To, Narrative: Record.Narrative, - Amount: amount_in_pence, + Amount: amountInPence, }; - const warnings = get_TransactionRecord_validity_warnings( + const warnings = getTransactionRecordValidityWarnings( Record, newTransactionRecord, ); if (warnings.length === 0) return newTransactionRecord; - logger.warn(`Warnings present on line ${line_index_number + 1}`); + logger.warn(`Warnings present on line ${lineIndexNumber + 1}`); warnings.forEach((warning) => { logger.warn(warning); }); From 6996350c9080eec1b0d1e2419c696cd21680d5cc Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Tue, 16 Sep 2025 17:36:11 +0100 Subject: [PATCH 11/12] rename Record to record --- utils/parseObjectToTransactionRecord.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/utils/parseObjectToTransactionRecord.ts b/utils/parseObjectToTransactionRecord.ts index 28a10e3..0ff1923 100644 --- a/utils/parseObjectToTransactionRecord.ts +++ b/utils/parseObjectToTransactionRecord.ts @@ -46,22 +46,22 @@ function parseDate(dateStr: string): Date { } function parseDataRecordToTransactionRecords( - Record: FileDataRecord, + record: FileDataRecord, lineIndexNumber: number, ): TransactionRecord | null { - const parsedDate = parseDate(Record.Date); - const amountInPence = convertPoundsToPence(parseFloat(Record.Amount)); + const parsedDate = parseDate(record.Date); + const amountInPence = convertPoundsToPence(parseFloat(record.Amount)); const newTransactionRecord: TransactionRecord = { Date: parsedDate, - From: Record.From, - To: Record.To, - Narrative: Record.Narrative, + From: record.From, + To: record.To, + Narrative: record.Narrative, Amount: amountInPence, }; const warnings = getTransactionRecordValidityWarnings( - Record, + record, newTransactionRecord, ); if (warnings.length === 0) return newTransactionRecord; From c8a45aa03e0c1871f5db4e91d92845fecc136685 Mon Sep 17 00:00:00 2001 From: AlanProphettSoftwire Date: Wed, 17 Sep 2025 09:36:31 +0100 Subject: [PATCH 12/12] add amount format check on parse --- utils/parseObjectToTransactionRecord.ts | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/utils/parseObjectToTransactionRecord.ts b/utils/parseObjectToTransactionRecord.ts index 0ff1923..cfa36bb 100644 --- a/utils/parseObjectToTransactionRecord.ts +++ b/utils/parseObjectToTransactionRecord.ts @@ -7,8 +7,9 @@ import { getLogger } from "./logger"; const logger = getLogger("parseObjectToTransactionRecord"); logger.level = "debug"; +const EXPECTED_MONETARY_REGEX = /^\d+\.\d\d$/; + function getTransactionRecordValidityWarnings( - originalRecord: FileDataRecord, transactionRecord: TransactionRecord, ): string[] { const warningMessages: string[] = []; @@ -31,13 +32,6 @@ function getTransactionRecordValidityWarnings( warningMessages.push(`Narrative - Field must not be empty`); } - if ( - convertPenceToPounds(transactionRecord.Amount).toString() !== - originalRecord.Amount.trim() - ) { - warningMessages.push(`Amount - There was a error parsing the amount`); - } - return warningMessages; } @@ -48,8 +42,9 @@ function parseDate(dateStr: string): Date { function parseDataRecordToTransactionRecords( record: FileDataRecord, lineIndexNumber: number, -): TransactionRecord | null { +): TransactionRecord { const parsedDate = parseDate(record.Date); + const amountInPence = convertPoundsToPence(parseFloat(record.Amount)); const newTransactionRecord: TransactionRecord = { @@ -61,9 +56,13 @@ function parseDataRecordToTransactionRecords( }; const warnings = getTransactionRecordValidityWarnings( - record, newTransactionRecord, ); + + if(EXPECTED_MONETARY_REGEX.test(record.Amount) === false){ + warnings.push(`Amount - ${record.Amount} is not in the expected format of a decimal number with two decimal places (e.g., 123.45)`); + } + if (warnings.length === 0) return newTransactionRecord; logger.warn(`Warnings present on line ${lineIndexNumber + 1}`); @@ -71,7 +70,7 @@ function parseDataRecordToTransactionRecords( logger.warn(warning); }); - return null; + throw new Error("Invalid record found"); } export function getParsedObjectsToTransactionRecords( @@ -88,13 +87,14 @@ export function getParsedObjectsToTransactionRecords( isAllValid = false; continue; } - const parsedRecord = parseDataRecordToTransactionRecords(row, i); - if (parsedRecord === null) { + try{ + const parsedRecord = parseDataRecordToTransactionRecords(row, i); + parsedDataRecords.push(parsedRecord); + } + catch (e){ isAllValid = false; continue; } - parsedDataRecords.push(parsedRecord); - } if (!isAllValid) {