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
104 changes: 104 additions & 0 deletions contract_service_dates/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
======================
Contract Service Dates
======================

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

.. |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/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github
:target: https://github.com/OCA/contract/tree/18.0/contract_service_dates
:alt: OCA/contract
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/contract-18-0/contract-18-0-contract_service_dates
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/contract&target_branch=18.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module adds **Service Start Date** and **Service End Date** fields
to contract lines, allowing you to track the actual service period
independently from the billing dates.

**Table of contents**

.. contents::
:local:

Use Cases / Context
===================

Contract lines in the base contract module carry a single start date and
end date that drive the recurring invoicing schedule. There is no
dedicated field to record the period during which the service is
actually delivered, which is often distinct from the billing period.
This module fills that gap.

Usage
=====

On a contract line form, a new **Service Dates** group is displayed in
the **Recurrence** tab, below the contract line start and end dates:

- **Service Start Date**: start of the service period. Populated
automatically from the contract line start date and kept in sync with
it unless manually overridden.
- **Service End Date**: end of the service period. Populated
automatically from the contract line end date and kept in sync with it
unless manually overridden.

Once a service date is set to a value different from its corresponding
contract line date, it is considered decoupled and will no longer be
updated automatically when the contract line date changes.

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/contract/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/OCA/contract/issues/new?body=module:%20contract_service_dates%0Aversion:%2018.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
-------

* ACSONE SA/NV

Contributors
------------

- Benoit Aimont benoit.aimont@acsone.eu (https://www.acsone.eu/)

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

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/contract <https://github.com/OCA/contract/tree/18.0/contract_service_dates>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions contract_service_dates/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions contract_service_dates/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2026 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Contract Service Dates",
"summary": """This module adds Service Dates fields to contract lines""",
"version": "18.0.1.0.0",
"license": "AGPL-3",
"author": "ACSONE SA/NV, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/contract",
"depends": [
"contract",
],
"data": [
"views/contract_line.xml",
],
"installable": True,
}
1 change: 1 addition & 0 deletions contract_service_dates/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import contract_line
58 changes: 58 additions & 0 deletions contract_service_dates/models/contract_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2026 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class ContractLine(models.Model):
_inherit = "contract.line"

service_start_date = fields.Date(
help="Start date of the service period covered by this contract line. "
"Defaults to the contract line start date and follows it unless "
"manually overridden.",
)
service_end_date = fields.Date(
help="End date of the service period covered by this contract line. "
"Defaults to the contract line end date and follows it unless "
"manually overridden.",
)

def _get_service_date_create_vals(self, vals):
"""Return service date vals to initialize on create."""
result = {}
if vals.get("date_start") and not vals.get("service_start_date"):
result["service_start_date"] = vals["date_start"]
if vals.get("date_end") and not vals.get("service_end_date"):
result["service_end_date"] = vals["date_end"]
return result

@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
vals.update(self._get_service_date_create_vals(vals))
return super().create(vals_list)

def _get_service_date_sync_vals(self, vals):
"""Return service date vals to sync from contract date vals."""
self.ensure_one()
service_vals = {}
if "date_start" in vals and self.service_start_date == self.date_start:
service_vals["service_start_date"] = vals["date_start"]
if "date_end" in vals and self.service_end_date == self.date_end:
service_vals["service_end_date"] = vals["date_end"]
return service_vals

def write(self, vals):
if not self.env.context.get("_sync_service_dates"):
service_vals_by_id = {}
for rec in self:
service_vals = rec._get_service_date_sync_vals(vals)
if service_vals:
service_vals_by_id[rec.id] = service_vals
for rec in self:
if rec.id in service_vals_by_id:
rec.with_context(_sync_service_dates=True).write(
service_vals_by_id[rec.id]
)
return super().write(vals)
3 changes: 3 additions & 0 deletions contract_service_dates/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
4 changes: 4 additions & 0 deletions contract_service_dates/readme/CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Contract lines in the base contract module carry a single start date and end
date that drive the recurring invoicing schedule. There is no dedicated field
to record the period during which the service is actually delivered, which is
often distinct from the billing period. This module fills that gap.
1 change: 1 addition & 0 deletions contract_service_dates/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Benoit Aimont <benoit.aimont@acsone.eu> (https://www.acsone.eu/)
3 changes: 3 additions & 0 deletions contract_service_dates/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This module adds **Service Start Date** and **Service End Date** fields to
contract lines, allowing you to track the actual service period independently
from the billing dates.
13 changes: 13 additions & 0 deletions contract_service_dates/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
On a contract line form, a new **Service Dates** group is displayed in the
**Recurrence** tab, below the contract line start and end dates:

- **Service Start Date**: start of the service period. Populated automatically
from the contract line start date and kept in sync with it unless manually
overridden.
- **Service End Date**: end of the service period. Populated automatically from
the contract line end date and kept in sync with it unless manually
overridden.

Once a service date is set to a value different from its corresponding contract
line date, it is considered decoupled and will no longer be updated
automatically when the contract line date changes.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading