Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dashboard) taxes + discount breakdown #9586

Merged
merged 11 commits into from
Oct 18, 2024
11 changes: 10 additions & 1 deletion packages/admin/dashboard/src/i18n/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,16 @@
"allocateItems": "Allocate items",
"editOrder": "Edit order",
"editOrderContinue": "Continue order edit",
"inventoryKit": "Consists of {{count}}x inventory items"
"inventoryKit": "Consists of {{count}}x inventory items",
"itemTotal": "Item Total",
"shippingTotal": "Shipping Total",
"discountTotal": "Discount Total",
"taxTotalIncl": "Tax Total (included)",
"itemSubtotal": "Item Subtotal",
"shippingSubtotal": "Shipping Subtotal",
"discountSubtotal": "Discount Subtotal",
"taxTotal": "Tax Total"

},
"payment": {
"title": "Payments",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
AdminOrder,
AdminOrderLineItem,
AdminOrderPreview,
AdminRegion,
AdminReturn,
} from "@medusajs/types"
import {
Expand All @@ -31,6 +32,7 @@ import {
toast,
Tooltip,
usePrompt,
clx,
} from "@medusajs/ui"

import { AdminPaymentCollection } from "../../../../../../../../core/types/dist/http/payment/admin/entities"
Expand Down Expand Up @@ -528,9 +530,9 @@ const Cost = ({
secondaryValue,
tooltip,
}: {
label: string
label: ReactNode
value: string | number
secondaryValue: string
secondaryValue?: string
tooltip?: ReactNode
}) => (
<div className="grid grid-cols-3 items-center">
Expand All @@ -550,45 +552,191 @@ const Cost = ({
</div>
)

const CostBreakdown = ({ order }: { order: AdminOrder }) => {
const CostBreakdown = ({
order,
}: {
order: AdminOrder & { region: AdminRegion }
}) => {
const { t } = useTranslation()
const [isTaxOpen, setIsTaxOpen] = useState(false)
const [isShippingOpen, setIsShippingOpen] = useState(false)

const discountCodes = useMemo(() => {
const codes = new Set()
order.items.forEach((item) =>
item.adjustments?.forEach((adj) => {
codes.add(adj.code)
})
)

return Array.from(codes).sort()
}, [order])

const taxCodes = useMemo(() => {
const taxCodeMap = {}

order.items.forEach((item) => {
item.tax_lines?.forEach((line) => {
taxCodeMap[line.code] = (taxCodeMap[line.code] || 0) + line.total
})
})

order.shipping_methods.forEach((sm) => {
sm.tax_lines?.forEach((line) => {
taxCodeMap[line.code] = (taxCodeMap[line.code] || 0) + line.total
})
})

return taxCodeMap
}, [order])

const automaticTaxesOn = !!order.region!.automatic_taxes
const hasTaxLines = !!Object.keys(taxCodes).length

const discountTotal = automaticTaxesOn
? order.discount_total
: order.discount_subtotal

return (
<div className="text-ui-fg-subtle flex flex-col gap-y-2 px-6 py-4">
<Cost
label={t("fields.discount")}
// TODO: DISCOUNTS -> moved to line items now
// secondaryValue={
// order.discounts.length > 0
// ? order.discounts.map((d) => d.code).join(", ")
// : "-"
// }
label={t(
automaticTaxesOn
? "orders.summary.itemTotal"
: "orders.summary.itemSubtotal"
)}
value={getLocaleAmount(order.item_total, order.currency_code)}
/>
<Cost
label={
<div
onClick={() => setIsShippingOpen((o) => !o)}
className="flex cursor-pointer items-center gap-1"
>
<span>
{t(
automaticTaxesOn
? "orders.summary.shippingTotal"
: "orders.summary.shippingSubtotal"
)}
</span>
<TriangleDownMini
style={{
transform: `rotate(${isShippingOpen ? 0 : -90}deg)`,
}}
/>
</div>
}
value={getLocaleAmount(
automaticTaxesOn ? order.shipping_total : order.shipping_subtotal,
order.currency_code
)}
/>

{isShippingOpen && (
<div className="flex flex-col gap-1 pl-5">
{(order.shipping_methods || [])
.sort((m1, m2) =>
(m1.created_at as string).localeCompare(m2.created_at as string)
)
.map((sm, i) => {
return (
<div
key={sm.id}
className="flex items-center justify-between gap-x-2"
>
<div>
<span className="txt-small text-ui-fg-subtle font-medium">
{sm.name}
{sm.detail.return_id &&
` (${t("fields.returnShipping")})`}{" "}
<ShippingInfoPopover key={i} shippingMethod={sm} />
</span>
</div>
<div className="relative flex-1">
<div className="bottom-[calc(50% - 2px)] absolute h-[1px] w-full border-b border-dashed" />
</div>
<span className="txt-small text-ui-fg-muted">
{getLocaleAmount(
automaticTaxesOn ? sm.total : sm.subtotal,
order.currency_code
)}
</span>
</div>
)
})}
</div>
)}

<Cost
label={t(
automaticTaxesOn
? "orders.summary.discountTotal"
: "orders.summary.discountSubtotal"
)}
secondaryValue={discountCodes.join(", ")}
value={
order.discount_total > 0
? `- ${getLocaleAmount(order.discount_total, order.currency_code)}`
discountTotal > 0
? `- ${getLocaleAmount(discountTotal, order.currency_code)}`
: "-"
}
/>
{(order.shipping_methods || [])
.sort((m1, m2) =>
(m1.created_at as string).localeCompare(m2.created_at as string)
)
.map((sm, i) => {
return (
<div key={sm.id}>
<Cost
label={
sm.detail.return_id
? t("fields.returnShipping")
: t("fields.outboundShipping")
}
secondaryValue={sm.name}
value={getLocaleAmount(sm.total, order.currency_code)}
tooltip={<ShippingInfoPopover key={i} shippingMethod={sm} />}

<>
<div className="flex justify-between">
<div
onClick={() => hasTaxLines && setIsTaxOpen((o) => !o)}
className={clx("flex items-center gap-1", {
"cursor-pointer": hasTaxLines,
})}
>
<span className="txt-small select-none">
{t(
automaticTaxesOn
? "orders.summary.taxTotalIncl"
: "orders.summary.taxTotal"
)}
</span>
{hasTaxLines && (
<TriangleDownMini
style={{
transform: `rotate(${isTaxOpen ? 0 : -90}deg)`,
}}
/>
</div>
)
})}
)}
</div>

<div className="text-right">
<Text size="small" leading="compact">
{getLocaleAmount(order.tax_total, order.currency_code)}
</Text>
</div>
</div>
{isTaxOpen && (
<div className="flex flex-col gap-1 pl-5">
{Object.entries(taxCodes).map(([code, total]) => {
return (
<div
key={code}
className="flex items-center justify-between gap-x-2"
>
<div>
<span className="txt-small text-ui-fg-subtle font-medium">
{code}
</span>
</div>
<div className="relative flex-1">
<div className="bottom-[calc(50% - 2px)] absolute h-[1px] w-full border-b border-dashed" />
</div>
<span className="txt-small text-ui-fg-muted">
{getLocaleAmount(total, order.currency_code)}
</span>
</div>
)
})}
</div>
)}
</>
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ const DEFAULT_PROPERTIES = [
"currency_code",
// --- TOTALS ---
"total",
"item_total",
"shipping_subtotal",
"subtotal",
"discounts_total",
"discount_total",
"discount_subtotal",
"shipping_total",
"shipping_tax_total",
"tax_total",
Expand Down Expand Up @@ -40,6 +43,7 @@ const DEFAULT_RELATIONS = [
"*payment_collections.payments",
"*payment_collections.payments.refunds",
"*payment_collections.payments.refunds.refund_reason",
"region.automatic_taxes",
]

export const DEFAULT_FIELDS = `${DEFAULT_PROPERTIES.join(
Expand Down
Loading