Merge pull request #215 from medusajs/fix/zero-decimal-currencies
Fix/zero decimal currencies
This commit is contained in:
13
packages/medusa-core-utils/src/humanize-amount.js
Normal file
13
packages/medusa-core-utils/src/humanize-amount.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import zeroDecimalCurrencies from "./zero-decimal-currencies"
|
||||
|
||||
const humanizeAmount = (amount, currency) => {
|
||||
let divisor = 100
|
||||
|
||||
if (zeroDecimalCurrencies.includes(currency.toLowerCase())) {
|
||||
divisor = 1
|
||||
}
|
||||
|
||||
return amount / divisor
|
||||
}
|
||||
|
||||
export default humanizeAmount
|
||||
@@ -5,3 +5,5 @@ export { default as MedusaError } from "./errors"
|
||||
export { default as getConfigFile } from "./get-config-file"
|
||||
export { default as createRequireFromPath } from "./create-require-from-path"
|
||||
export { default as compareObjectsByProp } from "./compare-objects"
|
||||
export { default as zeroDecimalCurrencies } from "./zero-decimal-currencies"
|
||||
export { default as humanizeAmount } from "./humanize-amount"
|
||||
|
||||
20
packages/medusa-core-utils/src/zero-decimal-currencies.js
Normal file
20
packages/medusa-core-utils/src/zero-decimal-currencies.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const zeroDecimalCurrencies = [
|
||||
"bif",
|
||||
"clp",
|
||||
"djf",
|
||||
"gnf",
|
||||
"jpy",
|
||||
"kmf",
|
||||
"krw",
|
||||
"mga",
|
||||
"pyg",
|
||||
"rwf",
|
||||
"ugx",
|
||||
"vnd",
|
||||
"vuv",
|
||||
"xaf",
|
||||
"xof",
|
||||
"xpf",
|
||||
]
|
||||
|
||||
export default zeroDecimalCurrencies
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { MedusaError, humanizeAmount } from "medusa-core-utils"
|
||||
import { BaseService } from "medusa-interfaces"
|
||||
import Brightpearl from "../utils/brightpearl"
|
||||
|
||||
@@ -290,10 +290,12 @@ class BrightpearlService extends BaseService {
|
||||
taxCode: region.tax_code,
|
||||
net: this.bpnum_(
|
||||
fromRefund.amount,
|
||||
fromOrder.currency_code,
|
||||
10000 / (100 + fromOrder.tax_rate)
|
||||
),
|
||||
tax: this.bpnum_(
|
||||
fromRefund.amount * (1 - 100 / (100 + fromOrder.tax_rate))
|
||||
fromRefund.amount * (1 - 100 / (100 + fromOrder.tax_rate)),
|
||||
fromOrder.currency_code
|
||||
),
|
||||
nominalCode: accountingCode,
|
||||
},
|
||||
@@ -311,7 +313,7 @@ class BrightpearlService extends BaseService {
|
||||
paymentMethodCode: this.options.payment_method_code || "1220",
|
||||
orderId: creditId,
|
||||
currencyIsoCode: fromOrder.currency_code.toUpperCase(),
|
||||
amountPaid: this.bpnum_(fromRefund.amount),
|
||||
amountPaid: this.bpnum_(fromRefund.amount, fromOrder.currency_code),
|
||||
paymentDate: new Date(),
|
||||
paymentType,
|
||||
}
|
||||
@@ -380,8 +382,15 @@ class BrightpearlService extends BaseService {
|
||||
name: "Difference",
|
||||
quantity: 1,
|
||||
taxCode: region.tax_code,
|
||||
net: this.bpnum_(difference, 10000 / (100 + fromOrder.tax_rate)),
|
||||
tax: this.bpnum_(difference * (1 - 100 / (100 + fromOrder.tax_rate))),
|
||||
net: this.bpnum_(
|
||||
difference,
|
||||
fromOrder.currency_code,
|
||||
10000 / (100 + fromOrder.tax_rate)
|
||||
),
|
||||
tax: this.bpnum_(
|
||||
difference * (1 - 100 / (100 + fromOrder.tax_rate)),
|
||||
fromOrder.currency_code
|
||||
),
|
||||
nominalCode: this.options.sales_account_code || "4000",
|
||||
})
|
||||
}
|
||||
@@ -397,7 +406,10 @@ class BrightpearlService extends BaseService {
|
||||
paymentMethodCode: this.options.payment_method_code || "1220",
|
||||
orderId: creditId,
|
||||
currencyIsoCode: fromOrder.currency_code.toUpperCase(),
|
||||
amountPaid: this.bpnum_(fromReturn.refund_amount),
|
||||
amountPaid: this.bpnum_(
|
||||
fromReturn.refund_amount,
|
||||
fromOrder.currencyCode
|
||||
),
|
||||
paymentDate: new Date(),
|
||||
paymentType,
|
||||
}
|
||||
@@ -640,10 +652,12 @@ class BrightpearlService extends BaseService {
|
||||
name: `#${fromOrder.display_id}: Claim ${fromClaim.id}`,
|
||||
net: this.bpnum_(
|
||||
fromClaim.refund_amount,
|
||||
fromOrder.currency_code,
|
||||
10000 / (100 + fromOrder.tax_rate)
|
||||
),
|
||||
tax: this.bpnum_(
|
||||
fromClaim.refund_amount * (1 - 100 / (100 + fromOrder.tax_rate))
|
||||
fromClaim.refund_amount * (1 - 100 / (100 + fromOrder.tax_rate)),
|
||||
fromOrder.currency_code
|
||||
),
|
||||
taxCode: region.tax_code,
|
||||
nominalCode: this.options.sales_account_code || `4000`,
|
||||
@@ -663,7 +677,10 @@ class BrightpearlService extends BaseService {
|
||||
paymentMethodCode: this.options.payment_method_code || "1220",
|
||||
orderId: creditId,
|
||||
currencyIsoCode: fromOrder.currency_code.toUpperCase(),
|
||||
amountPaid: this.bpnum_(fromClaim.refund_amount),
|
||||
amountPaid: this.bpnum_(
|
||||
fromClaim.refund_amount,
|
||||
fromOrder.currency_code
|
||||
),
|
||||
paymentDate: new Date(),
|
||||
paymentType,
|
||||
}
|
||||
@@ -775,7 +792,7 @@ class BrightpearlService extends BaseService {
|
||||
orderId: soId,
|
||||
paymentDate: new Date(),
|
||||
currencyIsoCode: fromOrder.currency_code.toUpperCase(),
|
||||
amountPaid: this.bpnum_(fromOrder.total),
|
||||
amountPaid: this.bpnum_(fromOrder.total, fromOrder.currency_code),
|
||||
paymentType,
|
||||
}
|
||||
|
||||
@@ -811,9 +828,13 @@ class BrightpearlService extends BaseService {
|
||||
}
|
||||
|
||||
if (config.include_price) {
|
||||
row.net = this.bpnum_(item.unit_price * item.quantity - ld.amount)
|
||||
row.net = this.bpnum_(
|
||||
item.unit_price * item.quantity - ld.amount,
|
||||
fromOrder.currency_code
|
||||
)
|
||||
row.tax = this.bpnum_(
|
||||
item.unit_price * item.quantity - ld.amount,
|
||||
fromOrder.currency_code,
|
||||
fromOrder.tax_rate
|
||||
)
|
||||
} else if (config.is_claim) {
|
||||
@@ -821,7 +842,11 @@ class BrightpearlService extends BaseService {
|
||||
bpProduct.productId,
|
||||
this.options.cost_price_list || `1`
|
||||
)
|
||||
row.tax = this.bpnum_(row.net * 100, fromOrder.tax_rate)
|
||||
row.tax = this.bpnum_(
|
||||
row.net * 100,
|
||||
fromOrder.currency_code,
|
||||
fromOrder.tax_rate
|
||||
)
|
||||
}
|
||||
|
||||
row.quantity = item.quantity
|
||||
@@ -847,8 +872,12 @@ class BrightpearlService extends BaseService {
|
||||
if (gcTotal) {
|
||||
lines.push({
|
||||
name: `Gift Card`,
|
||||
net: this.bpnum_(-1 * gcTotal),
|
||||
tax: this.bpnum_(-1 * gcTotal, fromOrder.tax_rate),
|
||||
net: this.bpnum_(-1 * gcTotal, fromOrder.currency_code),
|
||||
tax: this.bpnum_(
|
||||
-1 * gcTotal,
|
||||
fromOrder.currency_code,
|
||||
fromOrder.tax_rate
|
||||
),
|
||||
quantity: 1,
|
||||
taxCode: region.tax_code,
|
||||
nominalCode: this.options.gift_card_account_code || "4000",
|
||||
@@ -863,8 +892,12 @@ class BrightpearlService extends BaseService {
|
||||
lines.push({
|
||||
name: `Shipping: ${shippingMethods.map((m) => m.name).join(" + ")}`,
|
||||
quantity: 1,
|
||||
net: this.bpnum_(shippingTotal),
|
||||
tax: this.bpnum_(shippingTotal, fromOrder.tax_rate),
|
||||
net: this.bpnum_(shippingTotal, fromOrder.currency_code),
|
||||
tax: this.bpnum_(
|
||||
shippingTotal,
|
||||
fromOrder.currency_code,
|
||||
fromOrder.tax_rate
|
||||
),
|
||||
taxCode: region.tax_code,
|
||||
nominalCode: this.options.shipping_account_code || "4040",
|
||||
})
|
||||
@@ -1103,8 +1136,8 @@ class BrightpearlService extends BaseService {
|
||||
)
|
||||
}
|
||||
|
||||
bpnum_(number, taxRate = 100) {
|
||||
const bpNumber = number / 100
|
||||
bpnum_(number, currency, taxRate = 100) {
|
||||
const bpNumber = humanizeAmount(number, currency)
|
||||
return this.bpround_(bpNumber * (taxRate / 100))
|
||||
}
|
||||
}
|
||||
|
||||
188
packages/medusa-plugin-segment/src/services/__tests__/segment.js
Normal file
188
packages/medusa-plugin-segment/src/services/__tests__/segment.js
Normal file
@@ -0,0 +1,188 @@
|
||||
import SegmentService from "../segment"
|
||||
|
||||
jest.mock("analytics-node")
|
||||
|
||||
const orderFactory = (config = {}) => {
|
||||
return {
|
||||
id: "12355",
|
||||
display_id: "1234",
|
||||
cart_id: "cart_13",
|
||||
region_id: "reg_123",
|
||||
items: [
|
||||
{
|
||||
title: "Test",
|
||||
variant: {
|
||||
product_id: "prod_123",
|
||||
sku: "TEST",
|
||||
},
|
||||
unit_price: 1100,
|
||||
quantity: 2,
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
name: "standard",
|
||||
price: 12399,
|
||||
},
|
||||
],
|
||||
payments: [
|
||||
{
|
||||
id: "123",
|
||||
},
|
||||
],
|
||||
tax_rate: 23.1,
|
||||
currency_code: "DKK",
|
||||
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",
|
||||
subtotal: 2200,
|
||||
total: 12399,
|
||||
tax_total: 0,
|
||||
shipping_total: 12399,
|
||||
discount_total: 0,
|
||||
gift_card_total: 0,
|
||||
...config,
|
||||
}
|
||||
}
|
||||
|
||||
describe("SegmentService", () => {
|
||||
const ProductService = {
|
||||
retrieve: () =>
|
||||
Promise.resolve({
|
||||
collection: { title: "Collection" },
|
||||
type: { value: "Type" },
|
||||
subtitle: "Subtitle",
|
||||
}),
|
||||
}
|
||||
|
||||
const TotalsService = {
|
||||
getLineItemRefund: (_, item) => {
|
||||
return item.unit_price
|
||||
},
|
||||
}
|
||||
|
||||
describe("buildOrder", () => {
|
||||
const segmentService = new SegmentService(
|
||||
{
|
||||
productService: ProductService,
|
||||
totalsService: TotalsService,
|
||||
},
|
||||
{ account: "test" }
|
||||
)
|
||||
|
||||
segmentService.getReportingValue = async (_, v) => {
|
||||
const num = v
|
||||
return Promise.resolve(Number(Math.round(num + "e2") + "e-2"))
|
||||
}
|
||||
|
||||
it("successfully builds sales order", async () => {
|
||||
jest.clearAllMocks()
|
||||
|
||||
const order = orderFactory()
|
||||
const segmentOrder = await segmentService.buildOrder(order)
|
||||
|
||||
expect(segmentOrder).toEqual({
|
||||
checkout_id: "cart_13",
|
||||
coupon: undefined,
|
||||
currency: "DKK",
|
||||
discount: 0,
|
||||
email: "test@example.com",
|
||||
order_id: "12355",
|
||||
payment_provider: "",
|
||||
products: [
|
||||
{
|
||||
category: "Collection",
|
||||
name: "Test",
|
||||
price: 4.47,
|
||||
product_id: "prod_123",
|
||||
quantity: 2,
|
||||
reporting_revenue: 8.94,
|
||||
sku: "",
|
||||
subtitle: "Subtitle",
|
||||
type: "Type",
|
||||
variant: "TEST",
|
||||
},
|
||||
],
|
||||
region_id: "reg_123",
|
||||
reporting_discount: 0,
|
||||
reporting_revenue: 123.99,
|
||||
reporting_shipping: 123.99,
|
||||
reporting_subtotal: 22,
|
||||
reporting_tax: 0,
|
||||
reporting_total: 123.99,
|
||||
revenue: 123.99,
|
||||
shipping: 123.99,
|
||||
shipping_city: undefined,
|
||||
shipping_country: "DK",
|
||||
shipping_methods: [
|
||||
{
|
||||
name: "standard",
|
||||
price: 12399,
|
||||
},
|
||||
],
|
||||
subtotal: 22,
|
||||
tax: 0,
|
||||
total: 123.99,
|
||||
})
|
||||
})
|
||||
|
||||
it("successfully builds order with zero decimal currency", async () => {
|
||||
jest.clearAllMocks()
|
||||
|
||||
const order = orderFactory({ currency_code: "krw" })
|
||||
const segmentOrder = await segmentService.buildOrder(order)
|
||||
|
||||
expect(segmentOrder).toEqual({
|
||||
checkout_id: "cart_13",
|
||||
coupon: undefined,
|
||||
currency: "KRW",
|
||||
discount: 0,
|
||||
email: "test@example.com",
|
||||
order_id: "12355",
|
||||
payment_provider: "",
|
||||
products: [
|
||||
{
|
||||
category: "Collection",
|
||||
name: "Test",
|
||||
price: 446.79,
|
||||
product_id: "prod_123",
|
||||
quantity: 2,
|
||||
reporting_revenue: 893.58,
|
||||
sku: "",
|
||||
subtitle: "Subtitle",
|
||||
type: "Type",
|
||||
variant: "TEST",
|
||||
},
|
||||
],
|
||||
region_id: "reg_123",
|
||||
reporting_discount: 0,
|
||||
reporting_revenue: 12399,
|
||||
reporting_shipping: 12399,
|
||||
reporting_subtotal: 2200,
|
||||
reporting_tax: 0,
|
||||
reporting_total: 12399,
|
||||
revenue: 12399,
|
||||
shipping: 12399,
|
||||
shipping_city: undefined,
|
||||
shipping_country: "DK",
|
||||
shipping_methods: [
|
||||
{
|
||||
name: "standard",
|
||||
price: 12399,
|
||||
},
|
||||
],
|
||||
subtotal: 2200,
|
||||
tax: 0,
|
||||
total: 12399,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,7 @@
|
||||
import Analytics from "analytics-node"
|
||||
import axios from "axios"
|
||||
import { BaseService } from "medusa-interfaces"
|
||||
import { humanizeAmount } from "medusa-core-utils"
|
||||
|
||||
class SegmentService extends BaseService {
|
||||
/**
|
||||
@@ -43,7 +44,7 @@ class SegmentService extends BaseService {
|
||||
"EUR"
|
||||
|
||||
if (fromCurrency === toCurrency) {
|
||||
return this.totalsService_.rounded(value)
|
||||
return this.rounded_(value)
|
||||
}
|
||||
|
||||
const exchangeRate = await axios
|
||||
@@ -54,15 +55,17 @@ class SegmentService extends BaseService {
|
||||
return data.rates[fromCurrency]
|
||||
})
|
||||
|
||||
return this.totalsService_.rounded(value / exchangeRate)
|
||||
return this.rounded_(value / exchangeRate)
|
||||
}
|
||||
|
||||
async buildOrder(order) {
|
||||
const subtotal = order.subtotal / 100
|
||||
const total = order.total / 100
|
||||
const tax = order.tax_total / 100
|
||||
const discount = order.discount_total / 100
|
||||
const shipping = order.shipping_total / 100
|
||||
const curr = order.currency_code
|
||||
|
||||
const subtotal = humanizeAmount(order.subtotal, curr)
|
||||
const total = humanizeAmount(order.total, curr)
|
||||
const tax = humanizeAmount(order.tax_total, curr)
|
||||
const discount = humanizeAmount(order.discount_total, curr)
|
||||
const shipping = humanizeAmount(order.shipping_total, curr)
|
||||
const revenue = total - tax
|
||||
|
||||
let coupon
|
||||
@@ -119,7 +122,7 @@ class SegmentService extends BaseService {
|
||||
|
||||
const revenue = await this.getReportingValue(
|
||||
order.currency_code,
|
||||
lineTotal / 100
|
||||
humanizeAmount(lineTotal, curr)
|
||||
)
|
||||
|
||||
let sku = ""
|
||||
@@ -141,7 +144,9 @@ class SegmentService extends BaseService {
|
||||
return {
|
||||
name,
|
||||
variant,
|
||||
price: lineTotal / 100 / item.quantity,
|
||||
price: this.rounded_(
|
||||
humanizeAmount(lineTotal, curr) / item.quantity
|
||||
),
|
||||
reporting_revenue: revenue,
|
||||
product_id: item.variant.product_id,
|
||||
category: product.collection?.title,
|
||||
@@ -156,6 +161,10 @@ class SegmentService extends BaseService {
|
||||
|
||||
return orderData
|
||||
}
|
||||
|
||||
rounded_(v) {
|
||||
return Number(Math.round(v + "e2") + "e-2")
|
||||
}
|
||||
}
|
||||
|
||||
export default SegmentService
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { NotificationService } from "medusa-interfaces"
|
||||
import SendGrid from "@sendgrid/mail"
|
||||
|
||||
import { NotificationService } from "medusa-interfaces"
|
||||
import { humanizeAmount, zeroDecimalCurrencies } from "medusa-core-utils"
|
||||
|
||||
class SendGridService extends NotificationService {
|
||||
static identifier = "sendgrid"
|
||||
|
||||
@@ -361,18 +363,24 @@ class SendGridService extends NotificationService {
|
||||
date: order.created_at.toDateString(),
|
||||
items,
|
||||
discounts,
|
||||
subtotal: `${this.humanPrice_(subtotal * (1 + taxRate))} ${currencyCode}`,
|
||||
gift_card_total: `${this.humanPrice_(
|
||||
gift_card_total * (1 + taxRate)
|
||||
subtotal: `${this.humanPrice_(
|
||||
subtotal * (1 + taxRate),
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
tax_total: `${this.humanPrice_(tax_total)} ${currencyCode}`,
|
||||
gift_card_total: `${this.humanPrice_(
|
||||
gift_card_total * (1 + taxRate),
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
tax_total: `${this.humanPrice_(tax_total, currencyCode)} ${currencyCode}`,
|
||||
discount_total: `${this.humanPrice_(
|
||||
discount_total * (1 + taxRate)
|
||||
discount_total * (1 + taxRate),
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
shipping_total: `${this.humanPrice_(
|
||||
shipping_total * (1 + taxRate)
|
||||
shipping_total * (1 + taxRate),
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
total: `${this.humanPrice_(total)} ${currencyCode}`,
|
||||
total: `${this.humanPrice_(total, currencyCode)} ${currencyCode}`,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,15 +458,23 @@ class SendGridService extends NotificationService {
|
||||
has_shipping: !!returnRequest.shipping_method,
|
||||
email: order.email,
|
||||
items: this.processItems_(returnItems, taxRate, currencyCode),
|
||||
subtotal: `${this.humanPrice_(item_subtotal)} ${currencyCode}`,
|
||||
shipping_total: `${this.humanPrice_(shippingTotal)} ${currencyCode}`,
|
||||
subtotal: `${this.humanPrice_(
|
||||
item_subtotal,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
shipping_total: `${this.humanPrice_(
|
||||
shippingTotal,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
refund_amount: `${this.humanPrice_(
|
||||
returnRequest.refund_amount
|
||||
returnRequest.refund_amount,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
return_request: {
|
||||
...returnRequest,
|
||||
refund_amount: `${this.humanPrice_(
|
||||
returnRequest.refund_amount
|
||||
returnRequest.refund_amount,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
},
|
||||
order,
|
||||
@@ -539,9 +555,18 @@ class SendGridService extends NotificationService {
|
||||
email: order.email,
|
||||
items: this.processItems_(swap.additional_items, taxRate, currencyCode),
|
||||
return_items: returnItems,
|
||||
return_total: `${this.humanPrice_(returnTotal)} ${currencyCode}`,
|
||||
refund_amount: `${this.humanPrice_(refundAmount)} ${currencyCode}`,
|
||||
additional_total: `${this.humanPrice_(additionalTotal)} ${currencyCode}`,
|
||||
return_total: `${this.humanPrice_(
|
||||
returnTotal,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
refund_amount: `${this.humanPrice_(
|
||||
refundAmount,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
additional_total: `${this.humanPrice_(
|
||||
additionalTotal,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,12 +627,25 @@ class SendGridService extends NotificationService {
|
||||
date: swap.updated_at.toDateString(),
|
||||
email: order.email,
|
||||
tax_amount: `${this.humanPrice_(
|
||||
swap.difference_due * taxRate
|
||||
swap.difference_due * taxRate,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
paid_total: `${this.humanPrice_(
|
||||
swap.difference_due,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
return_total: `${this.humanPrice_(
|
||||
returnTotal,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
refund_amount: `${this.humanPrice_(
|
||||
refundAmount,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
additional_total: `${this.humanPrice_(
|
||||
additionalTotal,
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
paid_total: `${this.humanPrice_(swap.difference_due)} ${currencyCode}`,
|
||||
return_total: `${this.humanPrice_(returnTotal)} ${currencyCode}`,
|
||||
refund_amount: `${this.humanPrice_(refundAmount)} ${currencyCode}`,
|
||||
additional_total: `${this.humanPrice_(additionalTotal)} ${currencyCode}`,
|
||||
fulfillment: shipment,
|
||||
tracking_links: shipment.tracking_links,
|
||||
tracking_number: shipment.tracking_numbers.join(", "),
|
||||
@@ -647,14 +685,20 @@ class SendGridService extends NotificationService {
|
||||
...i,
|
||||
thumbnail: this.normalizeThumbUrl_(i.thumbnail),
|
||||
price: `${this.humanPrice_(
|
||||
i.unit_price * (1 + taxRate)
|
||||
i.unit_price * (1 + taxRate),
|
||||
currencyCode
|
||||
)} ${currencyCode}`,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
humanPrice_(amount) {
|
||||
return amount ? (amount / 100).toFixed(2) : "0.00"
|
||||
humanPrice_(amount, currency) {
|
||||
if (!amount) {
|
||||
return "0.00"
|
||||
}
|
||||
|
||||
const normalized = humanizeAmount(amount, currency)
|
||||
return normalized.toFixed(zeroDecimalCurrencies.includes(currency.toLowerCase()) ? 0 : 2)
|
||||
}
|
||||
|
||||
normalizeThumbUrl_(url) {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import axios from "axios"
|
||||
import { zeroDecimalCurrencies, humanizeAmount } from "medusa-core-utils"
|
||||
import { BaseService } from "medusa-interfaces"
|
||||
|
||||
class SlackService extends BaseService {
|
||||
/**
|
||||
* @param {Object} options - options defined in `medusa-config.js`
|
||||
* {
|
||||
* show_discount_code: If set to true the discount code used will be
|
||||
* displayed in the order channel.
|
||||
* slack_url: "https://hooks.slack.com/services/...",
|
||||
* admin_orders_url: "https:..../orders"
|
||||
* }
|
||||
@@ -58,6 +61,14 @@ class SlackService extends BaseService {
|
||||
const currencyCode = order.currency_code.toUpperCase()
|
||||
const taxRate = order.tax_rate / 100
|
||||
|
||||
const getDisplayAmount = (amount) => {
|
||||
const humanAmount = humanizeAmount(amount, currencyCode)
|
||||
if (zeroDecimalCurrencies.includes(currencyCode.toLowerCase())) {
|
||||
return humanAmount
|
||||
}
|
||||
return humanAmount.toFixed(2)
|
||||
}
|
||||
|
||||
let blocks = [
|
||||
{
|
||||
type: "section",
|
||||
@@ -83,32 +94,46 @@ class SlackService extends BaseService {
|
||||
type: "section",
|
||||
text: {
|
||||
type: "mrkdwn",
|
||||
text: `*Subtotal*\t${(subtotal / 100).toFixed(
|
||||
2
|
||||
)} ${currencyCode}\n*Shipping*\t${(shipping_total / 100).toFixed(
|
||||
2
|
||||
)} ${currencyCode}\n*Discount Total*\t${(
|
||||
discount_total / 100
|
||||
).toFixed(2)} ${currencyCode}\n*Tax*\t${(tax_total / 100).toFixed(
|
||||
2
|
||||
)} ${currencyCode}\n*Total*\t${(total / 100).toFixed(
|
||||
2
|
||||
text: `*Subtotal*\t${getDisplayAmount(
|
||||
subtotal
|
||||
)} ${currencyCode}\n*Shipping*\t${getDisplayAmount(
|
||||
shipping_total
|
||||
)} ${currencyCode}\n*Discount Total*\t${getDisplayAmount(
|
||||
discount_total
|
||||
)} ${currencyCode}\n*Tax*\t${getDisplayAmount(
|
||||
tax_total
|
||||
)} ${currencyCode}\n*Total*\t${getDisplayAmount(
|
||||
total
|
||||
)} ${currencyCode}`,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
order.discounts.forEach((d) => {
|
||||
if (order.gift_card_total) {
|
||||
blocks.push({
|
||||
type: "section",
|
||||
text: {
|
||||
type: "mrkdwn",
|
||||
text: `*Promo Code*\t${d.code} ${d.rule.value}${
|
||||
d.rule.type === "percentage" ? "%" : ` ${currencyCode}`
|
||||
}`,
|
||||
text: `*Gift Card Total*\t${getDisplayAmount(
|
||||
order.gift_card_total
|
||||
)} ${currencyCode}`,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (this.options_.show_discount_code) {
|
||||
order.discounts.forEach((d) => {
|
||||
blocks.push({
|
||||
type: "section",
|
||||
text: {
|
||||
type: "mrkdwn",
|
||||
text: `*Promo Code*\t${d.code} ${d.rule.value}${
|
||||
d.rule.type === "percentage" ? "%" : ` ${currencyCode}`
|
||||
}`,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
blocks.push({
|
||||
type: "divider",
|
||||
@@ -119,19 +144,15 @@ class SlackService extends BaseService {
|
||||
type: "section",
|
||||
text: {
|
||||
type: "mrkdwn",
|
||||
text: `*${lineItem.title}*\n${lineItem.quantity} x ${(
|
||||
(lineItem.unit_price / 100) *
|
||||
(1 + taxRate)
|
||||
).toFixed(2)} ${currencyCode}`,
|
||||
text: `*${lineItem.title}*\n${lineItem.quantity} x ${getDisplayAmount(
|
||||
lineItem.unit_price * (1 + taxRate)
|
||||
)} ${currencyCode}`,
|
||||
},
|
||||
}
|
||||
|
||||
if (lineItem.thumbnail) {
|
||||
let url = lineItem.thumbnail
|
||||
if (
|
||||
!lineItem.thumbnail.startsWith("http:") &&
|
||||
!lineItem.thumbnail.startsWith("https:")
|
||||
) {
|
||||
if (lineItem.thumbnail.startsWith("//")) {
|
||||
url = `https:${lineItem.thumbnail}`
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user