Taxes

Bebat Recupel

Overview

Bebat and Recupel are recycling taxes applicable to electronic products. In our app, we notify users that these taxes are included in the product prices by displaying messages on the following pages:

  • Product Detail Page (PDP)
  • Product Listing Page (PLP)
  • Trolley
  • Checkout

These messages are displayed only in the Belgium (BE) region where these taxes are applicable.

How the Feature Works

The Bebat and Recupel tax values are provided by the product API for products where these taxes apply. On the frontend, we check the API response for the presence of these taxes and display or hide the appropriate messages based on the data provided.

Types of Tax Messages

Three different messages are shown depending on the applicable taxes:

  1. Products with only Bebat tax:
    • Dutch: Bebatbijdrage inbegrepen
  2. Products with only Recupel tax:
    • Dutch: Recupelbijdrage inbegrepen
  3. Products with both taxes (or when the trolley contains products with both Bebat and Recupel taxes):
    • Dutch: Recupel & Bebatbijdrage inbegrepen

Displaying Bebat and Recupel Tax Messages on PDP

When a user clicks on a product, the app fetches product details using the ProductDetailPageBloc class.

Specifically, the _fetchPdpData method is called within the initState function to retrieve product details and update the state.

_state.add(currentState.copyWith(
  product: product,
  variations: variations,
  quantity: product.quantityMinimum,
  productSkuVariants: skuVariants,
));

Once the state is updated, the UI is rendered using a StreamBuilder inside the ProductDetailPage class, which is located in the product_detail_page.dart file.

Within the StreamBuilder, a stateful widget called _ProductSummary is responsible for displaying product name, description, and pricing.

_ProductSummary(
  product: product,
  isOutOfStock: state.isOutOfStock,
),

The _ProductSummary widget includes another widget, ProductSecondaryPrices, which handles pricing and the Bebat/Recupel taxes.

It takes various arguments, including two main values: formattedPrices and rawPrices, which include the Bebat and Recupel taxes.

ProductSecondaryPrices(
  formattedPrices: product.prices.formatted,
  rawPrices: product.prices.raw,
  textStyle: TextStyles.regularBlue2,
  spacing: verticalMargin2,
  exVatMaxLines: 3,
),

Feature Flag Check

The ProductSecondaryPrices widget contains a feature flag, hasBebatRecupelTaxes, which controls whether Bebat and Recupel tax messages should be shown. If this flag is false, no tax message is displayed even if the tax data is present.

if (hasBebatRecupelTaxes) ...[ 
  // Logic to display tax messages
]

If the flag is true, the app determines which taxes are present and displays the appropriate message.

1. Bebat Tax Only:

If the Bebat tax exists (bebatTotal is not null) and Recupel tax is absent (recupelCost is null), the Bebat tax message with its amount is shown:

if (widget.formattedPrices.bebatTotal != null &&
    widget.formattedPrices.recupelCost == null) ...[
  widget.spacing,
  Text(
    '${context.translations.bebatPrice} ${widget.formattedPrices.bebatTotal}',
    textAlign: widget.textAlign ?? TextAlign.start,
  ),
]

2. Recupel Tax Only:

If the Recupel tax exists (recupelCost is not null) and Bebat tax is absent (bebatTotal is null), the Recupel tax message with its amount is displayed:

else if (widget.formattedPrices.recupelCost != null &&
         widget.formattedPrices.bebatTotal == null) ...[
  widget.spacing,
  Text(
    '${context.translations.recupelPrice} ${widget.formattedPrices.recupelCost}',
    textAlign: widget.textAlign ?? TextAlign.start,
  ),
]

3. Both Bebat and Recupel Taxes:

If both taxes are present (bebatTotal and recupelCost are not null), the app will display a combined message with the total of both taxes:

else if (widget.rawPrices?.bebatTotal != null &&
         widget.rawPrices?.recupelCost != null) ...[
  widget.spacing,
  Text(
    '${context.translations.recupelAndBebatPrice} ${formatCurrency(
      (widget.rawPrices!.bebatTotal! + widget.rawPrices!.recupelCost!),
      regionLang: backend.regionRepository.currentRegionLanguage,
    )}',
    textAlign: widget.textAlign ?? TextAlign.start,
  ),
]

Displaying Bebat and Recupel Tax Messages on PLP

When users search for products, the _SliverResultsPages class fetches product data using the bloc.getProductWithStockByIndex method.

This method returns a productWithStock object, which contains product details and available stock. The ProductCard widget displays the product’s information, including any Bebat/Recupel taxes.

ProductCard(
  // Other arguments
  product: productWithStock,
  // Other arguments
)

Within the ProductCard widget, we use the ProductSecondaryPrices widget to display information of bebat/recupel taxes and prices . It work using a similar logic as described in the PDP section above.

