154 lines
6.1 KiB
TypeScript
154 lines
6.1 KiB
TypeScript
import * as plugins from './paypal.plugins';
|
|
import { PayPalTransaction } from './paypal.classes.transaction';
|
|
|
|
export interface IPayPalOptions {
|
|
clientId: string;
|
|
clientSecret: string;
|
|
accountOwner: string;
|
|
}
|
|
|
|
export class PayPalAccount {
|
|
public apiBaseUrl: string = 'https://api.paypal.com';
|
|
public options: IPayPalOptions;
|
|
|
|
private apiToken: string;
|
|
private apiTokenExpirationTime: number;
|
|
|
|
constructor(optionsArg: IPayPalOptions) {
|
|
this.options = optionsArg;
|
|
}
|
|
|
|
public async getTransactionsFromTo(fromTimeMillisArg: number, toTimeMillisArg: number) {
|
|
let allTransactions: PayPalTransaction[] = [];
|
|
// lets note the time from one month before. We need that for accurate transactions pools.
|
|
const monthBeforeStartMillis =
|
|
fromTimeMillisArg - plugins.smarttime.getMilliSecondsFromUnits({ days: 30 });
|
|
do {
|
|
const transactions = await PayPalTransaction.getTransactionFor30days(this, fromTimeMillisArg);
|
|
allTransactions = allTransactions.concat(transactions);
|
|
fromTimeMillisArg =
|
|
fromTimeMillisArg + plugins.smarttime.getMilliSecondsFromUnits({ days: 30 });
|
|
} while (fromTimeMillisArg < toTimeMillisArg);
|
|
|
|
const invoiceIds: string[] = [];
|
|
const transactionPools: PayPalTransaction[][] = [];
|
|
// lets get all invoiceids
|
|
allTransactions.forEach((transactionArg) => {
|
|
const invoiceId = transactionArg.data.originApiObject.transaction_info.invoice_id;
|
|
if (!invoiceIds.includes(invoiceId)) {
|
|
invoiceIds.push(invoiceId);
|
|
}
|
|
});
|
|
|
|
// lets get all transactions per invoiceId
|
|
invoiceIds.forEach((invoiceIdArg) => {
|
|
const transactionPool: PayPalTransaction[] = [];
|
|
allTransactions.forEach((transactionArg) => {
|
|
if (transactionArg.data.originApiObject.transaction_info.invoice_id === invoiceIdArg) {
|
|
transactionPool.push(transactionArg);
|
|
}
|
|
});
|
|
transactionPools.push(transactionPool);
|
|
});
|
|
|
|
const previousMonthTransactions = await PayPalTransaction.getTransactionFor30days(
|
|
this,
|
|
monthBeforeStartMillis
|
|
);
|
|
|
|
transactionPools.forEach((transactionPoolArg) => {
|
|
const poolInvoiceId = transactionPoolArg[0].data.originApiObject.transaction_info.invoice_id;
|
|
previousMonthTransactions.forEach((transactionArg) => {
|
|
if (transactionArg.data.originApiObject.transaction_info.invoice_id === poolInvoiceId) {
|
|
transactionPoolArg.push(transactionArg);
|
|
}
|
|
});
|
|
});
|
|
|
|
let finalTransactions: PayPalTransaction[] = [];
|
|
// lets process all transactionPool
|
|
transactionPools.forEach((transactionPoolArg) => {
|
|
// lets detect foreign transactions
|
|
let hasForeignTransactions = false;
|
|
transactionPoolArg.forEach((transactionArg) => {
|
|
if (transactionArg.data.currency !== 'EUR') {
|
|
hasForeignTransactions = true;
|
|
}
|
|
});
|
|
if (hasForeignTransactions && transactionPoolArg.length < 4) {
|
|
console.log(
|
|
`Pool with invoiceId ${transactionPoolArg[0].data.originApiObject.transaction_info.invoice_id} is not completed yet. Omminiting ${transactionPoolArg.length} transactions as a result.`
|
|
);
|
|
return;
|
|
}
|
|
if (hasForeignTransactions && transactionPoolArg.length === 4) {
|
|
const negativeNativeTransaction = transactionPoolArg.find(transactionArg => {
|
|
return transactionArg.data.amount < 0 && transactionArg.data.currency === 'EUR';
|
|
});
|
|
|
|
const negativeForeignTransaction = transactionPoolArg.find(transactionArg => {
|
|
return transactionArg.data.amount < 0 && transactionArg.data.currency !== 'EUR';
|
|
});
|
|
|
|
const positiveNativeTransaction = transactionPoolArg.find(transactionArg => {
|
|
return transactionArg.data.amount > 0 && transactionArg.data.currency === 'EUR';
|
|
});
|
|
|
|
const positiveForeignTransaction = transactionPoolArg.find(transactionArg => {
|
|
return transactionArg.data.amount > 0 && transactionArg.data.currency !== 'EUR';
|
|
});
|
|
|
|
negativeNativeTransaction.data.name = negativeForeignTransaction.data.name;
|
|
negativeNativeTransaction.data.description = negativeForeignTransaction.data.description;
|
|
positiveNativeTransaction.data.name = this.options.accountOwner;
|
|
positiveNativeTransaction.data.description = 'account balance transfer';
|
|
transactionPoolArg = transactionPoolArg.filter(transactionArg => transactionArg.data.currency === 'EUR');
|
|
}
|
|
if (!hasForeignTransactions && transactionPoolArg.length === 2) {
|
|
const positiveNativeTransaction = transactionPoolArg.find(transactionArg => {
|
|
return transactionArg.data.amount > 0 && transactionArg.data.currency === 'EUR';
|
|
});
|
|
positiveNativeTransaction.data.name = this.options.accountOwner;
|
|
positiveNativeTransaction.data.description = 'account balance transfer';
|
|
}
|
|
// pool is ready
|
|
finalTransactions = finalTransactions.concat(transactionPoolArg);
|
|
});
|
|
|
|
return finalTransactions;
|
|
}
|
|
|
|
public async request(methodArg: 'GET' | 'POST', routeArg: string, payloadArg: any) {
|
|
if (!this.apiToken || this.apiTokenExpirationTime < Date.now()) {
|
|
const authHeader = `Basic ${plugins.smartstring.base64.encode(
|
|
`${this.options.clientId}:${this.options.clientSecret}`
|
|
)}`;
|
|
const response = await plugins.smartrequest.request(
|
|
`${this.apiBaseUrl}/v1/oauth2/token?grant_type=client_credentials`,
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
'Accept-Language': 'en_US',
|
|
Authorization: authHeader,
|
|
},
|
|
keepAlive: false,
|
|
}
|
|
);
|
|
this.apiToken = response.body.access_token;
|
|
this.apiTokenExpirationTime = Date.now() + response.body.expires_in * 1000 - 600000;
|
|
}
|
|
|
|
// we have a token
|
|
const response = await plugins.smartrequest.request(`${this.apiBaseUrl}${routeArg}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
'Accept-Language': 'en_US',
|
|
Authorization: `Bearer ${this.apiToken}`,
|
|
},
|
|
});
|
|
return response.body;
|
|
}
|
|
}
|