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
100 changes: 100 additions & 0 deletions product_rental_fee_link/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
=======================
Product Rental Fee Link
=======================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:cd91e3917d3563e4af97a4bde7bef1cb579cce2450d30aa5d06150cd08052441
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-qrtl%2Focj--custom-lightgray.png?logo=github
:target: https://github.com/qrtl/ocj-custom/tree/19.0/product_rental_fee_link
:alt: qrtl/ocj-custom

|badge1| |badge2| |badge3|

This module lets you point an equipment product at the service product
used to bill its rental.

When rental fees are managed as products separate from the equipment
itself (one *rental fee* product per equipment model), nothing in the
standard data model ties the two together. This module adds a dedicated
**Rental Fee Product** link on the product, restricted to non-storable
service products.

Why a dedicated field rather than *Optional Products*:
``optional_product_ids`` is a many2many meant for cross-sell suggestions
in the quotation product configurator. It cannot express a single,
verifiable relationship, it carries no type restriction, and its meaning
collides with genuine cross-sell entries. A dedicated many2one can be
validated, searched, and used as the source for integrations.

**Table of contents**

.. contents::
:local:

Usage
=====

On an equipment product (Goods), set **Rental Fee Product** next to the
product category. Only non-storable service products can be selected,
and a product cannot point at itself.

The field is hidden on service products, since a rental fee product is
not itself rented.

To find equipment that still needs the link, use the **Rental Fee
Product Missing** filter in the product search view.

Several equipment products may share the same rental fee product; this
is not restricted, because the same fee often applies to more than one
model.

If the rental fee product carries variants (for example a *price
category* attribute for first unit / second unit / in-hospital use), the
variants of the linked product are the set of billable items for that
equipment - which is what an integration reads to publish the
corresponding product codes.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/qrtl/ocj-custom/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/qrtl/ocj-custom/issues/new?body=module:%20product_rental_fee_link%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Quartile

Maintainers
-----------

.. |maintainer-yostashiro| image:: https://github.com/yostashiro.png?size=40px
:target: https://github.com/yostashiro
:alt: yostashiro

Current maintainer:

|maintainer-yostashiro|

