Skip to content

Commit

Permalink
Formatting + openbank import logic
Browse files Browse the repository at this point in the history
  • Loading branch information
melledijkstra committed Jul 16, 2022
1 parent 75f7c31 commit 8076261
Show file tree
Hide file tree
Showing 16 changed files with 383 additions and 294 deletions.
2 changes: 1 addition & 1 deletion .clasp.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"scriptId":"1viSsQkJME8IWYt6v-LplS1i-06k4qpZ5Qb9hUuxpofPHUaFtJuQbOo-T",
"scriptId": "1viSsQkJME8IWYt6v-LplS1i-06k4qpZ5Qb9hUuxpofPHUaFtJuQbOo-T",
"rootDir": "src/"
}
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"trailingComma": "es5",
"singleQuote": true
}
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"[typescript]": {
"editor.formatOnSave": true
}
}
4 changes: 2 additions & 2 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
{
"compilerOptions": {
"checkJs": true,
"lib": ["es6"]
},
}
}
15 changes: 6 additions & 9 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
const ui = SpreadsheetApp.getUi()
const ui = SpreadsheetApp.getUi();

function onOpen(): void {
ui.createMenu('Import')
.addItem('Upload CSV', 'fileUploadDialog')
.addToUi()
ui.createMenu('Import').addItem('Upload CSV', 'fileUploadDialog').addToUi();
}

function fileUploadDialog(): void {
const html = HtmlService.createTemplateFromFile('fileinput.html')
.evaluate()
.setWidth(900)
.setHeight(600)
SpreadsheetApp.getUi()
.showModalDialog(html, 'File upload dialog');
.setHeight(600);
SpreadsheetApp.getUi().showModalDialog(html, 'File upload dialog');
}

function include(filename: string): string {
return HtmlService.createHtmlOutputFromFile(filename).getContent()
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}

function getStrategyOptions() {
return StrategyOption
return StrategyOption;
}
17 changes: 9 additions & 8 deletions src/appsscript.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"timeZone": "Europe/Amsterdam",
"dependencies": {
},
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"sheets": {
"macros": [{
"menuName": "Delete duplicate transaction",
"functionName": "macroDeleteDuplicateTransaction",
"defaultShortcut": "Ctrl+Alt+Shift+5"
}]
"macros": [
{
"menuName": "Delete duplicate transaction",
"functionName": "macroDeleteDuplicateTransaction",
"defaultShortcut": "Ctrl+Alt+Shift+5"
}
]
}
}
}
57 changes: 36 additions & 21 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@

const defaultAfterImport = [
(table: Table) => Utils.autoFillColumns(table, AUTO_FILL_COLUMNS)
]
(table: Table) => Utils.autoFillColumns(table, AUTO_FILL_COLUMNS),
];

