Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/add-fixed-product-taxes-package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@graphcommerce/magento-fixed-product-taxes': minor
---

Add `@graphcommerce/magento-fixed-product-taxes` — a new package that renders
Magento's Fixed Product Taxes (FPT / WEEE / GreenTax) on product pages and
inside cart items. The store-config display setting drives the behaviour:
nothing is rendered when FPT is disabled or set to "without details"; per-tax
labels and amounts are shown for the "with details" modes; an extra "Final
price" line is appended when the price excludes FPT. Activate via
`PRIVATE_ADDITIONAL_DEPENDENCIES`.
24 changes: 24 additions & 0 deletions packages/magento-fixed-product-taxes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# @graphcommerce/magento-fixed-product-taxes

Renders Magento's **Fixed Product Taxes** (FPT, also known as WEEE / GreenTax)
on product pages and inside cart items.

## Activate

Add to `PRIVATE_ADDITIONAL_DEPENDENCIES` in `.env`:

```bash
PRIVATE_ADDITIONAL_DEPENDENCIES="@graphcommerce/magento-fixed-product-taxes"
```

## Behaviour

Display is driven by Magento's `StoreConfig.product_fixed_product_tax_display_setting`:

| Setting | Effect |
| -------------------------------------- | ---------------------------------------------------------------------------- |
| `FPT_DISABLED` | No FPT rendering. |
| `INCLUDE_FPT_WITHOUT_DETAILS` | Tax is already in the price; nothing extra is rendered. |
| `INCLUDE_FPT_WITH_DETAILS` | Show each FPT label + amount next to the price. |
| `EXCLUDE_FPT_WITHOUT_DETAILS` | Price excludes FPT; nothing extra is rendered. |
| `EXCLUDE_FPT_AND_INCLUDE_WITH_DETAILS` | Price excludes FPT and the FPT lines are rendered. A final price is shown. |
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fragment FixedProductTax on FixedProductTax {
amount {
...Money
}
label
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fragment CartItem_FixedProductTaxes on CartItemInterface @inject(into: ["CartItem"]) {
prices {
fixed_product_taxes {
amount {
...Money
}
label
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fragment ProductPrice_FixedProductTaxes on ProductPrice @inject(into: ["ProductPrice"]) {
fixed_product_taxes {
amount {
...Money
}
label
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fragment StoreConfigFragment_FixedProductTaxes on StoreConfig @inject(into: ["StoreConfigFragment"]) {
product_fixed_product_tax_display_setting
category_fixed_product_tax_display_setting
sales_fixed_product_tax_display_setting
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useQuery } from '@graphcommerce/graphql'
import { StoreConfigDocument } from '@graphcommerce/magento-store'

export type FptDisplaySetting =
| 'FPT_DISABLED'
| 'INCLUDE_FPT_WITHOUT_DETAILS'
| 'INCLUDE_FPT_WITH_DETAILS'
| 'EXCLUDE_FPT_WITHOUT_DETAILS'
| 'EXCLUDE_FPT_AND_INCLUDE_WITH_DETAILS'

export function useFixedProductTaxes() {
const displaySetting = (useQuery(StoreConfigDocument).data?.storeConfig
?.product_fixed_product_tax_display_setting ?? 'FPT_DISABLED') as FptDisplaySetting

const subtractValue =
displaySetting === 'EXCLUDE_FPT_AND_INCLUDE_WITH_DETAILS' ||
displaySetting === 'EXCLUDE_FPT_WITHOUT_DETAILS'
const showDetails =
displaySetting === 'INCLUDE_FPT_WITH_DETAILS' ||
displaySetting === 'EXCLUDE_FPT_AND_INCLUDE_WITH_DETAILS'
const showFinalPrice = displaySetting === 'EXCLUDE_FPT_AND_INCLUDE_WITH_DETAILS'

return {
displaySetting,
subtractValue,
showDetails,
showFinalPrice,
}
}
1 change: 1 addition & 0 deletions packages/magento-fixed-product-taxes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './hooks/useFixedProductTaxes'
4 changes: 4 additions & 0 deletions packages/magento-fixed-product-taxes/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />
/// <reference types="@graphcommerce/next-ui/types" />
38 changes: 38 additions & 0 deletions packages/magento-fixed-product-taxes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@graphcommerce/magento-fixed-product-taxes",
"homepage": "https://www.graphcommerce.org/",
"repository": "github:graphcommerce-org/graphcommerce",
"version": "10.1.0-canary.16",
"sideEffects": false,
"prettier": "@graphcommerce/prettier-config-pwa",
"eslintConfig": {
"extends": "@graphcommerce/eslint-config-pwa",
"parserOptions": {
"project": "./tsconfig.json"
}
},
"peerDependencies": {
"@graphcommerce/eslint-config-pwa": "^10.1.0-canary.16",
"@graphcommerce/graphql": "^10.1.0-canary.16",
"@graphcommerce/magento-cart": "^10.1.0-canary.16",
"@graphcommerce/magento-cart-items": "^10.1.0-canary.16",
"@graphcommerce/magento-product": "^10.1.0-canary.16",
"@graphcommerce/magento-store": "^10.1.0-canary.16",
"@graphcommerce/next-config": "^10.1.0-canary.16",
"@graphcommerce/next-ui": "^10.1.0-canary.16",
"@graphcommerce/prettier-config-pwa": "^10.1.0-canary.16",
"@graphcommerce/typescript-config-pwa": "^10.1.0-canary.16",
"@lingui/core": "^5",
"@lingui/macro": "^5",
"@lingui/react": "^5",
"@mui/material": "^7.0.0",
"next": "*",
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"exports": {
".": "./index.ts",
"./plugins/FixedProductTaxesProductPagePrice": "./plugins/FixedProductTaxesProductPagePrice.tsx",
"./plugins/FixedProductTaxesCartItem": "./plugins/FixedProductTaxesCartItem.tsx"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { CartItemActionCardProps } from '@graphcommerce/magento-cart-items'
import { Money } from '@graphcommerce/magento-store'
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
import { filterNonNullableKeys } from '@graphcommerce/next-ui'
import { Box } from '@mui/material'
import { useFixedProductTaxes } from '../hooks/useFixedProductTaxes'

export const config: PluginConfig = {
type: 'component',
module: '@graphcommerce/magento-cart-items',
}

export function CartItemActionCard(props: PluginProps<CartItemActionCardProps>) {
const { Prev, cartItem, ...rest } = props
const { showDetails } = useFixedProductTaxes()

const taxes = filterNonNullableKeys(cartItem.prices?.fixed_product_taxes, ['amount']).filter(
(tax) => tax.amount.value && tax.amount.value > 0,
)

if (!showDetails || taxes.length === 0) {
return <Prev cartItem={cartItem} {...rest} />
}

return (
<Prev
cartItem={cartItem}
{...rest}
details={
<>
{rest.details}
<Box sx={{ typography: 'caption', color: 'text.secondary' }}>
{taxes.map((tax) => (
<Box key={tax.label ?? tax.amount.value} sx={{ display: 'flex', gap: 0.5 }}>
<span>{tax.label}</span>
<Money {...tax.amount} />
</Box>
))}
</Box>
</>
}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { ProductPagePriceProps } from '@graphcommerce/magento-product'
import { Money } from '@graphcommerce/magento-store'
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
import { filterNonNullableKeys, ListFormat } from '@graphcommerce/next-ui'
import { Box } from '@mui/material'
import { Trans } from '@lingui/react/macro'
import React from 'react'
import { useFixedProductTaxes } from '../hooks/useFixedProductTaxes'

export const config: PluginConfig = {
type: 'component',
module: '@graphcommerce/magento-product',
}

export function ProductPagePrice(props: PluginProps<ProductPagePriceProps>) {
const { Prev, product, ...rest } = props
const { displaySetting, showDetails, showFinalPrice } = useFixedProductTaxes()

const taxes = filterNonNullableKeys(
product.price_range.minimum_price.fixed_product_taxes,
['amount'],
).filter((tax) => tax.amount.value && tax.amount.value > 0)

if (taxes.length === 0 || displaySetting === 'FPT_DISABLED' || !showDetails) {
return <Prev product={product} {...rest} />
}

const totalFpt = taxes.reduce((sum, tax) => sum + (tax.amount.value ?? 0), 0)
const basePrice = product.price_range.minimum_price.final_price
const finalPriceValue = (basePrice.value ?? 0) + (showFinalPrice ? totalFpt : 0)

return (
<>
<Prev product={product} {...rest} />
<Box sx={{ typography: 'body2', mt: 0.5, color: 'text.secondary' }}>
<ListFormat listStyle='long'>
{taxes.map((tax) => (
<React.Fragment key={tax.label ?? tax.amount.value}>
{tax.label} <Money {...tax.amount} />
</React.Fragment>
))}
</ListFormat>
</Box>
{showFinalPrice && (
<Box sx={{ typography: 'body2', fontWeight: 'bold', mt: 0.5 }}>
<Trans>Final price</Trans>{' '}
<Money currency={basePrice.currency} value={finalPriceValue} />
</Box>
)}
</>
)
}
5 changes: 5 additions & 0 deletions packages/magento-fixed-product-taxes/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"exclude": ["**/node_modules", "**/.*/"],
"include": ["**/*.ts", "**/*.tsx"],
"extends": "@graphcommerce/typescript-config-pwa/nextjs.json"
}
Loading