Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

hapi-middleman-paypal-intacct

Package Overview
Dependencies
Maintainers
1
Versions
73
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hapi-middleman-paypal-intacct - npm Package Compare versions

Comparing version 0.0.21 to 0.0.22

3

lib/glue/hapi-paypal.js

@@ -26,6 +26,7 @@ "use strict";

try {
yield invoicing_1.hapiPayPalIntacctInvoicing.webhookHandler(request.payload);
yield invoicing_1.hapiPayPalIntacctInvoicing.webhookHandler(request.payload.webhook_event);
return reply("GOT IT!");
}
catch (err) {
request.server.log("error", `webhookEvent: ${JSON.stringify(request.payload.webhook_event)} | Error:${err.message}`);
return reply(boom.badRequest(err.message));

@@ -32,0 +33,0 @@ }

import * as hapi from "hapi";
import { IWebhookEvent, PayPalRestApi } from "paypal-rest-api";
import { IInvoice, IInvoiceItem, InvoiceModel, IWebhookEvent, PayPalRestApi } from "paypal-rest-api";
import { HapiIntacctInvoicing } from "./intacct";

@@ -49,20 +49,25 @@ export * from "./intacct";

export declare class HapiPayPalIntacctInvoicing {
static intacctKeys: string[];
private _intacct;
private _paypal;
private _server;
private _options;
constructor();
intacct: HapiIntacctInvoicing;
paypal: PayPalRestApi;
private server;
private options;
constructor();
server: hapi.Server;
options: IInvoicingOptions;
register: hapi.PluginFunction<any>;
webhookHandler(webhook: IWebhookEvent): Promise<void>;
private init();
private validateAccounts();
private validateKeys();
private refundInvoicesSync();
private refundInvoiceSync(invoice);
private createInvoiceSync();
private syncIntacctToPayPal(invoice);
private syncPayPalToIntacct(invoice);
private toPaypalInvoice(intacctInvoice);
private toPayPalLineItems(arrInvoiceItems);
private updateInacctInvoiceWithPayPalModel(intacctInvoice, paypalInvoice);
validateAccounts(): Promise<void>;
validateKeys(): Promise<void>;
refundInvoicesSync(): Promise<void>;
refundInvoiceSync(invoice: any): Promise<void>;
createInvoiceSync(): Promise<void>;
syncIntacctToPayPal(invoice: any): Promise<InvoiceModel>;
syncPayPalToIntacct(invoice: InvoiceModel): Promise<void>;
toPaypalInvoice(intacctInvoice: any): Partial<IInvoice>;
toPayPalLineItems(arrInvoiceItems: any): IInvoiceItem[];
init(): Promise<void>;
updateInacctInvoiceWithPayPalModel(intacctInvoice: any, paypalInvoice: InvoiceModel): any;
}

@@ -32,25 +32,7 @@ "use strict";

this.paypal = server.plugins["hapi-paypal"].paypal;
const optionsSchema = joi.object().keys({
autogenerate: joi.boolean().required(),
cron: joi.object().keys({
create: joi.object().keys({
latertext: joi.string().default("every 1 hour"),
}).optional(),
refund: joi.object().keys({
latertext: joi.string().default("every 1 day"),
}).optional(),
}),
merchant: paypal_rest_api_1.invoiceBillingInfoSchema.required(),
paymentaccounts: joi.object().keys({
currencies: joi.object().optional(),
default: joi.string().required(),
}).optional(),
reminderDays: joi.number().default(30),
return this.init()
.then(() => next())
.catch((err) => {
throw err;
});
const validate = joi.validate(options, optionsSchema);
if (validate.error) {
throw validate.error;
}
this.options = validate.value;
return this.init().then(() => next());
};

@@ -62,97 +44,90 @@ this.register.attributes = {

}
get intacct() {
return this._intacct;
}
set intacct(intacct) {
this._intacct = intacct;
}
get paypal() {
return this._paypal;
}
set paypal(paypal) {
this._paypal = paypal;
}
get server() {
return this._server;
}
set server(server) {
this._server = server;
}
get options() {
return this._options;
}
set options(options) {
const optionsSchema = joi.object().keys({
autogenerate: joi.boolean().required(),
cron: joi.object().keys({
create: joi.object().keys({
latertext: joi.string().default("every 1 hour"),
}).optional(),
refund: joi.object().keys({
latertext: joi.string().default("every 1 day"),
}).optional(),
}),
merchant: paypal_rest_api_1.invoiceBillingInfoSchema.required(),
paymentaccounts: joi.object().keys({
currencies: joi.object().optional(),
default: joi.string().required(),
}).optional(),
reminderDays: joi.number().default(15),
});
const validate = joi.validate(options, optionsSchema);
if (validate.error) {
throw validate.error;
}
this._options = validate.value;
}
webhookHandler(webhook) {
return __awaiter(this, void 0, void 0, function* () {
const intacctInvoice = {
PAYPALERROR: "",
};
switch (webhook.event_type) {
case "INVOICING.INVOICE.REFUNDED":
try {
this.intacct.update(webhook.resource.invoice.number, {
PAYPALINVOICESTATUS: webhook.resource.invoice.status,
});
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::webhookHandler::UpdateInvoice::INVOICING.INVOICE.PAID::${webhook.resource.invoice.id}::${err.message}`);
}
break;
case "INVOICING.INVOICE.CANCELLED":
try {
this.intacct.update(webhook.resource.invoice.number, {
PAYPALINVOICESTATUS: webhook.resource.invoice.status,
});
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::webhookHandler::UpdateInvoice::INVOICING.INVOICE.PAID::${webhook.resource.invoice.id}::${err.message}`);
}
break;
case "INVOICING.INVOICE.PAID":
const invoice = {
PAYPALERROR: "",
};
if (this.options.paymentaccounts) {
try {
const account = this.options.paymentaccounts.currencies ?
this.options.paymentaccounts.currencies[webhook.resource.invoice.total_amount.currency] :
this.options.paymentaccounts.default;
if (!account) {
throw new Error(`${webhook.resource.invoice.total_amount.currency} currency payment account not configured`);
}
yield this.intacct.createPayment({
customerid: webhook.resource.invoice.billing_info[0].additional_info,
paymentamount: webhook.resource.invoice.total_amount.value,
bankaccountid: account,
refid: webhook.resource.invoice.payments[webhook.resource.invoice.payments.length - 1].transaction_id,
arpaymentitem: [{
invoicekey: webhook.resource.invoice.number,
amount: webhook.resource.invoice.total_amount.value,
}],
});
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::webhookHandler::CreatePaymnet::INVOICING.INVOICE.PAID::${webhook.resource.invoice.id}::${err.message}`);
const error = JSON.parse(err.message);
if (error.length === 1 && error[0].errorno !== "BL03000130") {
invoice.PAYPALERROR = err.message;
}
}
const account = this.options.paymentaccounts.currencies ?
this.options.paymentaccounts.currencies[webhook.resource.invoice.total_amount.currency] :
this.options.paymentaccounts.default;
if (!account) {
throw new Error(`${webhook.resource.invoice.total_amount.currency} currency payment account not configured`);
}
invoice.PAYPALINVOICESTATUS = webhook.resource.invoice.status;
try {
this.intacct.update(webhook.resource.invoice.number, invoice);
const payment = {
customerid: webhook.resource.invoice.billing_info[0].additional_info,
paymentamount: webhook.resource.invoice.total_amount.value,
bankaccountid: account,
refid: webhook.resource.invoice.payments[webhook.resource.invoice.payments.length - 1].transaction_id,
arpaymentitem: [{
invoicekey: webhook.resource.invoice.number,
amount: webhook.resource.invoice.total_amount.value,
}],
};
yield this.intacct.createPayment(payment);
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::webhookHandler::UpdateInvoice::INVOICING.INVOICE.PAID::${webhook.resource.invoice.id}::${err.message}`);
const error = JSON.parse(err.message);
if (error.length === 1 && error[0].errorno !== "BL03000130") {
intacctInvoice.PAYPALERROR = err.message;
}
}
if (invoice.PAYPALERROR) {
throw new Error(invoice.PAYPALERROR);
}
break;
default:
}
intacctInvoice.PAYPALINVOICESTATUS = webhook.resource.invoice.status;
yield this.intacct.update(webhook.resource.invoice.number, intacctInvoice);
});
}
init() {
return __awaiter(this, void 0, void 0, function* () {
const promises = [];
try {
this.server.log("info", `hapi-paypal-intacct::initInvoicing::${JSON.stringify(this.options)}.`);
yield Promise.all([this.validateKeys(), this.validateAccounts()]);
if (this.options.cron.create && this.options.cron.create.latertext) {
promises.push(this.createInvoiceSync());
const timer = later.parse.text(this.options.cron.create.latertext);
later.setInterval(this.createInvoiceSync.bind(this), timer);
this.server.log("info", `hapi-paypal-intacct::initInvoicing::create cron set for ${this.options.cron.create.latertext}.`);
}
if (this.options.cron.refund && this.options.cron.refund.latertext) {
promises.push(this.refundInvoicesSync());
const refundtimer = later.parse.text(this.options.cron.refund.latertext);
later.setInterval(this.refundInvoicesSync.bind(this), refundtimer);
this.server.log("info", `hapi-paypal-intacct::initInvoicing::refund cron set for ${this.options.cron.refund.latertext}.`);
}
return yield Promise.all(promises);
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::init::${err.message}`);
throw err;
}
});
}
validateAccounts() {

@@ -171,20 +146,14 @@ return __awaiter(this, void 0, void 0, function* () {

}
try {
const accounts = yield this.intacct.listAccounts();
configAccounts.forEach((account) => {
if (!account) {
return;
}
const filteredAccounts = accounts.filter((faccount) => {
return faccount.BANKACCOUNTID === account;
});
if (filteredAccounts.length < 1) {
throw new Error(`Intacct Payment Account ${account} configured but does not exist in Intacct`);
}
const accounts = yield this.intacct.listAccounts();
configAccounts.forEach((account) => {
if (!account) {
return;
}
const filteredAccounts = accounts.filter((faccount) => {
return faccount.BANKACCOUNTID === account;
});
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::validateAccounts::${err.message}`);
throw err;
}
if (filteredAccounts.length < 1) {
throw new Error(`Intacct Payment Account ${account} configured but does not exist in Intacct`);
}
});
});