ProductSecondaryPrices(
  formattedPrices: _product.prices.formatted,
  rawPrices: _product.prices.raw,
  textStyle: TextStyles.regularBlue1.copyWith(height: 1.0),
  spacing: verticalMargin4,
)

This widget is responsible for managing and showing the appropriate messages based on the taxes that apply to the product.

Displaying Bebat and Recupel Tax Messages on the Trolley Page

Bebat/Recupel Tax Message within Product Card

In the TrolleyPage class, there is a widget called _TrolleyItemsCard. This widget is responsible for showing individual product which is added to trolley. It takes two key arguments:

  • items: A list of TrolleyItem objects (List).
  • headers: A widget that defines the layout of headers, such as TrolleyChannelDelivery and TrolleyChannelCollection.

Inside _TrolleyItemsCard, the items list is iterated using a for loop. For each TrolleyItem, a new TrolleyPageItem widget is added to a Column widget, which displays the items vertically.

Here's a code example illustrating this:

Column(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  mainAxisSize: MainAxisSize.min,
  children: [
    // Other Widgets
    for (final item in items) ...[
      TrolleyPageItem(trolleyItem: item), // Rendering TrolleyPageItem 
      if (item != items.last) const AppDivider(), // Divider between items
    ],
  ],
)

Within each TrolleyPageItem, there is another widget called ProductSecondaryPrices. This widget is used to display both the prices of the products and any applicable Bebat/Recupel taxes.

The ProductSecondaryPrices widget determines if Bebat and Recupel taxes apply to a specific product and, if so, displays the appropriate tax messages.

For a detailed explanation of how ProductSecondaryPrices check bebat/recupel taxes and displays messages, please refer to the Displaying Bebat and Recupel Tax Messages on PDP section.

Bebat/Recupel Tax Message within the Trolley Subtotal Section

In the TrolleyPage class, there is a _TotalsPanel widget responsible for displaying various totals such as product prices, discounts, taxes, and delivery charges.

Within this widget, a TrolleyTotalsPanel widget is used to calculate and display these totals.

The TrolleyTotalsPanel checks if Bebat or Recupel taxes are applicable to the items in the trolley.

If these taxes apply, the relevant tax messages and amounts are displayed using the _RecupelBebatPriceWidget.

Key Logic for Bebat and Recupel Taxes:

Bebat and Recupel Tax Check: In TrolleyTotalsPanel, we checks which taxes (Bebat or Recupel) are applicable by checking their values within the trolley’s totals.

  1. If both Bebat and Recupel taxes are present, a combined message is shown along with the sum of both taxes.
  2. If only the Bebat tax is present, a Bebat message is displayed along with the Bebat tax amount.
  3. If only the Recupel tax is present, a Recupel message is shown along with the Recupel tax.
// Checking if Bebat and Recupel taxes are applicable
if (isRecupelAndBebatPriceAvailable) {
  _RecupelBebatPriceWidget(
    translations: translations.recupelAndBebatPrice,
    price: formatCurrency(
      state.totals.recupel!.incVat.raw + state.totals.bebat!.incVat.raw,
      regionLang: context.currentRegionLanguage,
    ),
  );
} else if (isBebatPriceAvailable) {
  _RecupelBebatPriceWidget(
    translations: translations.bebatPrice,
    price: state.totals.bebat!.incVat.formatted!,
  );
} else if (isRecupelPriceAvailable) {
  _RecupelBebatPriceWidget(
    translations: translations.recupelPrice,
    price: state.totals.recupel!.incVat.formatted!,
  );
}

The widget _RecupelBebatPriceWidget is responsible for rendering the Bebat and Recupel price details. It takes two key arguments:

  • translations: The localized tax message (e.g., Bebat, Recupel, or both).
  • price: The formatted price of the tax being displayed.

This approach allows dynamic handling of different tax scenarios (Bebat only, Recupel only, or both) and ensures that the correct message and amounts are shown in the trolley subtotal section.

Bebat/Recupel Tax Message in the Checkout Page

In the CheckoutPage class, the TrolleyTotalsPanel widget is responsible for calculating and displaying the Bebat and Recupel taxes.

The logic for showing the correct message follows a similar pattern as described in the Trolley Subtotal Section above.

The widget checks Bebat and/or Recupel taxes are applicable and then displays the corresponding messages based on the tax data received.

Conclusion

In summary, the Bebat and Recupel tax messages play a critical role in informing users about recycling taxes that are included in the product prices.

We display these messages across multiple touchpoints within the app, including the Product Detail Page (PDP), Product Listing Page (PLP), Trolley, and Checkout pages.

By leveraging the product API, we ensure that these messages are shown only when applicable, maintaining consistency across regions like Belgium, where these taxes apply.

Furthermore, with the help of feature flags, we have flexibility in toggling these messages for future needs.


Copyright © 2026