# Product Rental — Complete Guide

> Overview The Product Rental module (dfproductrental) adds a rental mode you enable product by product on your PrestaShop shop, then covers the whole fleet operation. On a rentable product's page,…

- Page: <https://www.datafirefly.com/en/documentation/dfproductrental/>
- Language: en
- Last updated: 2026-09-22
- Other languages: [fr](https://www.datafirefly.com/documentation/dfproductrental/index.md), [es](https://www.datafirefly.com/es/documentation/dfproductrental/index.md), [de](https://www.datafirefly.com/de/documentation/dfproductrental/index.md), [it](https://www.datafirefly.com/it/documentation/dfproductrental/index.md), [pl](https://www.datafirefly.com/pl/documentation/dfproductrental/index.md), [pt](https://www.datafirefly.com/pt/documentation/dfproductrental/index.md), [nl](https://www.datafirefly.com/nl/documentation/dfproductrental/index.md)
- Index: <https://www.datafirefly.com/en/documentation/llms.txt>

## Overview

The **Product Rental** module (`dfproductrental`) adds a **rental mode** you enable product by product on your PrestaShop shop, then covers the whole fleet operation. On a rentable product's page, the customer picks dates in a calendar that greys out booked days, as a **range**, as **two fields with times** or as a **start date plus a number of weeks**. Pricing works per day through **degressive tiers**, a **percentage of the sale price** or **duration coefficients**, modulated by **seasonal pricing** and **fixed packages**. The **deposit** lives on a dedicated cart line, refundable by credit slip, or switches to a **Stripe card imprint**. Back-office side: monthly **planning**, **units with serial numbers**, **check-in and check-out** with condition reports and withholding, **statistics**, **payment-free requests**, **synced packs**, **REST API**, **outgoing webhooks** and cron **reminder emails**.

Ideal for equipment, furniture, event gear, instruments, vehicles or tools: anything that is rented rather than sold once and for all. The rental mode only activates on the products you designate, without denaturing the rest of your catalog.

## Compatibility

- PrestaShop 8.0 to 9.x
- PHP 7.4 to 8.3
- Single store and multistore
- 5 languages: FR, EN, ES, DE, IT (calendar also translated in NL, PT and PL)
- Classic theme and custom themes
- No dependency: no Composer, manual PSR-4 autoloader, flatpickr calendar embedded locally

## Installation

1. In the back office, open **Modules > Module Manager**.
2. Click **Upload a module** and select the `dfproductrental.zip` file.
3. Once installed, click **Configure**.

At install time, the module creates its five tables (`df_rental_product`, `df_rental_tier`, `df_rental_booking`, `df_rental_unit`, `df_rental_unit_assign`), registers its hooks, initialises its settings and adds five entries under **Catalog > Rental**: **Rental products**, **Bookings**, **Planning**, **Units** and **Statistics**. Upgrading from any previous version is handled by tolerant upgrade scripts: just upload the new ZIP over the old one, then clear the PrestaShop cache.

## General settings

The module's configuration page gathers the global options.

- **Buffer delay (days)**: days blocked after each return to prepare the item. Global value, overridable per product.
- **Booking horizon (days)**: how far in the future customers can book (365 by default).
- **Pending cart expiry (minutes)**: past this delay, an unconfirmed booking releases its dates (60 by default).
- **Charge the deposit**: enables the deposit cart line; when disabled, the deposit is shown without being cashed (imprint mode).
- **Charge the return day**: yes, calendar counting, the return day is a rental day (14th to 20th = 7 days); no, rotation model, the return happens the day after the billed period (14th to 21st = 7 days, one week runs Monday to Monday), that day staying unavailable for another handover.
- **Weekly closing days**: days on which no handover or return can happen (0 = Sunday to 6 = Saturday, comma separated). A rental can span a closed day.
- **Closing dates**: one date per line, as YYYY-MM-DD (one-off) or MM-DD (recurring every year, e.g. 12-25).
- **Seasonal pricing**: one season per line, `start|end|multiplier|label` (see below).
- **Automatic reminder emails** and **days in advance**: reminders before start and before return, overdue follow-up, triggered by the cron URL shown under the form.
- **Outgoing webhooks** and **webhook URL**: notify your software on every booking event (see below).
- **Deposit via Stripe imprint**, **publishable key**, **secret key**, **mandatory imprint before handover** and **consent text**: see the Deposit section.
- **Date selection**, **cart-wide dates**, **cart-only date selection**, **pickup and return times**, **block position**, **native buy button hiding**.
- **Deposit mode** (per product, automatic global, disabled), **whole catalog as rentals**, **coefficient grid**, **pack sync**, **request expiry**, **API**.

## Configuring a rentable product

Go to **Catalog > Rental > Rental products**, then **Add**: product, activation, pricing mode (fixed amounts, percentage of sale price or coefficient), base daily price, deposit, minimum and maximum duration, available units, buffer delay, payment-free request and stock blocking by requests.

### Degressive pricing tiers

Each tier is defined by a **minimum day**, a **maximum day** and a **daily price**. The module applies the tier whose range contains the chosen duration; a maximum day of 0 means unlimited; without a matching tier, the base price applies. Example: 39/day for 1 to 3 days, 32/day for 4 to 7 days, 26/day from 8 days.

### Fixed packages

Below the tiers, the **Fixed packages** area accepts one package per line as `days|price excl. tax|label`, for instance `7|199|Week package`. When the chosen duration matches exactly, this round price replaces the whole calculation: no tiers, no coefficients, no seasons. Combined with the weeks date mode, it makes the offer perfectly readable.

### Percentage mode

The base daily price, deposit and tiers are expressed as a **percentage of the product's sale price excluding tax**. A product sold at 1000 with a deposit of 10 requires a 100 deposit. Amounts automatically follow your catalog prices.

## Shop-side usage

### Choosing dates

Three selection modes, set globally: a single range on a two-month calendar, two start and end fields (with optional pickup and return times), or a **start date plus a number of weeks**, with the return date and total price computing automatically. Booked days are greyed out; closing days can be neither handover nor return. Cart-wide dates apply a single period to the whole order, editable from the cart.

### Price and booking

A recap details the number of days, the applied daily price, the rental total, the deposit and the grand total. The booking button adds the rental to the cart: the rental price is injected through a cart-scoped specific price, the product's catalog price staying untouched, and the deposit, if any, shows on its own line. A pending booking blocks the dates; unconfirmed carts expire and release their dates; order validation confirms the booking.

## Deposit: dedicated line or Stripe imprint

### Charged deposit

When **Charge the deposit** is enabled, the deposit shows as a **dedicated cart line**: a technical **Rental deposit** product, tax free, hidden from the catalog, carries the order's total deposit. Rented product prices only contain the rental. On the invoice, the deposit is a separate line; its refund when the equipment comes back takes one **credit slip** on that line, from the order sheet. If the customer removes the deposit line from their cart, it is recreated automatically. The amount comes from the chosen mode: per-product deposit, or automatic global deposit (multiplied base amount incl. tax, with minimum and rounding, editable in the back office).

### Stripe card imprint

With **Charge the deposit** disabled and **Deposit via Stripe imprint** enabled (`pk_` and `sk_` keys filled in), nothing is cashed. After their order, the customer is invited from the confirmation page to **save their card** on a secured page powered by Stripe Elements: no card data goes through the shop, no amount is charged or held.

In case of damage found at return: open the booking, enter the **withheld deposit** and its reason, save, then click **Charge the withholding via Stripe**. The amount is debited off session in the order currency and the payment identifier is kept on the booking. A bank decline (3-D Secure) is shown as is; the withholding then remains to be collected another way.

### Mandatory imprint before handover

A dedicated option makes the equipment handover conditional on the card being saved: a paid booking without an imprint is flagged **Pending (handover blocked)** in the bookings list (dedicated badge and filter), and the Handover button refuses until the card is saved. No paid order is ever cancelled automatically: you stay in control. The customer is guided along the way: a **Save my card** button on their My Rentals page, a daily email reminder with the secure link (through the cron URL, even when the other reminders are disabled), and a link you can copy from the booking sheet for a manual resend. A multilingual field in the configuration finally lets you replace the consent text of the imprint page with your own wording, adapted to your rental terms; the default text already mentions the authorisation to charge up to the deposit amount in case of damage.

For a case agreed with the customer (B2B, club, alternative guarantee), the **Allow handover without imprint** switch on the booking sheet exempts that one rental: the handover is unblocked, the reminders stop, the button disappears from My Rentals and the list shows an Exemption badge. Every other booking stays protected.

Why not a classic pre-authorisation? Card networks expire pre-authorisations after 7 days: impossible to cover a longer rental. Card registration does not expire; it is the model rental platforms use. The Stripe account used is independent from the shop's payment module.

## Units and serial numbers

In **Catalog > Rental > Units**, create one sheet per physical item: product, reference or serial number, state (available or under maintenance), activation, internal note. As soon as a product has at least one unit, its **rental capacity becomes the number of active and available units**: the configured quantity is no longer used, and putting a unit under maintenance removes it from stock without touching the configuration.

On each booking, the **Assigned units** field offers the units free over the period (buffer included) plus those already assigned: select the serial numbers handed to the customer. A unit taken by another booking is refused with a message. References show in the bookings list, the order sheet and the webhook.

## Check-out and check-in

In the bookings list, two actions pace the operations:

- **Handover**, on a confirmed booking: the equipment is given to the customer, the rental becomes **active** and the handover time is stored.
- **Return**, on an active rental: the equipment is given back, the rental becomes **returned** and the return time is stored. Dates release after the possible buffer.

The booking sheet holds the **condition report at handover** and **at return**, plus the **withheld deposit amount** and its **reason** in case of damage, ready for the Stripe charge or a partial credit slip.

## Planning

**Catalog > Rental > Planning** shows the month's occupancy, one row per product and one column per day: white cell free, yellow partially booked with the quantity, red full. Hovering a cell lists each booking (number, status, quantity, customer, pack marker). Closing days and the current day are marked, navigation moves month by month, and each product's post-return buffer is counted in the occupancy.

## Statistics

**Catalog > Rental > Statistics** analyses the period of your choice (last 12 months by default): per product, number of bookings, rented days multiplied by quantity and clipped to the period, capacity, occupancy rate, rental revenue excl. tax attached to the rental start, withheld deposits, with a totals row. Statuses taken into account: confirmed, active, returned.

## Seasonal pricing

The configuration grid accepts one season per line: `start|end|multiplier|label`. Two bound formats: full dates `2026-06-15|2026-09-15|1.3|High season` (one-off season) or month-day `12-20|01-05|1.5|Holidays` (recurring every year, year-crossing handled). Each rental day is billed at the daily rate multiplied by its season's coefficient; outside any season the coefficient is 1; when seasons overlap, the last line wins. Fixed packages ignore seasons: that is the point of a round price.

## Lifecycle emails (cron)

Three automatic emails accompany every paid rental: **reminder before the start**, **reminder before the return** (configurable advance, 1 = the day before) and **overdue follow-up** when the equipment is not returned on the planned date. Enable the switch then call the token-secured **cron URL** shown under the configuration form once a day (hosting cron task or external service). Each email is sent only once per booking, in the language of the customer's order, in five languages. The cron call also purges expired requests.

## Payment-free booking request

On products where the option is enabled, the product page shows a request button: the customer picks dates, leaves their contact details (identified automatically when logged in) and a message, without checking out. The request appears in the bookings with the **Request pending** status: **Accept** rechecks availability then confirms and notifies the customer; **Decline** releases the dates and notifies the customer. Stock blocking by requests is set per product and per request, and an expiry delay can cancel unanswered requests.

## Product packs

Native PrestaShop packs are synced: booking a pack blocks the availability of each of its rentable components over the same period (pack quantities included), booking a component alone makes the pack unavailable, and any change to the pack booking is propagated to its components. Component bookings are hidden shop side and visible in the back office with a Pack badge. A global setting disables the mechanism.

## REST API

Enable the API in the configuration: two regenerable tokens (read-write and read-only), passed via `X-Api-Key` or `Authorization: Bearer`.

- `GET ping`: authentication and version.
- `GET products`: rentable products and their configuration.
- `GET availability`: day-by-day availability, remaining units included.
- `GET bookings`: bookings, filterable by `status`, `id_product`, `from`, `to`, `updated_since`, `external_reference`.
- `POST bookings`: creation, idempotent via `external_reference`.
- `POST bookings&id=N`: update; `DELETE bookings&id=N`: cancellation.

## Outgoing webhooks

Enable webhooks and set your software's URL: on every event it receives a **JSON POST** containing the full booking (dates, quantity, price, status, customer, assigned units, check-in and check-out timestamps, withholding). Two headers accompany each call: `X-DfRental-Event` (event name) and `X-DfRental-Signature` (HMAC-SHA256 of the body with the secret shown in the dedicated panel, regenerable). Emitted events: `booking.requested`, `booking.confirmed`, `booking.declined`, `booking.cancelled`, `booking.active`, `booking.returned`, plus `booking.created` and `booking.updated` for the API. Delivery is best effort with a short timeout: a receiver being down never blocks the shop.

Webhooks and the API complement each other: webhooks notify your software in real time, the API with `updated_since` lets you catch up on history after a receiver outage.

## Booking tracking

**Catalog > Rental > Bookings** lists all bookings with product, customer, order, dates, assigned units and coloured status: request pending, pending, confirmed, active, returned, declined, cancelled. The Accept, Decline, Handover and Return actions show according to the status. Details also appear in the cart, on the order confirmation, in the back-office order sheet and on the My rentals page of the customer account.

## FAQ and troubleshooting

### Does the rental price change my product's price?

No. The price is injected through a specific price scoped to the current cart, and the deposit lives on its own line. The catalog price stays unchanged.

### The weeks mode returns on Sunday, I want Monday to Monday

Disable **Charge the return day**: one week then runs Monday to Monday, 7 billed days, the return happening the day after the billed period. That day stays unavailable for another handover.

### The customer did not save their Stripe imprint

As long as no card is saved, the link is offered on the order confirmation page and a Save my card button shows on the My Rentals page of the customer account. With the Mandatory imprint before handover option, the customer is additionally reminded daily by email with the secure link, and the Handover button stays blocked. The link can also be copied from the booking sheet for a manual resend; the sheet shows Imprint not saved until the flow is completed.

### The Stripe charge is declined

The customer's bank can decline an off-session debit (3-D Secure). Stripe's message is shown as is in the back office. The withholding then remains to be collected through another channel; the booking keeps the amount and reason.

### My product's capacity no longer follows the configured quantity

That is the expected behaviour as soon as a unit exists for this product: capacity becomes the number of active and available units. Delete the units to go back to the configured quantity.

### Does an accepted request create an order?

No. Acceptance confirms the booking and blocks the dates, without creating a PrestaShop order. You collect the payment through the channel of your choice and track the rental from the bookings screen.

### Reminder emails are not going out

Check that the reminder emails switch is on and that the cron URL is actually called daily: it answers in JSON with the number of emails sent. Each email is sent only once per booking, only for bookings attached to an order.

### The calendar does not show on the product page

Check that the product is configured and active in Rental products. Then clear the PrestaShop cache (Advanced Parameters > Performance) and, while testing, disable file combination (CCC).

### The API returns 401

Check that the API is enabled and that the token sent matches the displayed token. After a regeneration, update your integrations. The read-only token is only accepted on GET endpoints.

### Is it PrestaShop 9 compatible?

Yes. The module is compatible with PrestaShop 8 and 9, in multistore and multilingual setups. Price formatting uses the current Locale, in line with PrestaShop 9 practices.