This module is part of the `qrtl/ocj-custom <https://github.com/qrtl/ocj-custom/tree/19.0/product_rental_fee_link>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions product_rental_fee_link/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions product_rental_fee_link/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2026 Quartile (https://www.quartile.co)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
{
"name": "Product Rental Fee Link",
"version": "19.0.1.0.0",
"category": "Inventory/Inventory",
"website": "https://www.quartile.co",
"author": "Quartile",
"maintainers": ["yostashiro"],
"license": "LGPL-3",
"summary": "Link an equipment product to the service product used to bill "
"its rental",
"installable": True,
"depends": ["stock"],
"data": [
"views/product_template_views.xml",
],
}
66 changes: 66 additions & 0 deletions product_rental_fee_link/i18n/ja.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * product_rental_fee_link
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 19.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-30 05:51+0000\n"
"PO-Revision-Date: 2026-07-30 05:51+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: product_rental_fee_link
#. odoo-python
#: code:addons/product_rental_fee_link/models/product_template.py:0
msgid "A product cannot be its own rental fee product."
msgstr "プロダクト自身をレンタル費用品目に設定することはできません。"

#. module: product_rental_fee_link
#: model:ir.model.fields,field_description:product_rental_fee_link.field_product_template__display_name
msgid "Display Name"
msgstr "表示名"

#. module: product_rental_fee_link
#: model:ir.model.fields,field_description:product_rental_fee_link.field_product_template__id
msgid "ID"
msgstr ""

#. module: product_rental_fee_link
#: model:ir.model,name:product_rental_fee_link.model_product_template
msgid "Product"
msgstr "プロダクト"

#. module: product_rental_fee_link
#: model:ir.model.fields,field_description:product_rental_fee_link.field_product_product__rental_fee_product_tmpl_id
#: model:ir.model.fields,field_description:product_rental_fee_link.field_product_template__rental_fee_product_tmpl_id
msgid "Rental Fee Product"
msgstr "レンタル費用品目"

#. module: product_rental_fee_link
#: model_terms:ir.ui.view,arch_db:product_rental_fee_link.product_template_view_search
msgid "Rental Fee Product Missing"
msgstr "レンタル費用品目 未設定"

#. module: product_rental_fee_link
#: model:ir.model.fields,help:product_rental_fee_link.field_product_product__rental_fee_product_tmpl_id
#: model:ir.model.fields,help:product_rental_fee_link.field_product_template__rental_fee_product_tmpl_id
msgid ""
"Service product used to bill the rental of this equipment. The rental fee is"
" managed as a product separate from the equipment itself, so this link is "
"what ties the two together - e.g. to derive the product codes to send to an "
"external system from the variants of the rental fee product."
msgstr ""
"この機種の課金に使うレンタル費用品目。レンタル費用は機器そのものとは別の品目として管理するため、両者を結びつけるのはこの項目です"
"(例: 外部システムへ配信する商品CDを、レンタル費用品目のバリアントから導出する)。"

#. module: product_rental_fee_link
#. odoo-python
#: code:addons/product_rental_fee_link/models/product_template.py:0
msgid "The rental fee product must be a service, but %(product)s is not."
msgstr "レンタル費用品目はサービス品目でなければなりません(%(product)s はサービス品目ではありません)。"
1 change: 1 addition & 0 deletions product_rental_fee_link/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import product_template
40 changes: 40 additions & 0 deletions product_rental_fee_link/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2026 Quartile (https://www.quartile.co)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).

from odoo import api, fields, models
from odoo.exceptions import ValidationError


class ProductTemplate(models.Model):
_inherit = "product.template"

rental_fee_product_tmpl_id = fields.Many2one(
comodel_name="product.template",
string="Rental Fee Product",
domain=[("type", "=", "service")],
help="Service product used to bill the rental of this equipment. The "
"rental fee is managed as a product separate from the equipment itself, "
"so this link is what ties the two together - e.g. to derive the product "
"codes to send to an external system from the variants of the rental fee "
"product.",
)

@api.constrains("rental_fee_product_tmpl_id", "type")
def _check_rental_fee_product_tmpl_id(self):
# The product type is the discriminator here; is_storable is deliberately
# not checked, as it only means "track inventory" and can be turned on by
# a user default even for services (core clears it on recompute anyway).
for template in self.filtered("rental_fee_product_tmpl_id"):
fee_product = template.rental_fee_product_tmpl_id
if fee_product == template:
raise ValidationError(
self.env._("A product cannot be its own rental fee product.")
)
if fee_product.type != "service":
raise ValidationError(
self.env._(
"The rental fee product must be a service, but "
"%(product)s is not.",
product=fee_product.display_name,
)
)
3 changes: 3 additions & 0 deletions product_rental_fee_link/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
14 changes: 14 additions & 0 deletions product_rental_fee_link/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
This module lets you point an equipment product at the service product used to
bill its rental.

When rental fees are managed as products separate from the equipment itself
(one *rental fee* product per equipment model), nothing in the standard data
model ties the two together. This module adds a dedicated **Rental Fee Product**
link on the product, restricted to non-storable service products.

Why a dedicated field rather than *Optional Products*: `optional_product_ids` is
a many2many meant for cross-sell suggestions in the quotation product
configurator. It cannot express a single, verifiable relationship, it carries no
type restriction, and its meaning collides with genuine cross-sell entries. A
dedicated many2one can be validated, searched, and used as the source for
integrations.
17 changes: 17 additions & 0 deletions product_rental_fee_link/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
On an equipment product (Goods), set **Rental Fee Product** next to the product
category. Only non-storable service products can be selected, and a product
cannot point at itself.

The field is hidden on service products, since a rental fee product is not
itself rented.

To find equipment that still needs the link, use the **Rental Fee Product
Missing** filter in the product search view.

Several equipment products may share the same rental fee product; this is not
restricted, because the same fee often applies to more than one model.

If the rental fee product carries variants (for example a *price category*
attribute for first unit / second unit / in-hospital use), the variants of the
linked product are the set of billable items for that equipment - which is what
an integration reads to publish the corresponding product codes.
Loading
Loading