class Config {
static getConfig(): Strategy {
return {
'n26': {
n26: {
beforeImport: [
Utils.deleteLastRow,
Utils.deleteFirstRow,
Expand All @@ -26,11 +25,11 @@ class Config {
},
afterImport: defaultAfterImport,
},
'rabobank': {
rabobank: {
beforeImport: [
Utils.deleteLastRow,
Utils.deleteFirstRow,
Utils.sortByDate(raboCols.Datum)
Utils.sortByDate(raboCols.Datum),
],
columnImportRules: {
ref: buildColumn(raboCols.Volgnr, parseInt),
Expand All @@ -44,41 +43,57 @@ class Config {
description: buildColumn(raboCols.Omschrijving1, String),
label: buildColumn(raboCols.Omschrijving2, String),
},
afterImport: defaultAfterImport
afterImport: defaultAfterImport,
},
"bbva": {
bbva: {
beforeImport: [
Utils.deleteLastRow,
Utils.deleteFirstRow,
Utils.sortByDate(bbvaCols.Date)
Utils.sortByDate(bbvaCols.Date),
],
columnImportRules: {
ref: null,
iban: (data) => new Array(data.length).fill(BankAccount.BBVA),
date: buildColumn(bbvaCols.Date, (val) => new Date(val)),
amount: buildColumn(bbvaCols.Amount, parseFloat),
date: buildColumn(bbvaCols.Date, (val) => Utils.transformDate(val)),
amount: buildColumn(bbvaCols.Amount, Utils.transformMoneyColumn),
category: null,
contra_iban: null,
currency: buildColumn(bbvaCols.Currency, String),
description: buildColumn(bbvaCols.Comments, String),
label: buildColumn(bbvaCols.SubjectLine, String)
label: buildColumn(bbvaCols.SubjectLine, String),
},
afterImport: defaultAfterImport
afterImport: defaultAfterImport,
},
"openbank": {
openbank: {
beforeImport: [
Utils.deleteFirstRow,
Utils.deleteLastRow,
// open bank has some empty columns when importing
(table) => Utils.deleteColumns(table, [0, 2, 4, 6, 8]),
],
columnImportRules: {
ref: null,
iban: (data) => new Array(data.length).fill(BankAccount.OPENBANK),
date: null,
amount: null,
date: buildColumn(openbankCols.Fecha, (val) => {
let [day, month, year] = val.split('/');
let yearNum = +year;
if (year && year.length === 2) {
// if year is of length 2 it means it only provides the year since 2000
// to fix we add 2000
yearNum = +year + 2000;
}
return new Date(+yearNum, +month - 1, +day);
}),
amount: buildColumn(openbankCols.Importe, Utils.transformMoneyColumn),
category: null,
contra_account: null,
label: null,
description: null,
description: buildColumn(openbankCols.Concepto, String),
contra_iban: null,
currency: null,
}
}
}
},
afterImport: defaultAfterImport,
},
};
}
}
}
99 changes: 54 additions & 45 deletions src/csv-processor.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
const sourceSheetId = 1093484485
const sourceSheetId = 1093484485;
const AUTO_FILL_COLUMNS = [
5, // balance column
9, // category icon
12, // hours column
14, // disabled column
]
];

const FireSpreadsheet = SpreadsheetApp.getActiveSpreadsheet()
const sheets = FireSpreadsheet.getSheets()
const Props = PropertiesService.getUserProperties()
const sourceSheet = getSheetById(sourceSheetId)
const FireSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheets = FireSpreadsheet.getSheets();
const Props = PropertiesService.getUserProperties();
const sourceSheet = getSheetById(sourceSheetId);

function getSheetById(id: number): GoogleAppsScript.Spreadsheet.Sheet {
return sheets.find(sheet => sheet.getSheetId() === id)
return sheets.find((sheet) => sheet.getSheetId() === id);
}

const FireColumns = [
Expand All @@ -31,73 +31,82 @@ const FireColumns = [
'contra_iban',
'disabled',
'currency',
]
];

function buildColumn<T>(
column: InputColumn,
transformer: (value: string) => T
): (data: Table) => T[]
{
): (data: Table) => T[] {
return (data: Table): T[] => {
const rowCount = data.length
const columnTable = Utils.transpose(data) // try to transpose somewhere else
const rowCount = data.length;
const columnTable = Utils.transpose(data); // try to transpose somewhere else
if (columnTable[column] !== undefined) {
return columnTable[column].map((val) => transformer(val))
return columnTable[column].map((val) => transformer(val));
} else {
return new Array(rowCount)
return new Array(rowCount);
}
}
};
}

function buildNewTableData(input: Table, columnImportRules: FireColumnRules) {
let output: Table = []
const rowCount = input.length
let output: Table = [];
const rowCount = input.length;
for (const columnName of FireColumns) {
if (!(columnName in columnImportRules) || !columnImportRules[columnName]) {
output.push(new Array(rowCount))
continue
output.push(new Array(rowCount));
continue;
}
const colRule = columnImportRules[columnName] as ColumnRule<any>
let column: any[]
const colRule = columnImportRules[columnName] as ColumnRule<any>;
let column: any[];
try {
column = colRule(input)
column = Utils.ensureLength(column, rowCount)
} catch(e) {
Logger.log(e)
column = new Array(rowCount)
column = colRule(input);
column = Utils.ensureLength(column, rowCount);
} catch (e) {
Logger.log(e);
column = new Array(rowCount);
}
output.push(column)
output.push(column);
}
output = Utils.transpose(output) // flip columns to rows
return output
output = Utils.transpose(output); // flip columns to rows
return output;
}

/**
* This function gets called by client side script
* This function gets called by client side script
* @see file-input.html
*/
function processCSV(input: Table, importStrategy: StrategyOption): ServerResponse {
const strategies = Config.getConfig()
sourceSheet.activate()
sourceSheet.showSheet()
function processCSV(
input: Table,
importStrategy: StrategyOption
): ServerResponse {
const strategies = Config.getConfig();
sourceSheet.activate();
sourceSheet.showSheet();
if (!(importStrategy in strategies)) {
throw new Error(`Import strategy ${importStrategy} is not defined!`)
throw new Error(`Import strategy ${importStrategy} is not defined!`);
}

const { beforeImport, columnImportRules, afterImport } = strategies[importStrategy]
const { beforeImport, columnImportRules, afterImport } =
strategies[importStrategy];

for (const rule of beforeImport) {
input = rule(input)
if (beforeImport) {
for (const rule of beforeImport) {
input = rule(input);
}
}
let output = buildNewTableData(input, columnImportRules)
Utils.importData(output)
for (const rule of afterImport) {
rule(output)

let output = buildNewTableData(input, columnImportRules);
Utils.importData(output);

if (afterImport) {
for (const rule of afterImport) {
rule(output);
}
}

const msg = `imported ${output.length} rows!`
Logger.log(`processCSV done: ${msg}`)
const msg = `imported ${output.length} rows!`;
Logger.log(`processCSV done: ${msg}`);
return {
message: msg,
}
};
}
Loading

0 comments on commit 8076261

Please sign in to comment.