@@ -194,14 +163,8 @@ }

return __awaiter(this, void 0, void 0, function* () {
try {
const inspect = yield this.intacct.inspect();
Object.keys(exports.intacctInvoiceExtend).forEach((key) => {
if ((inspect).indexOf(key) === -1) {
throw new Error(`${key} not defined. Add the key to the Intacct Invoice object.`);
}
});
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::validateKeys::${err.message}`);
throw err;
}
const inspect = yield this.intacct.inspect();
HapiPayPalIntacctInvoicing.intacctKeys.forEach((key) => {
if ((inspect).indexOf(key) === -1) {
throw new Error(`${key} not defined. Add the key to the Intacct Invoice object.`);
}
});
});

@@ -211,18 +174,12 @@ }

return __awaiter(this, void 0, void 0, function* () {
try {
const promises = [];
const query = `RAWSTATE = 'V' AND PAYPALINVOICESTATUS = 'PAID'`;
const invoices = yield this.intacct.query(query);
const query = `RAWSTATE = 'V' AND PAYPALINVOICESTATUS != 'REFUNDED'`;
const invoices = yield this.intacct.query(query);
for (const invoice of invoices) {
try {
invoices.forEach((invoice) => promises.push(this.refundInvoiceSync(invoice)));
yield this.refundInvoiceSync(invoice);
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::refundInvoicesSync::${err.message}`);
this.server.log("error", `refundInvoicesSync | ${err.message}`);
}
return Promise.all(promises);
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::refundInvoicesSync::${err.message}`);
throw err;
}
});

@@ -232,37 +189,17 @@ }

return __awaiter(this, void 0, void 0, function* () {
try {
let paypalInvoice;
const paypalInvoice = yield this.paypal.invoice.get(invoice.PAYPALINVOICEID);
const intacctInvoice = {
PAYPALERROR: "",
};
for (const payment of paypalInvoice.model.payments) {
try {
paypalInvoice = yield this.paypal.invoice.get(invoice.PAYPALINVOICEID);
yield this.paypal.sale.api.refund(payment.transaction_id);
}
catch (err) {
throw err;
intacctInvoice.PAYPALERROR += JSON.stringify(err);
}
try {
const promises = [];
paypalInvoice.model.payments.forEach((payment) => __awaiter(this, void 0, void 0, function* () {
const sale = yield this.paypal.sale.get(payment.transaction_id);
promises.push(sale.refund());
}));
yield Promise.all(promises);
yield this.intacct.update(invoice.RECORDNO, {
PAYPALINVOICESTATUS: paypalInvoice.model.status,
});
}
catch (err) {
if (err.message === "Request was refused.This transaction has already been fully refunded") {
try {
yield this.intacct.update(invoice.RECORDNO, {
PAYPALINVOICESTATUS: paypalInvoice.model.status,
});
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::refundInvoiceSync::UpdateIntacct::${err.message}`);
}
}
}
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::refundInvoiceSync::${err.message}`);
}
yield paypalInvoice.get();
this.updateInacctInvoiceWithPayPalModel(intacctInvoice, paypalInvoice);
yield this.intacct.update(invoice.RECORDNO, intacctInvoice);
});

@@ -272,16 +209,36 @@ }

return __awaiter(this, void 0, void 0, function* () {
let query = process.env.INTACCT_INVOICE_QUERY || `RAWSTATE = 'A' AND ( PAYPALINVOICESTATUS IN (NULL,'DRAFT') OR PAYPALINVOICEID IS NULL ) AND WHENCREATED > '8/1/2017'`;
let query = process.env.INTACCT_INVOICE_CREATE_QUERY || `RAWSTATE = 'A' AND ( PAYPALINVOICESTATUS IN (NULL,'DRAFT') OR PAYPALINVOICEID IS NULL ) AND WHENCREATED > '8/1/2017'`;
if (!this.options.autogenerate && !process.env.INTACCT_INVOICE_QUERY) {
query += ` AND PAYPALINVOICING = 'T'`;
}
const promises = [];
try {
const invoices = yield Promise.all([this.intacct.query(query, ["RECORDNO"]), this.paypal.invoice.search({ status: ["SENT", "UNPAID"] })]);
invoices[0].forEach((invoice) => promises.push(this.syncIntacctToPayPal(invoice)));
invoices[1].forEach((invoice) => promises.push(this.syncPayPalToIntacct(invoice)));
yield Promise.all(promises);
this.server.log("info", "hapi-paypal-intacct::syncInvoices::Success");
const invoices = yield Promise.all([
this.intacct.query(query, ["RECORDNO"]),
this.paypal.invoice.search({ status: ["SENT", "UNPAID"] }),
]);
for (const invoice of invoices[0]) {
const intacctUpdate = {
PAYPALERROR: "",
};
let paypalInvoice;
try {
paypalInvoice = yield this.syncIntacctToPayPal(invoice);
}
catch (err) {
intacctUpdate.PAYPALERROR = err.message.toString();
this.server.log("error", err.toString());
}
try {
yield this.intacct.update(invoice.RECORDNO, this.updateInacctInvoiceWithPayPalModel(intacctUpdate, paypalInvoice));
}
catch (err) {
this.server.log("error", err.toString());
}
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::syncInvoices::Error::${err.message}`);
for (const invoice of invoices[1]) {
try {
yield this.syncPayPalToIntacct(invoice);
}
catch (err) {
this.server.log("error", `syncPayPalToIntacct | Error: ${err.message}`);
}
}

@@ -294,45 +251,27 @@ });

let intacctInvoice;
const intacctUpdate = {
PAYPALERROR: "",
};
try {
const fullInvoices = yield Promise.all([
this.intacct.get(invoice.RECORDNO),
this.paypal.invoice.search({ number: invoice.RECORDNO }),
]);
intacctInvoice = fullInvoices[0];
if (fullInvoices[1].length === 1) {
paypalInvoice = fullInvoices[1][0];
intacctInvoice.PAYPALINVOICEID = paypalInvoice.model.id;
}
else if (fullInvoices[1].length > 1) {
const ids = fullInvoices[1].map((inv) => inv.model.id);
const error = `Multiple PayPal Invoice IDs ${ids}. You should login to paypal and cancel one.\n`;
intacctInvoice.PAYPALERROR += error;
this.server.log("warn", error);
}
if (intacctInvoice.PAYPALINVOICEID && paypalInvoice) {
yield paypalInvoice.update(this.toPaypalInvoice(intacctInvoice));
}
else if (!intacctInvoice.PAYPALINVOICEID) {
paypalInvoice = new this.paypal.invoice(this.toPaypalInvoice(intacctInvoice));
yield paypalInvoice.create();
intacctInvoice.PAYPALINVOICEID = paypalInvoice.model.id;
}
this.updateInacctInvoiceWithPayPalModel(intacctUpdate, paypalInvoice);
if (paypalInvoice.model.status === "DRAFT") {
yield paypalInvoice.send();
}
this.updateInacctInvoiceWithPayPalModel(intacctUpdate, paypalInvoice);
const fullInvoices = yield Promise.all([
this.intacct.get(invoice.RECORDNO),
this.paypal.invoice.search({ number: invoice.RECORDNO }),
]);
intacctInvoice = fullInvoices[0];
if (fullInvoices[1].length === 1) {
paypalInvoice = fullInvoices[1][0];
intacctInvoice.PAYPALINVOICEID = paypalInvoice.model.id;
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::syncInvoices::UpdatePayPal::${invoice.RECORDNO}::${err.message}`);
intacctUpdate.PAYPALERROR += `${JSON.stringify(err.message)}\n`;
else if (fullInvoices[1].length > 1) {
const ids = fullInvoices[1].map((inv) => inv.model.id);
throw new Error(`Multiple PayPal Invoice IDs ${ids}. You should login to paypal and cancel one.\n`);
}
try {
yield this.intacct.update(intacctInvoice.RECORDNO, intacctUpdate);
if (!intacctInvoice.PAYPALINVOICEID && !paypalInvoice) {
paypalInvoice = new this.paypal.invoice(this.toPaypalInvoice(intacctInvoice));
yield paypalInvoice.create();
intacctInvoice.PAYPALINVOICEID = paypalInvoice.model.id;
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::syncInvoices::UpdateIntacct::${invoice.RECORDNO}::${err.message}`);
else if (intacctInvoice.PAYPALINVOICEID && paypalInvoice) {
yield paypalInvoice.update(this.toPaypalInvoice(intacctInvoice));
}
if (paypalInvoice.model.status === "DRAFT") {
yield paypalInvoice.send();
}
return paypalInvoice;
});

@@ -342,9 +281,10 @@ }

return __awaiter(this, void 0, void 0, function* () {
try {
const intacctInvoice = yield this.intacct.get(invoice.model.number);
if (!intacctInvoice) {
yield invoice.cancel();
}
else {
const reminder = new Date(invoice.model.metadata.last_sent_date + this.options.reminderDays);
const intacctInvoice = yield this.intacct.get(invoice.model.number);
if (!intacctInvoice) {
yield invoice.cancel();
}
else {
if (invoice.model.metadata.last_sent_date && this.options.reminderDays) {
const lastReminder = new Date(invoice.model.metadata.last_sent_date);
const reminder = new Date(lastReminder.setDate(lastReminder.getDate() + this.options.reminderDays));
const now = new Date();

@@ -355,6 +295,6 @@ if (now > reminder) {

}
else {
throw new Error("No last_sent_date property.");
}
}
catch (err) {
this.server.log("error", `hapi-paypal-intacct::syncInvoicePayPalToIntacct::${err.message}`);
}
});

@@ -368,9 +308,5 @@ }

city: intacctInvoice.BILLTO.MAILADDRESS.CITY,
country_code: intacctInvoice.BILLTO.MAILADDRESS.COUNTRYCODE,
country_code: intacctInvoice.BILLTO.MAILADDRESS.COUNTRYCODE || "US",
line1: intacctInvoice.BILLTO.MAILADDRESS.ADDRESS1,
line2: intacctInvoice.BILLTO.MAILADDRESS.ADDRESS2,
phone: {
country_code: "1",
national_number: intacctInvoice.BILLTO.PHONE1,
},
postal_code: intacctInvoice.BILLTO.MAILADDRESS.ZIP,

@@ -399,3 +335,3 @@ state: intacctInvoice.BILLTO.MAILADDRESS.STATE,

city: intacctInvoice.SHIPTO.MAILADDRESS.CITY,
country_code: intacctInvoice.SHIPTO.MAILADDRESS.COUNTRYCODE,
country_code: intacctInvoice.SHIPTO.MAILADDRESS.COUNTRYCODE || "US",
line1: intacctInvoice.SHIPTO.MAILADDRESS.ADDRESS1,

@@ -431,3 +367,23 @@ line2: intacctInvoice.SHIPTO.MAILADDRESS.ADDRESS2,

}
init() {
return __awaiter(this, void 0, void 0, function* () {
yield Promise.all([this.validateKeys(), this.validateAccounts()]);
if (this.options.cron.create && this.options.cron.create.latertext) {
yield this.createInvoiceSync();
const timer = later.parse.text(this.options.cron.create.latertext);
later.setInterval(this.createInvoiceSync.bind(this), timer);
this.server.log("info", `hapi-paypal-intacct::initInvoicing::create cron set for ${this.options.cron.create.latertext}.`);
}
if (this.options.cron.refund && this.options.cron.refund.latertext) {
yield this.refundInvoicesSync();
const refundtimer = later.parse.text(this.options.cron.refund.latertext);
later.setInterval(this.refundInvoicesSync.bind(this), refundtimer);
this.server.log("info", `hapi-paypal-intacct::initInvoicing::refund cron set for ${this.options.cron.refund.latertext}.`);
}
});
}
updateInacctInvoiceWithPayPalModel(intacctInvoice, paypalInvoice) {
if (!paypalInvoice || !paypalInvoice.model) {
return intacctInvoice;
}
intacctInvoice.PAYPALINVOICEID = paypalInvoice.model.id;

@@ -438,5 +394,13 @@ intacctInvoice.PAYPALINVOICESTATUS = paypalInvoice.model.status;

}
return intacctInvoice;
}
}
HapiPayPalIntacctInvoicing.intacctKeys = [
"PAYPALERROR",
"PAYPALINVOICEID",
"PAYPALINVOICESTATUS",
"PAYPALINVOICEURL",
"PAYPALINVOICING",
];
exports.HapiPayPalIntacctInvoicing = HapiPayPalIntacctInvoicing;
//# sourceMappingURL=index.js.map
{
"name": "hapi-middleman-paypal-intacct",
"version": "0.0.21",
"version": "0.0.22",
"description": "hapi-middleman module for integrating paypal with intacct",

@@ -25,3 +25,3 @@ "license": "MIT",

"build": "npm run clean && npm run lint && echo Using TypeScript && tsc --version && tsc --pretty",
"test": "nyc tape test/**/*-spec.ts dotenv_config_path=./example/.env | tap-spec; nyc report ---reporter=text",
"test": "nyc tape test/**/*-spec.ts dotenv_config_path=./test/.env | tap-spec; nyc report ---reporter=text",
"watch": "npm run build -- --watch",

@@ -28,0 +28,0 @@ "watch:test": "npm run test -- --watch",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc