Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Commit

Permalink
Support multiple transaction parts in the row interpreter.
Browse files Browse the repository at this point in the history
Moves category determination, amount and memo to all take parameters. Then implement getTransactionParts which grabs transaction information from the details field, falling back to the envelope and amount if none is provided.
This way, the row interpreter consistently breaks up transactions into parts. The DataTransformer remains in charge of turning transaction parts into full transactions. This includes taking the part of a transaction into account when calculating the import ID.
  • Loading branch information
jordancrawfordnz committed Aug 5, 2018
1 parent a1f0919 commit 192b543
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 25 deletions.
23 changes: 14 additions & 9 deletions lib/data_transformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,27 @@ class DataTransformer {
async transformRow(row) {
let rowInterpreter = new RowInterpreter(row, await this.ynabCategoryIds());

return [{
let baseTransaction = {
account_id: this.ynabAccountId,
category_id: rowInterpreter.categoryId(),
date: rowInterpreter.date(this.dateFormat),
amount: rowInterpreter.amount(),
payee_name: rowInterpreter.payeeName(),
memo: rowInterpreter.memo(),
cleared: 'cleared',
import_id: this.calculateImportIdForRow(row)
}];
cleared: 'cleared'
};

return rowInterpreter.getTransactionParts().map((transactionPart, partIndex) => {
return Object.assign({
category_id: transactionPart.categoryId,
amount: transactionPart.amount,
memo: transactionPart.memo,
import_id: this.calculateImportIdForTransaction(row, partIndex)
}, baseTransaction);
});
}

calculateImportIdForRow(row) {
calculateImportIdForTransaction(row, part) {
let transactionHash = hash.MD5(row);
let occurenceIndex = this.transactionHashes[transactionHash] = (this.transactionHashes[transactionHash] || 0) + 1
let importId = "GBI:" + hash.MD5(Object.assign({ occurence: occurenceIndex, rerun: this.rerunIndex }, row));
let importId = "GBI:" + hash.MD5(Object.assign({ part: part, occurence: occurenceIndex, rerun: this.rerunIndex }, row));

return importId;
}
Expand Down
56 changes: 40 additions & 16 deletions lib/row_interpreter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,61 @@ class RowInterpreter {
this.ynabCategoryIds = ynabCategoryIds;
}

categoryId() {
let envelopeName = this.row.Envelope.split(': ').pop();
getTransactionParts() {
let parts = this.row.Details.split('||').reduce((parts, transactionPart) => {
let envelopeAndAmount = transactionPart.split('|');
if (envelopeAndAmount[0] !== '' && envelopeAndAmount.length === 2) parts.push(envelopeAndAmount);

return this.ynabCategoryIds[envelopeName];
}
return parts;
}, []);

date(dateFormat) {
return moment(this.row.Date, dateFormat).format('YYYY-MM-DD');
}
if (parts.length === 0) parts.push([this.row.Envelope, this.row.Amount]);

amount() {
let amount = parseFloat(this.row.Amount.replace(',', ''));
return parts.map((part) => {
let categoryId = this.categoryForEnvelope(part[0]);

return Math.round(amount * 1000);
return {
categoryId: categoryId,
amount: this.amountAsMilliunits(part[1]),
memo: this.memoForCategory(categoryId)
};
});
}


date(dateFormat) {
return moment(this.row.Date, dateFormat).format('YYYY-MM-DD');
}

payeeName() {
return this.row.Name.length == 0 ? null : this.row.Name.substring(0, 50);
}

memoForCategory(category) {
let memo = this.row.Notes;

memo() {
let memo = this.row.Notes + this.row.Details;

if (!this.categoryId() && this.row.Envelope.length > 0) {
if (!category && this.row.Envelope.length > 0) {
if (memo.length > 0) memo += " ";
memo += "Original envelope: " + this.row.Envelope;
}
let truncatedMemo = memo.substring(0, 100);

return truncatedMemo;
}

categoryForEnvelope(envelope) {
let envelopeName = envelope.split(': ').pop();

// Handle income by converting unallocated parts to money to be budgeted.
if (envelopeName === '[Unallocated]') envelopeName = 'To be Budgeted';

return this.ynabCategoryIds[envelopeName];
}

amountAsMilliunits(rawAmount) {
let amount = parseFloat(rawAmount.replace(',', ''));

return Math.round(amount * 1000);
}
}

module.exports = RowInterpreter;

0 comments on commit 192b543

Please sign in to comment.