Replaces MongoDB support with PostgreSQL (#151)
- All schemas have been rewritten to a relational model - All services have been rewritten to accommodate the new data model - Adds idempotency keys to core endpoints allowing you to retry requests with no additional side effects - Adds staged jobs to avoid putting jobs in the queue when transactions abort - Adds atomic transactions to all methods with access to the data layer Co-authored-by: Oliver Windall Juhl <oliver@mrbltech.com>
This commit is contained in:
co-authored by
Oliver Windall Juhl
parent
5f819486fc
commit
f1baca3cbd
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "medusa-plugin-brightpearl",
|
||||
"version": "1.0.26",
|
||||
"version": "1.0.21-alpha.176+0646bd3",
|
||||
"description": "Brightpearl plugin for Medusa Commerce",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
@@ -27,7 +27,7 @@
|
||||
"cross-env": "^7.0.2",
|
||||
"eslint": "^6.8.0",
|
||||
"jest": "^25.5.2",
|
||||
"medusa-test-utils": "^1.0.13",
|
||||
"medusa-test-utils": "^1.0.12-alpha.176+0646bd3",
|
||||
"prettier": "^2.0.5"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -43,8 +43,8 @@
|
||||
"axios": "^0.19.2",
|
||||
"axios-rate-limit": "^1.2.1",
|
||||
"express": "^4.17.1",
|
||||
"medusa-core-utils": "^1.0.11",
|
||||
"medusa-core-utils": "^1.0.12-alpha.787+0646bd3",
|
||||
"randomatic": "^3.1.1"
|
||||
},
|
||||
"gitHead": "3bd91f65304ed1d31c41b85d5c87123450e0542e"
|
||||
"gitHead": "0646bd395a6056657cb0aa93c13699c4a9dbbcdd"
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
const REFRESH_CRON = process.env.BP_REFRESH_CRON || "5 4 * * */6"
|
||||
|
||||
const refreshToken = async (container) => {
|
||||
const logger = container.resolve("logger")
|
||||
const oauthService = container.resolve("oauthService")
|
||||
const eventBus = container.resolve("eventBusService")
|
||||
|
||||
try {
|
||||
logger.info("registering refresh cron job BP")
|
||||
eventBus.createCronJob("refresh-token-bp", {}, REFRESH_CRON, async () => {
|
||||
const appData = await oauthService.retrieveByName("brightpearl")
|
||||
const data = appData.data
|
||||
if (data && data.refresh_token) {
|
||||
return oauthService.refreshToken("brightpearl", data.refresh_token)
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
if (err.name === "not_allowed") {
|
||||
return
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
export default refreshToken
|
||||
@@ -6,8 +6,52 @@ import MockAdapter from "axios-mock-adapter"
|
||||
|
||||
jest.mock("../../utils/brightpearl")
|
||||
|
||||
const order = {
|
||||
region: {
|
||||
tax_code: "1234",
|
||||
},
|
||||
items: [
|
||||
{
|
||||
title: "Test",
|
||||
variant: {
|
||||
sku: "TEST",
|
||||
},
|
||||
unit_price: 1100,
|
||||
quantity: 2,
|
||||
},
|
||||
],
|
||||
shipping_total: 12399,
|
||||
shipping_methods: [
|
||||
{
|
||||
name: "standard",
|
||||
price: 12399,
|
||||
},
|
||||
],
|
||||
payment_method: {
|
||||
id: "123",
|
||||
},
|
||||
tax_rate: 23.1,
|
||||
currency_code: "DKK",
|
||||
display_id: "1234",
|
||||
id: "12355",
|
||||
discounts: [],
|
||||
shipping_address: {
|
||||
first_name: "Test",
|
||||
last_name: "Testson",
|
||||
address_1: "Test",
|
||||
address_2: "TEst",
|
||||
postal_code: "1234",
|
||||
country_code: "DK",
|
||||
phone: "12345678",
|
||||
},
|
||||
email: "test@example.com",
|
||||
}
|
||||
|
||||
const OrderService = {
|
||||
setMetadata: () => {
|
||||
retrieve: () => {
|
||||
return Promise.resolve(order)
|
||||
},
|
||||
update: () => {
|
||||
return Promise.resolve()
|
||||
},
|
||||
}
|
||||
@@ -20,7 +64,7 @@ const TotalsService = {
|
||||
return Promise.resolve([])
|
||||
},
|
||||
getShippingTotal: () => {
|
||||
return 123.9999929393293
|
||||
return 12399
|
||||
},
|
||||
rounded: (value) => {
|
||||
const decimalPlaces = 4
|
||||
@@ -91,45 +135,6 @@ describe("BrightpearlService", () => {
|
||||
})
|
||||
|
||||
describe("createSalesOrder", () => {
|
||||
const order = {
|
||||
items: [
|
||||
{
|
||||
title: "Test",
|
||||
content: {
|
||||
variant: {
|
||||
sku: "TEST",
|
||||
},
|
||||
unit_price: 11,
|
||||
},
|
||||
quantity: 2,
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
name: "standard",
|
||||
price: 123.9999929393293,
|
||||
},
|
||||
],
|
||||
payment_method: {
|
||||
_id: "123",
|
||||
},
|
||||
tax_rate: 0.231,
|
||||
currency_code: "DKK",
|
||||
display_id: "1234",
|
||||
_id: "12355",
|
||||
discounts: [],
|
||||
shipping_address: {
|
||||
first_name: "Test",
|
||||
last_name: "Testson",
|
||||
address_1: "Test",
|
||||
address_2: "TEst",
|
||||
postal_code: "1234",
|
||||
country_code: "DK",
|
||||
phone: "12345678",
|
||||
},
|
||||
email: "test@example.com",
|
||||
}
|
||||
|
||||
const bpService = new BrightpearlService(
|
||||
{
|
||||
orderService: OrderService,
|
||||
@@ -187,8 +192,8 @@ describe("BrightpearlService", () => {
|
||||
{
|
||||
name: "Shipping: standard",
|
||||
quantity: 1,
|
||||
net: 124,
|
||||
tax: 28.644,
|
||||
net: 123.99,
|
||||
tax: 28.6417,
|
||||
taxCode: "1234",
|
||||
nominalCode: "4040",
|
||||
},
|
||||
|
||||
@@ -160,7 +160,7 @@ class BrightpearlService extends BaseService {
|
||||
|
||||
// Only update if the inventory levels have changed
|
||||
if (parseInt(v.inventory_quantity) !== parseInt(onHand)) {
|
||||
return this.productVariantService_.update(v._id, {
|
||||
return this.productVariantService_.update(v.id, {
|
||||
inventory_quantity: onHand,
|
||||
})
|
||||
}
|
||||
@@ -181,10 +181,13 @@ class BrightpearlService extends BaseService {
|
||||
const onHand = availability[productId].total.onHand
|
||||
|
||||
const sku = brightpearlProduct.identity.sku
|
||||
const [variant] = await this.productVariantService_.list({ sku })
|
||||
if (!sku) return
|
||||
|
||||
const variant = await this.productVariantService_
|
||||
.retrieveBySKU(sku)
|
||||
.catch((_) => undefined)
|
||||
if (variant && variant.manage_inventory) {
|
||||
await this.productVariantService_.update(variant._id, {
|
||||
await this.productVariantService_.update(variant.id, {
|
||||
inventory_quantity: onHand,
|
||||
})
|
||||
}
|
||||
@@ -249,7 +252,7 @@ class BrightpearlService extends BaseService {
|
||||
}
|
||||
|
||||
async createRefundCredit(fromOrder, fromRefund) {
|
||||
const region = await this.regionService_.retrieve(fromOrder.region_id)
|
||||
const region = fromOrder.region
|
||||
const client = await this.getClient()
|
||||
const authData = await this.getAuthData()
|
||||
const orderId = fromOrder.metadata.brightpearl_sales_order_id
|
||||
@@ -266,7 +269,7 @@ class BrightpearlService extends BaseService {
|
||||
const order = {
|
||||
currency: parentSo.currency,
|
||||
ref: parentSo.ref,
|
||||
externalRef: `${parentSo.externalRef}.${fromOrder.refunds.length}`,
|
||||
externalRef: `${parentSo.externalRef}.${fromRefund.id}`,
|
||||
channelId: this.options.channel_id || `1`,
|
||||
installedIntegrationInstanceId: authData.installation_instance_id,
|
||||
customer: parentSo.customer,
|
||||
@@ -277,11 +280,12 @@ class BrightpearlService extends BaseService {
|
||||
name: `${fromRefund.reason}: ${fromRefund.note}`,
|
||||
quantity: 1,
|
||||
taxCode: region.tax_code,
|
||||
net: this.totalsService_.rounded(
|
||||
fromRefund.amount / (1 + fromOrder.tax_rate)
|
||||
net: this.bpnum_(
|
||||
fromRefund.amount,
|
||||
10000 / (100 + fromOrder.tax_rate)
|
||||
),
|
||||
tax: this.totalsService_.rounded(
|
||||
fromRefund.amount - fromRefund.amount / (1 + fromOrder.tax_rate)
|
||||
tax: this.bpnum_(
|
||||
fromRefund.amount * (1 - 100 / (100 + fromOrder.tax_rate))
|
||||
),
|
||||
nominalCode: accountingCode,
|
||||
},
|
||||
@@ -291,15 +295,15 @@ class BrightpearlService extends BaseService {
|
||||
return client.orders
|
||||
.createCredit(order)
|
||||
.then(async (creditId) => {
|
||||
const paymentMethod = fromOrder.payment_method
|
||||
const paymentMethod = fromOrder.payments[0]
|
||||
const paymentType = "PAYMENT"
|
||||
const payment = {
|
||||
transactionRef: `${paymentMethod._id}.${fromOrder.refunds.length}`,
|
||||
transactionCode: fromOrder._id,
|
||||
transactionRef: `${paymentMethod.id}.${fromRefund.id}`,
|
||||
transactionCode: fromOrder.id,
|
||||
paymentMethodCode: this.options.payment_method_code || "1220",
|
||||
orderId: creditId,
|
||||
currencyIsoCode: fromOrder.currency_code,
|
||||
amountPaid: fromRefund.amount,
|
||||
currencyIsoCode: fromOrder.currency_code.toUpperCase(),
|
||||
amountPaid: this.bpnum_(fromRefund.amount),
|
||||
paymentDate: new Date(),
|
||||
paymentType,
|
||||
}
|
||||
@@ -309,18 +313,21 @@ class BrightpearlService extends BaseService {
|
||||
|
||||
await client.payments.create(payment)
|
||||
|
||||
return this.orderService_.setMetadata(
|
||||
fromOrder._id,
|
||||
"brightpearl_credit_ids",
|
||||
newIds
|
||||
)
|
||||
return this.orderService_.update(fromOrder.id, {
|
||||
metadata: {
|
||||
brightpearl_credit_ids: newIds,
|
||||
},
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
console.log(err.response.data.errors)
|
||||
})
|
||||
.catch((err) => console.log(err.response.data.errors))
|
||||
}
|
||||
}
|
||||
|
||||
async createSalesCredit(fromOrder, fromReturn) {
|
||||
const region = await this.regionService_.retrieve(fromOrder.region_id)
|
||||
const region = fromOrder.region
|
||||
const client = await this.getClient()
|
||||
const authData = await this.getAuthData()
|
||||
const orderId = fromOrder.metadata.brightpearl_sales_order_id
|
||||
@@ -329,7 +336,7 @@ class BrightpearlService extends BaseService {
|
||||
const order = {
|
||||
currency: parentSo.currency,
|
||||
ref: parentSo.ref,
|
||||
externalRef: `${parentSo.externalRef}.${fromOrder.refunds.length}`,
|
||||
externalRef: `${parentSo.externalRef}.${fromReturn.id}`,
|
||||
channelId: this.options.channel_id || `1`,
|
||||
installedIntegrationInstanceId: authData.installation_instance_id,
|
||||
customer: parentSo.customer,
|
||||
@@ -359,18 +366,14 @@ class BrightpearlService extends BaseService {
|
||||
return acc + next.net + next.tax
|
||||
}, 0)
|
||||
|
||||
const difference = fromReturn.refund_amount - total
|
||||
const difference = (fromReturn.refund_amount / 100 - total) * 100
|
||||
if (difference) {
|
||||
order.rows.push({
|
||||
name: "Difference",
|
||||
quantity: 1,
|
||||
taxCode: region.tax_code,
|
||||
net: this.totalsService_.rounded(
|
||||
difference / (1 + fromOrder.tax_rate)
|
||||
),
|
||||
tax: this.totalsService_.rounded(
|
||||
difference - difference / (1 + fromOrder.tax_rate)
|
||||
),
|
||||
net: this.bpnum_(difference, 10000 / (100 + fromOrder.tax_rate)),
|
||||
tax: this.bpnum_(difference * (1 - 100 / (100 + fromOrder.tax_rate))),
|
||||
nominalCode: this.options.sales_account_code || "4000",
|
||||
})
|
||||
}
|
||||
@@ -378,15 +381,15 @@ class BrightpearlService extends BaseService {
|
||||
return client.orders
|
||||
.createCredit(order)
|
||||
.then(async (creditId) => {
|
||||
const paymentMethod = fromOrder.payment_method
|
||||
const paymentMethod = fromOrder.payments[0]
|
||||
const paymentType = "PAYMENT"
|
||||
const payment = {
|
||||
transactionRef: `${paymentMethod._id}.${fromOrder.refunds.length}`,
|
||||
transactionCode: fromOrder._id,
|
||||
transactionRef: `${paymentMethod.id}.${fromReturn.id}`,
|
||||
transactionCode: fromOrder.id,
|
||||
paymentMethodCode: this.options.payment_method_code || "1220",
|
||||
orderId: creditId,
|
||||
currencyIsoCode: fromOrder.currency_code,
|
||||
amountPaid: fromReturn.refund_amount,
|
||||
currencyIsoCode: fromOrder.currency_code.toUpperCase(),
|
||||
amountPaid: this.bpnum_(fromReturn.refund_amount),
|
||||
paymentDate: new Date(),
|
||||
paymentType,
|
||||
}
|
||||
@@ -396,17 +399,34 @@ class BrightpearlService extends BaseService {
|
||||
|
||||
await client.payments.create(payment)
|
||||
|
||||
return this.orderService_.setMetadata(
|
||||
fromOrder._id,
|
||||
"brightpearl_credit_ids",
|
||||
newIds
|
||||
)
|
||||
return this.orderService_.update(fromOrder.id, {
|
||||
metadata: {
|
||||
brightpearl_credit_ids: newIds,
|
||||
},
|
||||
})
|
||||
})
|
||||
.catch((err) => console.log(err.response.data.errors))
|
||||
.catch((err) => console.log(err))
|
||||
}
|
||||
}
|
||||
|
||||
async createSalesOrder(fromOrder) {
|
||||
async createSalesOrder(fromOrderId) {
|
||||
const fromOrder = await this.orderService_.retrieve(fromOrderId, {
|
||||
select: [
|
||||
"total",
|
||||
"subtotal",
|
||||
"shipping_total",
|
||||
"gift_card_total",
|
||||
"discount_total",
|
||||
],
|
||||
relations: [
|
||||
"region",
|
||||
"shipping_address",
|
||||
"billing_address",
|
||||
"shipping_methods",
|
||||
"payments",
|
||||
],
|
||||
})
|
||||
|
||||
const client = await this.getClient()
|
||||
let customer = await this.retrieveCustomerByEmail(fromOrder.email)
|
||||
|
||||
@@ -420,10 +440,10 @@ class BrightpearlService extends BaseService {
|
||||
const { shipping_address } = fromOrder
|
||||
const order = {
|
||||
currency: {
|
||||
code: fromOrder.currency_code,
|
||||
code: fromOrder.currency_code.toUpperCase(),
|
||||
},
|
||||
ref: fromOrder.display_id,
|
||||
externalRef: fromOrder._id,
|
||||
externalRef: fromOrder.id,
|
||||
channelId: this.options.channel_id || `1`,
|
||||
installedIntegrationInstanceId: authData.installation_instance_id,
|
||||
statusId: this.options.default_status_id || `3`,
|
||||
@@ -464,33 +484,34 @@ class BrightpearlService extends BaseService {
|
||||
return salesOrderId
|
||||
})
|
||||
.then((salesOrderId) => {
|
||||
return this.orderService_.setMetadata(
|
||||
fromOrder._id,
|
||||
"brightpearl_sales_order_id",
|
||||
salesOrderId
|
||||
)
|
||||
return this.orderService_.update(fromOrder.id, {
|
||||
metadata: {
|
||||
brightpearl_sales_order_id: salesOrderId,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async createSwapPayment(fromSwap) {
|
||||
async createSwapPayment(fromSwapId) {
|
||||
const fromSwap = await this.swapService_.retrieve(fromSwapId)
|
||||
|
||||
const client = await this.getClient()
|
||||
const soId =
|
||||
fromSwap.metadata && fromSwap.metadata.brightpearl_sales_order_id
|
||||
|
||||
if (!soId || fromSwap.amount_paid <= 0) {
|
||||
if (!soId || fromSwap.difference_due <= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const paymentType = "RECEIPT"
|
||||
const paymentMethod = fromSwap.payment_method
|
||||
const payment = {
|
||||
transactionRef: `${paymentMethod._id}.${paymentType}`, // Brightpearl cannot accept an auth and capture with same ref
|
||||
transactionCode: fromSwap._id,
|
||||
transactionRef: `${fromSwap.id}.${paymentType}`, // Brightpearl cannot accept an auth and capture with same ref
|
||||
transactionCode: fromSwap.id,
|
||||
paymentMethodCode: this.options.payment_method_code || "1220",
|
||||
orderId: soId,
|
||||
paymentDate: new Date(),
|
||||
currencyIsoCode: fromSwap.currency_code,
|
||||
amountPaid: fromSwap.amount_paid,
|
||||
currencyIsoCode: fromSwap.order.currency_code.toUpperCase(),
|
||||
amountPaid: fromSwap.difference_due,
|
||||
paymentType,
|
||||
}
|
||||
|
||||
@@ -502,20 +523,23 @@ class BrightpearlService extends BaseService {
|
||||
let customer = await this.retrieveCustomerByEmail(fromOrder.email)
|
||||
|
||||
if (!customer) {
|
||||
customer = await this.createCustomer(fromOrder)
|
||||
customer = await this.createCustomer({
|
||||
...fromOrder,
|
||||
...fromSwap,
|
||||
})
|
||||
}
|
||||
|
||||
const authData = await this.getAuthData()
|
||||
|
||||
const sIndex = fromOrder.swaps.findIndex((s) => fromSwap._id.equals(s))
|
||||
const sIndex = fromOrder.swaps.findIndex((s) => fromSwap.id === s.id)
|
||||
|
||||
const { shipping_address } = fromSwap
|
||||
const order = {
|
||||
currency: {
|
||||
code: fromOrder.currency_code,
|
||||
code: fromOrder.currency_code.toUpperCase(),
|
||||
},
|
||||
ref: `${fromOrder.display_id}-S${sIndex + 1}`,
|
||||
externalRef: `${fromOrder._id}.${fromSwap._id}`,
|
||||
externalRef: `${fromOrder.id}.${fromSwap.id}`,
|
||||
channelId: this.options.channel_id || `1`,
|
||||
installedIntegrationInstanceId: authData.installation_instance_id,
|
||||
statusId:
|
||||
@@ -545,7 +569,7 @@ class BrightpearlService extends BaseService {
|
||||
},
|
||||
},
|
||||
rows: await this.getBrightpearlRows({
|
||||
region_id: fromOrder.region_id,
|
||||
region: fromOrder.region,
|
||||
discounts: fromOrder.discounts,
|
||||
tax_rate: fromOrder.tax_rate,
|
||||
items: fromSwap.additional_items,
|
||||
@@ -562,14 +586,14 @@ class BrightpearlService extends BaseService {
|
||||
return acc + parseFloat(next.net) + parseFloat(next.tax)
|
||||
}, 0)
|
||||
|
||||
const paymentMethod = fromOrder.payment_method
|
||||
const paymentMethod = fromOrder.payments[0]
|
||||
const paymentType = "RECEIPT"
|
||||
const payment = {
|
||||
transactionRef: `${paymentMethod._id}.${paymentType}-${fromSwap._id}`,
|
||||
transactionCode: fromOrder._id,
|
||||
transactionRef: `${paymentMethod.id}.${paymentType}-${fromSwap.id}`,
|
||||
transactionCode: fromOrder.id,
|
||||
paymentMethodCode: this.options.payment_method_code || "1220",
|
||||
orderId: salesOrderId,
|
||||
currencyIsoCode: fromOrder.currency_code,
|
||||
currencyIsoCode: fromOrder.currency_code.toUpperCase(),
|
||||
amountPaid: total,
|
||||
paymentDate: new Date(),
|
||||
paymentType,
|
||||
@@ -577,33 +601,33 @@ class BrightpearlService extends BaseService {
|
||||
|
||||
await client.payments.create(payment)
|
||||
|
||||
return this.swapService_.setMetadata(
|
||||
fromSwap._id,
|
||||
"brightpearl_sales_order_id",
|
||||
salesOrderId
|
||||
)
|
||||
return this.swapService_.update(fromSwap.id, {
|
||||
metadata: {
|
||||
brightpearl_sales_order_id: salesOrderId,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async createSwapCredit(fromOrder, fromSwap) {
|
||||
const region = await this.regionService_.retrieve(fromOrder.region_id)
|
||||
const region = fromOrder.region
|
||||
const client = await this.getClient()
|
||||
const authData = await this.getAuthData()
|
||||
const orderId = fromOrder.metadata.brightpearl_sales_order_id
|
||||
const sIndex = fromOrder.swaps.findIndex((s) => fromSwap._id.equals(s))
|
||||
const sIndex = fromOrder.swaps.findIndex((s) => fromSwap.id === s.id)
|
||||
|
||||
if (orderId) {
|
||||
const parentSo = await client.orders.retrieve(orderId)
|
||||
const order = {
|
||||
currency: parentSo.currency,
|
||||
ref: `${parentSo.ref}-S${sIndex + 1}`,
|
||||
externalRef: `${parentSo.externalRef}.${fromSwap._id}`,
|
||||
externalRef: `${parentSo.externalRef}.${fromSwap.id}`,
|
||||
channelId: this.options.channel_id || `1`,
|
||||
installedIntegrationInstanceId: authData.installation_instance_id,
|
||||
customer: parentSo.customer,
|
||||
delivery: parentSo.delivery,
|
||||
parentId: orderId,
|
||||
rows: fromSwap.return.items.map((i) => {
|
||||
rows: fromSwap.return_order.items.map((i) => {
|
||||
const parentRow = parentSo.rows.find((row) => {
|
||||
return row.externalRef === i.item_id
|
||||
})
|
||||
@@ -623,13 +647,18 @@ class BrightpearlService extends BaseService {
|
||||
}),
|
||||
}
|
||||
|
||||
if (fromSwap.return_shipping && fromSwap.return_shipping.price) {
|
||||
if (
|
||||
fromSwap.return_order.shipping_method &&
|
||||
fromSwap.return_order.shipping_method.price
|
||||
) {
|
||||
order.rows.push({
|
||||
name: "Return Shipping",
|
||||
quantity: 1,
|
||||
taxCode: region.tax_code,
|
||||
net: -1 * fromSwap.return_shipping.price,
|
||||
tax: -1 * fromSwap.return_shipping.price * fromOrder.tax_rate,
|
||||
net: (-1 * fromSwap.return_order.shipping_method.price) / 100,
|
||||
tax:
|
||||
((-1 * fromSwap.return_order.shipping_method.price) / 100) *
|
||||
(fromOrder.tax_rate / 100),
|
||||
nominalCode: this.options.shipping_account_code || "4040",
|
||||
})
|
||||
}
|
||||
@@ -641,14 +670,14 @@ class BrightpearlService extends BaseService {
|
||||
return client.orders
|
||||
.createCredit(order)
|
||||
.then(async (creditId) => {
|
||||
const paymentMethod = fromOrder.payment_method
|
||||
const paymentMethod = fromOrder.payments[0]
|
||||
const paymentType = "PAYMENT"
|
||||
const payment = {
|
||||
transactionRef: `${paymentMethod._id}.${paymentType}-${fromSwap._id}`,
|
||||
transactionCode: fromSwap._id,
|
||||
transactionRef: `${paymentMethod.id}.${paymentType}-${fromSwap.id}`,
|
||||
transactionCode: fromSwap.id,
|
||||
paymentMethodCode: this.options.payment_method_code || "1220",
|
||||
orderId: creditId,
|
||||
currencyIsoCode: fromSwap.currency_code,
|
||||
currencyIsoCode: fromOrder.currency_code.toUpperCase(),
|
||||
amountPaid: total,
|
||||
paymentDate: new Date(),
|
||||
paymentType,
|
||||
@@ -660,7 +689,12 @@ class BrightpearlService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
async createPayment(fromOrder) {
|
||||
async createPayment(fromOrderId) {
|
||||
const fromOrder = await this.orderService_.retrieve(fromOrderId, {
|
||||
select: ["total"],
|
||||
relations: ["payments"],
|
||||
})
|
||||
|
||||
const client = await this.getClient()
|
||||
const soId =
|
||||
fromOrder.metadata && fromOrder.metadata.brightpearl_sales_order_id
|
||||
@@ -669,38 +703,35 @@ class BrightpearlService extends BaseService {
|
||||
}
|
||||
|
||||
const paymentType = "RECEIPT"
|
||||
const paymentMethod = fromOrder.payment_method
|
||||
const payment = {
|
||||
transactionRef: `${paymentMethod._id}.${paymentType}`, // Brightpearl cannot accept an auth and capture with same ref
|
||||
transactionCode: fromOrder._id,
|
||||
transactionRef: `${fromOrder.id}.${paymentType}`, // Brightpearl cannot accept an auth and capture with same ref
|
||||
transactionCode: fromOrder.id,
|
||||
paymentMethodCode: this.options.payment_method_code || "1220",
|
||||
orderId: soId,
|
||||
paymentDate: new Date(),
|
||||
currencyIsoCode: fromOrder.currency_code,
|
||||
amountPaid: await this.totalsService_.getTotal(fromOrder),
|
||||
currencyIsoCode: fromOrder.currency_code.toUpperCase(),
|
||||
amountPaid: this.bpnum_(fromOrder.total),
|
||||
paymentType,
|
||||
}
|
||||
|
||||
await client.payments.create(payment)
|
||||
return client.payments.create(payment)
|
||||
}
|
||||
|
||||
async getBrightpearlRows(fromOrder) {
|
||||
const region = await this.regionService_.retrieve(fromOrder.region_id)
|
||||
const { region } = fromOrder
|
||||
const discount = fromOrder.discounts.find(
|
||||
({ discount_rule }) => discount_rule.type !== "free_shipping"
|
||||
({ rule }) => rule.type !== "free_shipping"
|
||||
)
|
||||
let lineDiscounts = []
|
||||
if (discount && !discount.is_giftcard) {
|
||||
if (discount) {
|
||||
lineDiscounts = this.totalsService_.getLineDiscounts(fromOrder, discount)
|
||||
}
|
||||
|
||||
const lines = await Promise.all(
|
||||
fromOrder.items.map(async (item) => {
|
||||
const bpProduct = await this.retrieveProductBySKU(
|
||||
item.content.variant.sku
|
||||
)
|
||||
const bpProduct = await this.retrieveProductBySKU(item.variant.sku)
|
||||
|
||||
const ld = lineDiscounts.find((l) => item._id === l.item._id) || {
|
||||
const ld = lineDiscounts.find((l) => item.id === l.item.id) || {
|
||||
amount: 0,
|
||||
}
|
||||
|
||||
@@ -710,13 +741,14 @@ class BrightpearlService extends BaseService {
|
||||
} else {
|
||||
row.name = item.title
|
||||
}
|
||||
row.net = this.totalsService_.rounded(
|
||||
item.content.unit_price * item.quantity - ld.amount
|
||||
row.net = this.bpnum_(item.unit_price * item.quantity - ld.amount)
|
||||
row.tax = this.bpnum_(
|
||||
item.unit_price * item.quantity - ld.amount,
|
||||
fromOrder.tax_rate
|
||||
)
|
||||
row.tax = this.totalsService_.rounded(row.net * fromOrder.tax_rate)
|
||||
row.quantity = item.quantity
|
||||
row.taxCode = region.tax_code
|
||||
row.externalRef = item._id
|
||||
row.externalRef = item.id
|
||||
row.nominalCode = this.options.sales_account_code || "4000"
|
||||
|
||||
if (item.is_giftcard) {
|
||||
@@ -731,30 +763,28 @@ class BrightpearlService extends BaseService {
|
||||
// correspondingly. This reduces the amount payable, while debiting the
|
||||
// gift card account that was previously credited, when the gift card was
|
||||
// purchased.
|
||||
if (discount && discount.is_giftcard) {
|
||||
const discountTotal = await this.totalsService_.getDiscountTotal(
|
||||
fromOrder
|
||||
)
|
||||
const gcTotal = fromOrder.gift_card_total
|
||||
if (gcTotal) {
|
||||
lines.push({
|
||||
name: `Gift Card: ${discount.code}`,
|
||||
net: -1 * discountTotal,
|
||||
tax: this.totalsService_.rounded(
|
||||
-1 * discountTotal * fromOrder.tax_rate
|
||||
),
|
||||
name: `Gift Card`,
|
||||
net: this.bpnum_(-1 * gcTotal),
|
||||
tax: this.bpnum_(-1 * gcTotal, fromOrder.tax_rate),
|
||||
quantity: 1,
|
||||
taxCode: region.tax_code,
|
||||
nominalCode: this.options.gift_card_account_code || "4000",
|
||||
})
|
||||
}
|
||||
|
||||
const shippingTotal = this.totalsService_.getShippingTotal(fromOrder)
|
||||
const shippingTotal =
|
||||
fromOrder.shipping_total ||
|
||||
this.totalsService_.getShippingTotal(fromOrder)
|
||||
const shippingMethods = fromOrder.shipping_methods
|
||||
if (shippingMethods.length > 0) {
|
||||
lines.push({
|
||||
name: `Shipping: ${shippingMethods.map((m) => m.name).join(" + ")}`,
|
||||
quantity: 1,
|
||||
net: this.totalsService_.rounded(shippingTotal),
|
||||
tax: this.totalsService_.rounded(shippingTotal * fromOrder.tax_rate),
|
||||
net: this.bpnum_(shippingTotal),
|
||||
tax: this.bpnum_(shippingTotal, fromOrder.tax_rate),
|
||||
taxCode: region.tax_code,
|
||||
nominalCode: this.options.shipping_account_code || "4040",
|
||||
})
|
||||
@@ -821,11 +851,10 @@ class BrightpearlService extends BaseService {
|
||||
.filter((i) => !!i)
|
||||
|
||||
// Orders with a concatenated externalReference are swap orders
|
||||
const [orderId, swapId] = order.externalRef.split(".")
|
||||
const [_, swapId] = order.externalRef.split(".")
|
||||
|
||||
if (swapId) {
|
||||
const order = await this.orderService_.retrieve(orderId)
|
||||
return this.swapService_.createFulfillment(order, swapId, {
|
||||
return this.swapService_.createFulfillment(swapId, {
|
||||
goods_out_note: id,
|
||||
})
|
||||
}
|
||||
@@ -866,6 +895,11 @@ class BrightpearlService extends BaseService {
|
||||
|
||||
return { contactId: customer }
|
||||
}
|
||||
|
||||
bpnum_(number, taxRate = 100) {
|
||||
const bpNumber = number / 100
|
||||
return this.totalsService_.rounded(bpNumber * (taxRate / 100))
|
||||
}
|
||||
}
|
||||
|
||||
export default BrightpearlService
|
||||
|
||||
@@ -3,18 +3,24 @@ class OrderSubscriber {
|
||||
eventBusService,
|
||||
orderService,
|
||||
swapService,
|
||||
returnService,
|
||||
paymentProviderService,
|
||||
brightpearlService,
|
||||
fulfillmentService,
|
||||
}) {
|
||||
this.orderService_ = orderService
|
||||
this.brightpearlService_ = brightpearlService
|
||||
this.swapService_ = swapService
|
||||
this.returnService_ = returnService
|
||||
this.paymentProviderService_ = paymentProviderService
|
||||
this.fulfillmentService_ = fulfillmentService
|
||||
|
||||
eventBusService.subscribe("order.placed", this.sendToBrightpearl)
|
||||
|
||||
eventBusService.subscribe("order.refund_created", this.registerRefund)
|
||||
|
||||
eventBusService.subscribe("order.items_returned", this.registerReturn)
|
||||
|
||||
eventBusService.subscribe("order.placed", this.sendToBrightpearl)
|
||||
|
||||
eventBusService.subscribe(
|
||||
"order.payment_captured",
|
||||
this.registerCapturedPayment
|
||||
@@ -24,50 +30,65 @@ class OrderSubscriber {
|
||||
eventBusService.subscribe("swap.shipment_created", this.registerShipment)
|
||||
|
||||
// Before we initiate a swap we wait for the payment and the return
|
||||
eventBusService.subscribe("swap.payment_completed", this.registerSwap)
|
||||
eventBusService.subscribe(
|
||||
"swap.payment_completed",
|
||||
this.registerSwapPayment
|
||||
)
|
||||
eventBusService.subscribe("order.swap_received", this.registerSwap)
|
||||
}
|
||||
|
||||
sendToBrightpearl = (order) => {
|
||||
return this.brightpearlService_.createSalesOrder(order)
|
||||
sendToBrightpearl = (data) => {
|
||||
return this.brightpearlService_.createSalesOrder(data.id)
|
||||
}
|
||||
|
||||
registerCapturedPayment = (order) => {
|
||||
return this.brightpearlService_.createPayment(order)
|
||||
registerCapturedPayment = ({ id }) => {
|
||||
return this.brightpearlService_.createPayment(id)
|
||||
}
|
||||
|
||||
registerSwapPayment = async (data) => {
|
||||
return this.registerSwap({ id: data.id, swap_id: data.id })
|
||||
}
|
||||
|
||||
registerSwap = async (data) => {
|
||||
const { order, swap, swap_id } = data
|
||||
const { id, swap_id } = data
|
||||
|
||||
if (!order && !swap) {
|
||||
if (!id && !swap_id) {
|
||||
return
|
||||
}
|
||||
|
||||
let fromOrder = order
|
||||
if (!fromOrder) {
|
||||
fromOrder = await this.orderService_.retrieve(swap.order_id)
|
||||
}
|
||||
const fromSwap = await this.swapService_.retrieve(swap_id, {
|
||||
relations: [
|
||||
"order",
|
||||
"order.payments",
|
||||
"order.region",
|
||||
"order.swaps",
|
||||
"order.discounts",
|
||||
"return_order",
|
||||
"return_order.items",
|
||||
"return_order.shipping_method",
|
||||
"additional_items",
|
||||
"shipping_address",
|
||||
"shipping_methods",
|
||||
],
|
||||
})
|
||||
let fromOrder = fromSwap.order
|
||||
|
||||
let fromSwap
|
||||
if (swap) {
|
||||
fromSwap = await this.swapService_.retrieve(swap._id)
|
||||
} else {
|
||||
fromSwap = await this.swapService_.retrieve(swap_id)
|
||||
}
|
||||
|
||||
if (!(fromSwap.is_paid && fromSwap.return.status === "received")) {
|
||||
if (
|
||||
!(
|
||||
fromSwap.confirmed_at !== null &&
|
||||
fromSwap.return_order.status === "received"
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
await this.brightpearlService_.createSwapCredit(fromOrder, fromSwap)
|
||||
await this.brightpearlService_.createSwapOrder(fromOrder, fromSwap)
|
||||
|
||||
const paySwap = await this.swapService_.retrieve(fromSwap._id)
|
||||
await this.brightpearlService_.createSwapPayment(paySwap)
|
||||
}
|
||||
|
||||
registerShipment = async (data) => {
|
||||
const { shipment } = data
|
||||
const { fulfillment_id } = data
|
||||
const shipment = await this.fulfillmentService_.retrieve(fulfillment_id)
|
||||
const noteId = shipment.metadata.goods_out_note
|
||||
if (noteId) {
|
||||
await this.brightpearlService_.registerGoodsOutTrackingNumber(
|
||||
@@ -78,15 +99,28 @@ class OrderSubscriber {
|
||||
}
|
||||
}
|
||||
|
||||
registerReturn = (data) => {
|
||||
const { order, return: fromReturn } = data
|
||||
registerReturn = async (data) => {
|
||||
const { id, return_id } = data
|
||||
|
||||
const order = await this.orderService_.retrieve(id, {
|
||||
relations: ["region", "payments"],
|
||||
})
|
||||
|
||||
const fromReturn = await this.returnService_.retrieve(return_id, {
|
||||
relations: ["items"],
|
||||
})
|
||||
|
||||
return this.brightpearlService_
|
||||
.createSalesCredit(order, fromReturn)
|
||||
.catch((err) => console.log(err))
|
||||
}
|
||||
|
||||
registerRefund = (data) => {
|
||||
const { order, refund } = data
|
||||
registerRefund = async (data) => {
|
||||
const { id, refund_id } = data
|
||||
const order = await this.orderService_.retrieve(id, {
|
||||
relations: ["region", "payments"],
|
||||
})
|
||||
const refund = await this.paymentProviderService_.retrieveRefund(refund_id)
|
||||
return this.brightpearlService_
|
||||
.createRefundCredit(order, refund)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
Reference in New Issue
Block a user