Merge branch 'master' of https://github.com/medusajs/medusa
This commit is contained in:
commit
564b30ebbc
11 files changed
+273
-36
No files matched your search
+1
-1
@@ -4,5 +4,5 @@
|
|||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
"version": "1.0.0-y.18"
|
"version": "1.0.0-y.24"
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "medusa-plugin-brightpearl",
|
"name": "medusa-plugin-brightpearl",
|
||||||
"version": "1.0.0-alpha.33",
|
"version": "1.0.0-y.23",
|
||||||
"description": "Brightpearl plugin for Medusa Commerce",
|
"description": "Brightpearl plugin for Medusa Commerce",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import bodyParser from "body-parser"
|
import bodyParser from "body-parser"
|
||||||
|
|
||||||
|
const BP_SECRET_TOKEN = process.env.BP_SECRET_TOKEN || ""
|
||||||
|
|
||||||
export default (container) => {
|
export default (container) => {
|
||||||
const app = Router()
|
const app = Router()
|
||||||
|
|
||||||
@@ -40,5 +42,35 @@ export default (container) => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
app.post("/brightpearl/orders/:id", async (req, res) => {
|
||||||
|
const { access_token } = req.query
|
||||||
|
const { id } = req.params
|
||||||
|
|
||||||
|
if (
|
||||||
|
!access_token ||
|
||||||
|
!id ||
|
||||||
|
!BP_SECRET_TOKEN ||
|
||||||
|
access_token !== BP_SECRET_TOKEN
|
||||||
|
) {
|
||||||
|
res.sendStatus(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const brightpearlService = req.scope.resolve("brightpearlService")
|
||||||
|
const orderService = req.scope.resolve("orderService")
|
||||||
|
|
||||||
|
try {
|
||||||
|
const order = await orderService.retrieve(id)
|
||||||
|
if (order.metadata && order.metadata.brightpearl_sales_order_id) {
|
||||||
|
throw new Error("Already sent to BP")
|
||||||
|
}
|
||||||
|
|
||||||
|
await brightpearlService.createSalesOrder(order)
|
||||||
|
res.sendStatus(200)
|
||||||
|
} catch (err) {
|
||||||
|
res.status(400).json(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
import BrightpearlService from "../brightpearl"
|
||||||
|
import Brightpearl, { mockCreateOrder } from "../../utils/brightpearl"
|
||||||
|
|
||||||
|
jest.mock("../../utils/brightpearl")
|
||||||
|
|
||||||
|
const OrderService = {
|
||||||
|
setMetadata: () => {
|
||||||
|
return Promise.resolve()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const TotalsService = {
|
||||||
|
getTotal: () => {
|
||||||
|
return Promise.resolve(123)
|
||||||
|
},
|
||||||
|
getLineDiscounts: () => {
|
||||||
|
return Promise.resolve([])
|
||||||
|
},
|
||||||
|
getShippingTotal: () => {
|
||||||
|
return 123.9999929393293
|
||||||
|
},
|
||||||
|
rounded: (value) => {
|
||||||
|
const decimalPlaces = 4
|
||||||
|
return Number(
|
||||||
|
Math.round(parseFloat(value + "e" + decimalPlaces)) + "e-" + decimalPlaces
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const OAuthService = {
|
||||||
|
retrieveByName: () => {
|
||||||
|
return Promise.resolve({
|
||||||
|
data: {
|
||||||
|
access_token: "12345",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const RegionService = {
|
||||||
|
retrieve: () => {
|
||||||
|
return Promise.resolve({
|
||||||
|
tax_code: "1234",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
totalsService: TotalsService,
|
||||||
|
oauthService: OAuthService,
|
||||||
|
regionService: RegionService,
|
||||||
|
},
|
||||||
|
{ account: "test" }
|
||||||
|
)
|
||||||
|
|
||||||
|
it("successfully builds sales order", async () => {
|
||||||
|
await bpService.createSalesOrder(order)
|
||||||
|
|
||||||
|
expect(mockCreateOrder).toHaveBeenCalledWith({
|
||||||
|
currency: { code: "DKK" },
|
||||||
|
ref: "1234",
|
||||||
|
externalRef: "12355",
|
||||||
|
channelId: "1",
|
||||||
|
installedIntegrationInstanceId: undefined,
|
||||||
|
statusId: "3",
|
||||||
|
customer: {
|
||||||
|
id: "12345",
|
||||||
|
address: {
|
||||||
|
addressFullName: "Test Testson",
|
||||||
|
addressLine1: "Test",
|
||||||
|
addressLine2: "TEst",
|
||||||
|
postalCode: "1234",
|
||||||
|
countryIsoCode: "DK",
|
||||||
|
telephone: "12345678",
|
||||||
|
email: "test@example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delivery: {
|
||||||
|
shippingMethodId: 0,
|
||||||
|
address: {
|
||||||
|
addressFullName: "Test Testson",
|
||||||
|
addressLine1: "Test",
|
||||||
|
addressLine2: "TEst",
|
||||||
|
postalCode: "1234",
|
||||||
|
countryIsoCode: "DK",
|
||||||
|
telephone: "12345678",
|
||||||
|
email: "test@example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
name: "Test",
|
||||||
|
net: 22,
|
||||||
|
tax: 5.082,
|
||||||
|
quantity: 2,
|
||||||
|
taxCode: "1234",
|
||||||
|
externalRef: undefined,
|
||||||
|
nominalCode: "4000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Shipping: standard",
|
||||||
|
quantity: 1,
|
||||||
|
net: 124,
|
||||||
|
tax: 28.644,
|
||||||
|
taxCode: "1234",
|
||||||
|
nominalCode: "4040",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -279,9 +279,12 @@ class BrightpearlService extends BaseService {
|
|||||||
name: `${fromRefund.reason}: ${fromRefund.note}`,
|
name: `${fromRefund.reason}: ${fromRefund.note}`,
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
taxCode: region.tax_code,
|
taxCode: region.tax_code,
|
||||||
net: fromRefund.amount / (1 + fromOrder.tax_rate),
|
net: this.totalsService_.rounded(
|
||||||
tax:
|
fromRefund.amount / (1 + fromOrder.tax_rate)
|
||||||
fromRefund.amount - fromRefund.amount / (1 + fromOrder.tax_rate),
|
),
|
||||||
|
tax: this.totalsService_.rounded(
|
||||||
|
fromRefund.amount - fromRefund.amount / (1 + fromOrder.tax_rate)
|
||||||
|
),
|
||||||
nominalCode: accountingCode,
|
nominalCode: accountingCode,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -339,8 +342,12 @@ class BrightpearlService extends BaseService {
|
|||||||
return row.externalRef === i.item_id
|
return row.externalRef === i.item_id
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
net: (parentRow.net / parentRow.quantity) * i.quantity,
|
net: this.totalsService_.rounded(
|
||||||
tax: (parentRow.tax / parentRow.quantity) * i.quantity,
|
(parentRow.net / parentRow.quantity) * i.quantity
|
||||||
|
),
|
||||||
|
tax: this.totalsService_.rounded(
|
||||||
|
(parentRow.tax / parentRow.quantity) * i.quantity
|
||||||
|
),
|
||||||
productId: parentRow.productId,
|
productId: parentRow.productId,
|
||||||
taxCode: parentRow.taxCode,
|
taxCode: parentRow.taxCode,
|
||||||
externalRef: parentRow.externalRef,
|
externalRef: parentRow.externalRef,
|
||||||
@@ -360,8 +367,12 @@ class BrightpearlService extends BaseService {
|
|||||||
name: "Difference",
|
name: "Difference",
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
taxCode: region.tax_code,
|
taxCode: region.tax_code,
|
||||||
net: difference / (1 + fromOrder.tax_rate),
|
net: this.totalsService_.rounded(
|
||||||
tax: difference - difference / (1 + fromOrder.tax_rate),
|
difference / (1 + fromOrder.tax_rate)
|
||||||
|
),
|
||||||
|
tax: this.totalsService_.rounded(
|
||||||
|
difference - difference / (1 + fromOrder.tax_rate)
|
||||||
|
),
|
||||||
nominalCode: this.options.sales_account_code || "4000",
|
nominalCode: this.options.sales_account_code || "4000",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -543,8 +554,10 @@ class BrightpearlService extends BaseService {
|
|||||||
} else {
|
} else {
|
||||||
row.name = item.title
|
row.name = item.title
|
||||||
}
|
}
|
||||||
row.net = item.content.unit_price * item.quantity - discount.amount
|
row.net = this.totalsService_.rounded(
|
||||||
row.tax = row.net * fromOrder.tax_rate
|
item.content.unit_price * item.quantity - discount.amount
|
||||||
|
)
|
||||||
|
row.tax = this.totalsService_.rounded(row.net * fromOrder.tax_rate)
|
||||||
row.quantity = item.quantity
|
row.quantity = item.quantity
|
||||||
row.taxCode = region.tax_code
|
row.taxCode = region.tax_code
|
||||||
row.externalRef = item._id
|
row.externalRef = item._id
|
||||||
@@ -560,8 +573,8 @@ class BrightpearlService extends BaseService {
|
|||||||
lines.push({
|
lines.push({
|
||||||
name: `Shipping: ${shippingMethods.map((m) => m.name).join(" + ")}`,
|
name: `Shipping: ${shippingMethods.map((m) => m.name).join(" + ")}`,
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
net: shippingTotal,
|
net: this.totalsService_.rounded(shippingTotal),
|
||||||
tax: shippingTotal * fromOrder.tax_rate,
|
tax: this.totalsService_.rounded(shippingTotal * fromOrder.tax_rate),
|
||||||
taxCode: region.tax_code,
|
taxCode: region.tax_code,
|
||||||
nominalCode: this.options.shipping_account_code || "4040",
|
nominalCode: this.options.shipping_account_code || "4040",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ class BrightpearlOauth extends OauthService {
|
|||||||
const client_id = "medusa-dev"
|
const client_id = "medusa-dev"
|
||||||
const client_secret = CLIENT_SECRET
|
const client_secret = CLIENT_SECRET
|
||||||
const state = randomize("A0", 16)
|
const state = randomize("A0", 16)
|
||||||
const redirect =
|
const redirect = "https://tekla.medusa-commerce.com/a/oauth/brightpearl"
|
||||||
"https://tekla-staging-admin.medusa-commerce.com/a/oauth/brightpearl"
|
|
||||||
return {
|
return {
|
||||||
application_name: "brightpearl",
|
application_name: "brightpearl",
|
||||||
display_name: "Brightpearl",
|
display_name: "Brightpearl",
|
||||||
@@ -40,8 +39,7 @@ class BrightpearlOauth extends OauthService {
|
|||||||
const params = {
|
const params = {
|
||||||
client_id: "medusa-dev",
|
client_id: "medusa-dev",
|
||||||
client_secret: CLIENT_SECRET,
|
client_secret: CLIENT_SECRET,
|
||||||
redirect:
|
redirect: "https://tekla.medusa-commerce.com/a/oauth/brightpearl",
|
||||||
"https://tekla-staging-admin.medusa-commerce.com/a/oauth/brightpearl",
|
|
||||||
code,
|
code,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const mockCreateOrder = jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValue(Promise.resolve("1234"))
|
||||||
|
|
||||||
|
const mock = jest.fn().mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
warehouses: {
|
||||||
|
createReservation: jest.fn().mockReturnValue(Promise.resolve()),
|
||||||
|
},
|
||||||
|
payments: {
|
||||||
|
create: jest.fn().mockReturnValue(Promise.resolve()),
|
||||||
|
},
|
||||||
|
orders: {
|
||||||
|
create: mockCreateOrder,
|
||||||
|
retrieve: jest.fn().mockReturnValue(Promise.resolve()),
|
||||||
|
},
|
||||||
|
products: {
|
||||||
|
retrieveBySKU: jest.fn().mockReturnValue(
|
||||||
|
Promise.resolve({
|
||||||
|
productId: 1234,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
},
|
||||||
|
customers: {
|
||||||
|
retrieveByEmail: jest.fn().mockReturnValue(
|
||||||
|
Promise.resolve([
|
||||||
|
{
|
||||||
|
primaryEmail: "test@example.com",
|
||||||
|
contactId: "12345",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default mock
|
||||||
@@ -93,7 +93,6 @@ class BrightpearlClient {
|
|||||||
|
|
||||||
this.client_.interceptors.response.use(undefined, async (error) => {
|
this.client_.interceptors.response.use(undefined, async (error) => {
|
||||||
const response = error.response
|
const response = error.response
|
||||||
console.log(response.data && response.data.errors)
|
|
||||||
|
|
||||||
if (response) {
|
if (response) {
|
||||||
if (
|
if (
|
||||||
@@ -104,7 +103,6 @@ class BrightpearlClient {
|
|||||||
try {
|
try {
|
||||||
await onRefresh(this)
|
await onRefresh(this)
|
||||||
} catch (authError) {
|
} catch (authError) {
|
||||||
console.log(authError)
|
|
||||||
// refreshing has failed, but report the original error, i.e. 401
|
// refreshing has failed, but report the original error, i.e. 401
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,47 +355,44 @@ var BrightpearlClient = /*#__PURE__*/function () {
|
|||||||
switch (_context.prev = _context.next) {
|
switch (_context.prev = _context.next) {
|
||||||
case 0:
|
case 0:
|
||||||
response = error.response;
|
response = error.response;
|
||||||
console.log(response.data && response.data.errors);
|
|
||||||
|
|
||||||
if (!response) {
|
if (!response) {
|
||||||
_context.next = 15;
|
_context.next = 13;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(response.status === 401 && error.config && !error.config.__isRetryRequest)) {
|
if (!(response.status === 401 && error.config && !error.config.__isRetryRequest)) {
|
||||||
_context.next = 15;
|
_context.next = 13;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.prev = 4;
|
_context.prev = 3;
|
||||||
_context.next = 7;
|
_context.next = 6;
|
||||||
return onRefresh(_this2);
|
return onRefresh(_this2);
|
||||||
|
|
||||||
case 7:
|
case 6:
|
||||||
_context.next = 13;
|
_context.next = 11;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 9:
|
case 8:
|
||||||
_context.prev = 9;
|
_context.prev = 8;
|
||||||
_context.t0 = _context["catch"](4);
|
_context.t0 = _context["catch"](3);
|
||||||
console.log(_context.t0); // refreshing has failed, but report the original error, i.e. 401
|
|
||||||
|
|
||||||
return _context.abrupt("return", Promise.reject(error));
|
return _context.abrupt("return", Promise.reject(error));
|
||||||
|
|
||||||
case 13:
|
case 11:
|
||||||
// retry the original request
|
// retry the original request
|
||||||
error.config.__isRetryRequest = true;
|
error.config.__isRetryRequest = true;
|
||||||
return _context.abrupt("return", _this2.client_(error.config));
|
return _context.abrupt("return", _this2.client_(error.config));
|
||||||
|
|
||||||
case 15:
|
case 13:
|
||||||
return _context.abrupt("return", Promise.reject(error));
|
return _context.abrupt("return", Promise.reject(error));
|
||||||
|
|
||||||
case 16:
|
case 14:
|
||||||
case "end":
|
case "end":
|
||||||
return _context.stop();
|
return _context.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, _callee, null, [[4, 9]]);
|
}, _callee, null, [[3, 8]]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return function (_x) {
|
return function (_x) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "medusa-plugin-ip-lookup",
|
"name": "medusa-plugin-ip-lookup",
|
||||||
"version": "1.0.0-alpha.26",
|
"version": "1.0.0-y.24",
|
||||||
"description": "IP lookup middleware for Medusa core",
|
"description": "IP lookup middleware for Medusa core",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -11,8 +11,12 @@ export default {
|
|||||||
|
|
||||||
const ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress
|
const ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress
|
||||||
|
|
||||||
|
console.log(ip)
|
||||||
|
|
||||||
const { data } = await ipLookupService.lookupIp(ip)
|
const { data } = await ipLookupService.lookupIp(ip)
|
||||||
|
|
||||||
|
console.log(data)
|
||||||
|
|
||||||
if (!data.country_code) {
|
if (!data.country_code) {
|
||||||
next()
|
next()
|
||||||
return
|
return
|
||||||
@@ -23,6 +27,8 @@ export default {
|
|||||||
countries: data.country_code,
|
countries: data.country_code,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(regions)
|
||||||
|
|
||||||
// If this region exists, add it to the body of the cart creation request
|
// If this region exists, add it to the body of the cart creation request
|
||||||
if (regions[0]) {
|
if (regions[0]) {
|
||||||
req.body.region_id = regions[0]._id.toString()
|
req.body.region_id = regions[0]._id.toString()
|
||||||
@@ -30,6 +36,7 @@ export default {
|
|||||||
|
|
||||||
next()
|
next()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in new issue
Block a user