Skip to content

[19.0][ADD] subscription_oca: subscription renewals#1469

Open
alvaro-domatix wants to merge 1 commit into
OCA:19.0from
alvaro-domatix:19.0-add-subscription_oca-renewals
Open

[19.0][ADD] subscription_oca: subscription renewals#1469
alvaro-domatix wants to merge 1 commit into
OCA:19.0from
alvaro-domatix:19.0-add-subscription_oca-renewals

Conversation

@alvaro-domatix

Copy link
Copy Markdown

Adds subscription renewals while keeping the contractual genealogy: a renewal clones the template, lines, pricelist, fiscal position, partner and journal into a new subscription in the configured pre-stage, linked back to its parent.

The parent form gains:

  • a Renew header button, visible only while the contract is in progress and has no active child yet;
  • stat buttons for the Parent contract and the Renewals of a subscription;
  • search filters Renewals / Originals and a group-by parent contract.

Activating a renewal closes its parent via close_subscription() (respecting the company), and is_renewed — a stored boolean with a partial index, True while any non-closed child exists — hides the Renew button so a contract cannot be renewed twice in parallel.

Purely additive: it does not touch stage_id semantics or any pre-existing field, so installations with custom stages keep working. Existing subscriptions simply end up with no parent/child lineage, which is correct.

@alvaro-domatix alvaro-domatix force-pushed the 19.0-add-subscription_oca-renewals branch from 4be868b to a6fba40 Compare June 23, 2026 17:13
Add a first-class renewal workflow so a subscription can spawn a child
renewal quote, keep the link between both records, and automatically
close the parent when the renewal is activated.

* `parent_subscription_id` Many2one (self) — points at the contract
  this one was renewed from.
* `origin_subscription_id` recursive computed Many2one (stored) —
  walks up the chain to the original contract.
* `child_subscription_ids` One2many — renewals spawned from this one.
* `renewal_count` — convenience compute for the stat button.
* `is_renewed` Boolean (stored, partial index) — True when any child
  is not yet closed. Hides the Renew button while a quote is open.

`action_prepare_renewal()` clones template, lines, pricelist, fiscal
position, partner and journal into a new subscription in the configured
`pre` stage, then chats a link on the parent. Activating that renewal
calls `_handle_renewal_activation(child=self)` on the parent, which
closes it via `close_subscription()`.

UI:

* Header button "Renew", visible only when the contract is in progress
  and there is no active child yet.
* Stat buttons "Parent contract" and "Renewals" on the form.
* Search filters "Renewals" / "Originals" and a groupby by
  parent contract.

Migration: pure additive. `-u subscription_oca` runs the ORM recompute
for `origin_subscription_id` and `is_renewed`; existing subscriptions
end up with `False` for both (correct — no genealogy existed before).

This does not touch `stage_id` semantics or any pre-existing field, so
installations with custom stages keep working unchanged.
@alvaro-domatix alvaro-domatix force-pushed the 19.0-add-subscription_oca-renewals branch from a6fba40 to 68372a9 Compare June 25, 2026 17:54
@jelenapoblet

Copy link
Copy Markdown

I see the value of subscription_oca as a simpler subscription solution with a lower barrier to entry than contract. My concern is the long-term direction. As we continue adding features like renewals, aren't we gradually converging on the same feature set?

Would it make sense to explore extending or integrating with contract for some advanced capabilities instead of implementing them independently? I'm not sure it will be sustainable for both modules to evolve in parallel if they end up covering the same use cases.

@OCA-git-bot

Copy link
Copy Markdown
Contributor

This PR has the approved label and has been created more than 5 days ago. It should therefore be ready to merge by a maintainer (or a PSC member if the concerned addon has no declared maintainer). 🤖

@alvaro-domatix

Copy link
Copy Markdown
Author

Hi @jelenapoblet,

The subscription_oca module has been an alternative to contract from the very beginning, not something complementary. From the start it has had features that the contract module also covered, but what it has always had is a simpler approach (which doesn't necessarily mean less functionality).

Our experience with the contract module, and that of others (as can be read in the original post where the module is proposed, #971), was unsatisfactory from the beginning, and we took the initiative to build a module that could satisfy another segment of users (hence the impossibility of "extending" or "integrating" with that other module). The initiative we took has made subscription_oca, as of today, the module that many people and companies use instead of the contract module to manage their subscriptions. The work done in the latest PRs not only provides more useful functionality to the module, but is also the result of real effort and work.

In the same way that, in #1453, @pedrobaeza has one opinion ("With all of these changes, you are converting subscription_oca into contract in complexity terms") and you have another ("I don't think it will reach the same level of complexity as contract."), in this case I think exactly the same thing is happening.

If the changes should be implemented in a different way—for example, splitting the functionality into more modules, or having a separate repository dedicated exclusively to keeping contract and subscription_oca apart—we can look into that. But opposing a module having more useful functionality just because it would otherwise resemble another one too much, I don't quite see it.

@jelenapoblet

Copy link
Copy Markdown

@alvaro-domatix I completely understand the history, and also why subscription_oca exists. We use it ourselves for exactly the same reason. We evaluated contract, and it didn't fit our needs either.
My only point is about the long-term direction.
In any case, this is just a personal architectural observation, not an opinion for or against this PR or an attempt to influence the decision.

@alvaro-domatix

Copy link
Copy Markdown
Author

@jelenapoblet I think for us this is structural, not really a feature-set question. We didn't pick subscription_oca because it was the lighter option or because it did less. We picked it because its model fits how we work, and because it's clearly laid out. Doing less was a side effect, not the reason.

So adding functionality to it, carefully and additively, is what turns it into a genuinely powerful module that still fits us. That's the whole point.

And that's why I have a hard time following the argument. If subscription_oca should stay limited on purpose to keep distance from contract, we just end up with a weaker module for no real gain. If the advanced features belong in contract instead, well, contract's base model doesn't fit us. And by your own words, it doesn't fit you either. I don't really see a third option that works.

Open to the wider positioning conversation, wherever it makes sense. But for us, keeping subscription_oca frozen isn't really on the table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants