# magendoo/module-base-price

> EU Base Price (Grundpreis) display for Magento 2. Shows price per reference unit (kg, litre, m) on product pages, category listings, search results and cart. Compliant with EU Price Indication Directive 98/6/EC and German PAngV.

`composer require magendoo/module-base-price`

Canonical URL: https://packagento.com/magendoo/module-base-price

## At a glance

- **Vendor**: magendoo (https://packagento.com/magendoo.md)
- **Latest version**: 1.0.0 — released 2026-04-13
- **Pricing**: Free
- **Package type**: Magento 2 module
- **Status**: active, accepting new buyers

## Installation

Packagento is licence-gated, so even free packages need a licence on a project before Composer can resolve them.

1. **Sign in or create an account** at https://packagento.com/customer/account/.

2. **Add the package to your account.** Open https://packagento.com/magendoo/module-base-price and complete the free checkout. A licence is minted automatically.

3. **Create or pick a project, then activate the licence on it.**
   - Projects represent the Magento installs you deploy to. Manage them at https://packagento.com/projects/.
   - Activate the new licence on the project you'll deploy this package to. Activation is what generates the Composer credentials scoped to that project.

4. **Add the project credentials to your Magento codebase.**

   Grab the project's public + private key from https://packagento.com/projects/ (open the project, then its Credentials tab), and add them to `auth.json`:

   ```json
   {
     "http-basic": {
       "packagento.com": {
         "username": "ppk_live_...",
         "password": "psk_live_..."
       }
     }
   }
   ```

   Add the Packagento Composer repository to `composer.json`:

   ```json
   {
     "repositories": [
       { "type": "composer", "url": "https://packagento.com" }
     ]
   }
   ```

5. **Install and apply.**

   ```bash
   composer require magendoo/module-base-price:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

EU Base Price (Grundpreis) display for Magento 2. Shows price per reference unit (kg, litre, m) on product pages, category listings, search results and cart. Compliant with EU Price Indication Directive 98/6/EC and German PAngV.

## README

Displays a per-unit reference price (**Grundpreis**) next to every product's selling price across product pages, category listings, search results, and the shopping cart.

A customer buying a 300 g shampoo at €4.99 also sees **"Base price: €16.63 / 1 kilogram"**, enabling direct price comparison across different pack sizes and brands.

---

### Legal background

Displaying a unit reference price is **legally required** in several jurisdictions:

- **Germany** — Preisangabenverordnung (PAngV §4)
- **EU member states** — Price Indication Directive 98/6/EC, updated by Directive 2019/2161 (Omnibus)

The obligation applies to products sold by weight, volume, length, area, or piece count that are offered in different pack sizes. Consult your legal adviser to determine your specific requirements.

---

### Requirements

| Dependency | Version |
|------------|---------|
| Magento Open Source / Adobe Commerce | 2.4.x |
| PHP | 8.1 or higher |

---

### Installation

#### Via Composer (recommended)

```bash
composer require magendoo/module-base-price
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
```

#### Manual

```bash
mkdir -p app/code/Magendoo/BasePrice
## Copy all module files into that directory
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
```

`setup:upgrade` creates the `magendoo_baseprice_unit` table, adds four EAV product attributes, and seeds nine SI measurement units.

---

### Configuration

Navigate to **Stores → Configuration → Magendoo Extensions → Base Price**.

#### General

| Field | Default | Description |
|-------|---------|-------------|
| Enable Base Price | Yes | Master switch. Disabling this hides base prices everywhere. |

#### Product Page

| Field | Default | Description |
|-------|---------|-------------|
| Enable on Product Pages | Yes | Show base price on individual product pages. |
| Display Template | `Base price: {{unit_price}} / {{reference_amount}} {{reference_unit}}` | Output format. Supports all template variables. |
| CSS Class | `base-price` | Class applied to the wrapping `<div>`. |

#### Category & Search

| Field | Default | Description |
|-------|---------|-------------|
| Enable on Category Pages | Yes | Show base price on category listing pages. |
| Category Display Template | `({{unit_price}} / {{reference_amount}} {{reference_unit}})` | Output format for listing cards. |
| Enable on Search Results | Yes | Show base price on catalogsearch result pages. |

#### Cart

| Field | Default | Description |
|-------|---------|-------------|
| Enable on Cart Page | Yes | Show base price in the shopping cart item rows. |
| Cart Display Template | `Base price: {{unit_price}} / {{reference_amount}} {{reference_unit}}` | Output format for cart rows. |
| Enable on Mini-Cart | Yes | Reserved for future Knockout.js integration. |

---

### Template variables

All display templates accept the following placeholders:

| Variable | Description | Example output |
|----------|-------------|----------------|
| `{{unit_price}}` | Formatted price per reference unit | €16.63 |
| `{{reference_amount}}` | Reference quantity | 1 |
| `{{reference_unit}}` | Reference unit label | kilogram |
| `{{product_amount}}` | Numeric amount in the product | 300 |
| `{{measure_unit}}` | Name of the product's measurement unit | gram |
| `{{product_price}}` | Selling price formatted via store currency | €4.99 |

Unknown placeholders are left intact, so you can safely mix in static text.

---

### Formula

```
base_price = (selling_price ÷ product_amount) × (reference_amount × rate)
```

Where **rate** is the conversion factor from the product unit to the reference unit (e.g. 1 000 for gram → kilogram).

**Examples:**

| Product | Price | Amount | Unit | Calculation | Base price |
|---------|-------|--------|------|-------------|------------|
| Shampoo | €4.99 | 300 g | gram | (4.99 ÷ 300) × (1 × 1 000) | €16.63 / kg |
| Wine | €9.99 | 0.75 l | litre | (9.99 ÷ 0.75) × (1 × 1) | €13.32 / litre |
| Ribbon | €5.00 | 200 cm | centimetre | (5.00 ÷ 200) × (1 × 100) | €2.50 / metre |
| 6-pack | €5.94 | 6 | piece | (5.94 ÷ 6) × (1 × 1) | €0.99 / piece |

The result is rounded to 4 decimal places before formatting.

#### Reference amount override

A product can override the unit's default reference amount. Set **Reference Amount** to `0.1` on a gram-unit product to show the price per 100 g instead of per kilogram:

```
(4.99 ÷ 300) × (0.1 × 1 000) = €1.66 / 100 g
```

---

### Unit management

Navigate to **Catalog → Base Price Units** in the admin panel.

Nine SI units are pre-installed:

| ID | Unit | Reference unit | Rate |
|----|------|----------------|------|
| 1 | gram | kilogram | 1 000 |
| 2 | milligram | kilogram | 1 000 000 |
| 3 | kilogram | kilogram | 1 |
| 4 | millilitre | litre | 1 000 |
| 5 | centilitre | litre | 100 |
| 6 | litre | litre | 1 |
| 7 | centimetre | metre | 100 |
| 8 | metre | metre | 1 |
| 9 | piece | piece | 1 |

#### Adding a custom unit

Click **Add New Unit** and fill in:

| Field | Description | Example |
|-------|-------------|---------|
| Name | Display name of the product unit | fluid ounce |
| Reference Unit Label | The reference unit shown in the output | litre |
| Rate | Multiplier to convert to the reference unit | 33.814 |
| Reference Amount | Default quantity shown in the output | 1 |
| Position | Sort order in the admin grid | 100 |
| Status | Active / Inactive | Active |

---

### Configuring products

#### Admin UI

Open any product in the admin and locate the **Base Price** panel (below the standard price fields):

_(README truncated for .md surface. Full README on https://packagento.com/magendoo/module-base-price.)_

## Changelog

All notable changes to this project will be documented in this file.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### [Unreleased]

### [1.0.0] - 2026-04-13

#### Added
- Base price calculation and display on product detail pages, category listing pages, search result pages, and the shopping cart
- Formula: `(selling_price ÷ product_amount) × (reference_amount × rate)`, rounded to 4 decimal places
- Nine pre-installed SI measurement units: gram, milligram, kilogram, millilitre, centilitre, litre, centimetre, metre, piece
- Configurable display templates with six `{{variable}}` placeholders: `unit_price`, `reference_amount`, `reference_unit`, `measure_unit`, `product_amount`, `product_price`
- Admin unit management grid at Catalog → Base Price Units (create, edit, delete, mass-enable/disable)
- Per-product enable/disable toggle and optional reference amount override (e.g. show per 100 g instead of per kg)
- REST API: unit CRUD (`/V1/baseprice/units`), product base price read/write/delete (`/V1/baseprice/products/:sku`), and an anonymous calculator endpoint (`/V1/baseprice/calculate`)
- EAV attributes `baseprice_is_enabled`, `baseprice_product_amount`, `baseprice_unit_id`, `baseprice_reference_amount` with `used_in_product_listing = true` for efficient collection loading
- 32 PHPUnit unit tests covering every calculation combination, reference amount override, edge cases, template rendering, and formatting
- PHPStan level 2 clean

[Unreleased]: https://github.com/magendooro/module-base-price/compare/v1.0.0...HEAD
[1.0.0]: https://github.com/magendooro/module-base-price/releases/tag/v1.0.0

## Recent Versions

| Version | Released |
|---|---|
| 1.0.0 | 2026-04-13 |

## Dependencies

### Require

| Package | Constraint |
|---|---|
| magento/framework | >=102.0.0 |
| magento/module-backend | * |
| magento/module-catalog | * |
| magento/module-config | * |
| magento/module-eav | * |
| magento/module-store | * |
| magento/module-ui | * |
| php | >=8.1 |

### Require (dev)

| Package | Constraint |
|---|---|
| phpstan/phpstan | ^1.10 \|\| ^2.0 |
| phpunit/phpunit | ^10.5 |

## Quality

Latest release (1.0.0) fails the Packagento QA pipeline. Verdicts below are per-cell (Magento line × PHP version) for the matrixed tools, and run-once for the static / security tiers.


### Compatibility

Each Magento line is installed on its supported PHP versions, then the module is built (DI compile + static-content deploy). Cells show passed / failed / untested; staircase gaps render as `–`.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Pass | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | Pass |


### Code Quality

Advisory checks against the module's source. Never affect the Compatibility verdict — a phpcs finding can't make a module incompatible.

#### Static Analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Warning | 89 | 89 warnings (ruleset: Magento2), 7 auto-fixable with phpcbf |
| PHPMD | Warning | 50 | 50 rule violations (UnusedPrivateField:50) |
| Cpd | Pass | 0 |  |
| Composer validate | Info | 8 | valid; 8 advisory notes (composer validate --strict) |

#### PHPStan

Type-checks the module against a real Magento install. Re-runs per Magento + PHP version because resolvable symbols differ between releases.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | 2 | 2 | – | – |
| 2.4.8 | – | 2 | 2 | – |
| 2.4.9 | – | – | 2 | 2 |


### Tests

Unit and integration suites run per Magento + PHP cell. Test failures speak to the module's behaviour, not its compatibility with a line, so they're reported here separately.

#### Unit Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Pass | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | Pass |

#### Integration Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |


### Security

Dependency-advisory audit (composer audit) plus a source malware scan. A malware detection fails the version outright.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| Composer audit | Pass | 0 |  |
| Malware scan | Pass | 0 |  |

## Licence and pricing

Free. A licence is still minted on checkout and bound to your project for Composer access — no payment step.

Refundable within 14 days of first purchase via https://packagento.com/account/refunds/.

## Install via Claude Code or any MCP client

The Packagento MCP server can run the licence + project + Composer steps above in one tool call:

```
purchase_and_install_packages(
  composer_names=["magendoo/module-base-price"],
  project_id="proj_xxx"
)
```

This handles cart, checkout, licence minting, project activation, and writes auth.json credentials. Connect a client with `claude mcp add packagento https://mcp.packagento.com`. Full setup at https://packagento.com/docs/mcp-setup.

## Vendor

magendoo is a Magento 2 vendor on Packagento. See https://packagento.com/magendoo.md for their full catalogue.

