148 lines
5.8 KiB
TypeScript
148 lines
5.8 KiB
TypeScript
|
import * as plugins from '../csvparser.plugins.js';
|
||
|
|
||
|
import * as interfaces from './interfaces/index.js';
|
||
|
|
||
|
export class CsvPayPal extends plugins.portablefinance
|
||
|
.AcCsvParser<plugins.portablefinance.IMonetaryTransaction> {
|
||
|
// INSTANCE
|
||
|
public paymentProviderName = 'PayPal';
|
||
|
public description: string = 'a csv parser optimized for PayPal obtained csv files.';
|
||
|
public csvDescriptorArray: plugins.portablefinance.ICsvDescriptor[] = [];
|
||
|
|
||
|
constructor() {
|
||
|
super();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* gets transactions
|
||
|
*/
|
||
|
public async getTransactions() {
|
||
|
const payments: plugins.portablefinance.IMonetaryTransaction[] = [];
|
||
|
for (const csvDescriptor of this.csvDescriptorArray) {
|
||
|
let stringToParse = csvDescriptor.contentString;
|
||
|
stringToParse = stringToParse.replace(/"(.*?)"/gi, (match, p1, offset, originalString) => {
|
||
|
return plugins.smartstring.base64.encodeUri(match);
|
||
|
});
|
||
|
const smartCsvInstance = new plugins.smartcsv.Csv(stringToParse, {
|
||
|
headers: true,
|
||
|
});
|
||
|
const payPalTransactions: interfaces.IPayPalCsvOriginalTransaction[] = (
|
||
|
await smartCsvInstance.exportAsObject()
|
||
|
).map((originalTransaction) => {
|
||
|
// tslint:disable-next-line: no-object-literal-type-assertion
|
||
|
const decodedTransaction = {} as interfaces.IPayPalCsvOriginalTransaction;
|
||
|
for (const key in originalTransaction) {
|
||
|
if (originalTransaction[key]) {
|
||
|
let finalKey = plugins.smartstring.base64.decode(key);
|
||
|
finalKey = finalKey.replace(/['"]+/g, '');
|
||
|
let finalValue = plugins.smartstring.base64.decode(originalTransaction[key]);
|
||
|
finalValue = finalValue.replace(/['"]+/g, '');
|
||
|
decodedTransaction[finalKey] = finalValue;
|
||
|
}
|
||
|
}
|
||
|
// pushing the ready transaction
|
||
|
return decodedTransaction;
|
||
|
});
|
||
|
|
||
|
// adjust numberFormat
|
||
|
const anf = (numberString: string): number => {
|
||
|
return parseFloat(numberString.replace(/\,/g, '.'));
|
||
|
};
|
||
|
|
||
|
const monetaryTransactions: interfaces.IPayPalTransaction[] = [];
|
||
|
for (const originalTransaction of payPalTransactions) {
|
||
|
const paypalTransaction: interfaces.IPayPalTransaction = {
|
||
|
// assigned later
|
||
|
transactionHash: null,
|
||
|
simpleTransaction: null,
|
||
|
|
||
|
// assigned now
|
||
|
originalTransaction,
|
||
|
transactionDate: plugins.smarttime.ExtendedDate.fromEuropeanDateAndTime(
|
||
|
originalTransaction.Datum,
|
||
|
originalTransaction.Uhrzeit,
|
||
|
'Europe/Berlin'
|
||
|
),
|
||
|
transactionCode: originalTransaction.Transaktionscode,
|
||
|
linkedTransactionCode: originalTransaction['Zugehöriger Transaktionscode'],
|
||
|
timezone: originalTransaction.Zeitzone,
|
||
|
bankAccount: originalTransaction.Bankkonto,
|
||
|
bankName: originalTransaction['Name der Bank'],
|
||
|
brutto: anf(originalTransaction.Brutto),
|
||
|
netto: anf(originalTransaction.Netto),
|
||
|
credit: anf(originalTransaction.Guthaben),
|
||
|
fee: anf(originalTransaction.Gebühr),
|
||
|
processingAndShippingFee: anf(originalTransaction['Versand- und Bearbeitungsgebühr']),
|
||
|
currency: originalTransaction.Währung,
|
||
|
description: originalTransaction.Beschreibung,
|
||
|
invoiceNumber: originalTransaction.Rechnungsnummer,
|
||
|
name: originalTransaction.Name,
|
||
|
payeeEmail: originalTransaction['Absender E-Mail-Adresse'],
|
||
|
transactionTime: originalTransaction.Uhrzeit,
|
||
|
vatAmount: anf(originalTransaction.Umsatzsteuer),
|
||
|
};
|
||
|
|
||
|
monetaryTransactions.push(paypalTransaction);
|
||
|
}
|
||
|
|
||
|
const foreignTransactions: interfaces.IPayPalTransaction[] = [];
|
||
|
const eurTransactions: interfaces.IPayPalTransaction[] = monetaryTransactions.filter(
|
||
|
(payPalTransaction: interfaces.IPayPalTransaction) => {
|
||
|
const isEur = payPalTransaction.currency === 'EUR';
|
||
|
if (isEur) {
|
||
|
return true;
|
||
|
} else {
|
||
|
foreignTransactions.push(payPalTransaction);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
let finalReturnTransactions = eurTransactions.map((transaction) => {
|
||
|
if (transaction.brutto > 0) {
|
||
|
return transaction; // lets don't bother with payments from the bank
|
||
|
}
|
||
|
const eurTime = transaction.transactionDate.getTime();
|
||
|
const foreignCandidates: interfaces.IPayPalTransaction[] = [];
|
||
|
for (const foreignTransaction of foreignTransactions) {
|
||
|
const foreignTime = foreignTransaction.transactionDate.getTime();
|
||
|
if (eurTime === foreignTime) {
|
||
|
foreignCandidates.push(foreignTransaction);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (foreignCandidates.length !== 2 && foreignCandidates.length !== 0) {
|
||
|
console.log('error! Found a weird amoun of corresponding foreign transactions');
|
||
|
}
|
||
|
|
||
|
if (foreignCandidates.length === 2) {
|
||
|
const wantedForeignTransaction = foreignCandidates.find((foreignTransaction) => {
|
||
|
return foreignTransaction.brutto < 0;
|
||
|
});
|
||
|
transaction.description = wantedForeignTransaction.description;
|
||
|
transaction.payeeEmail = wantedForeignTransaction.payeeEmail;
|
||
|
transaction.name = wantedForeignTransaction.name;
|
||
|
}
|
||
|
|
||
|
return transaction;
|
||
|
});
|
||
|
|
||
|
// lets assign simple transactions at last
|
||
|
finalReturnTransactions = finalReturnTransactions.map((transaction) => {
|
||
|
transaction.simpleTransaction = {
|
||
|
accountId: null,
|
||
|
id: transaction.transactionCode,
|
||
|
amount: transaction.brutto,
|
||
|
date: transaction.transactionDate,
|
||
|
description: transaction.description,
|
||
|
name: transaction.name,
|
||
|
};
|
||
|
return transaction;
|
||
|
});
|
||
|
|
||
|
const csvPayPalInstance = new CsvPayPal(finalReturnTransactions);
|
||
|
return csvPayPalInstance;
|
||
|
}
|
||
|
return payments;
|
||
|
}
|
||
|
}
|