Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Business modules

Module

Subscriptions module (subscriptions)

Module page for subscriptions, which holds recurring subscription plans and customer and purchase subscriptions with their lifecycle and daily sweep.

The subscriptions module in src/cluster_erp/modules/subscriptions/ records recurring business: plans that the company offers, subscriptions of customers to those plans, and subscriptions the company itself holds with vendors. It tracks billing periods, renewals, and expiry and emits lifecycle events; it produces no invoices. It is a business module, not the SaaS membership of a tenant, which is explained in multi-tenancy.

At a glance

Item Value Source
Package src/cluster_erp/modules/subscriptions/ folder
Module class Module src/cluster_erp/modules/subscriptions/module.py:15
name / version subscriptions / 0.1.0 src/cluster_erp/modules/subscriptions/module.py:16-22
API prefix /api/v1/subscriptions (ModuleBase.api_prefix) src/cluster_erp/core/module_base.py:37-38
Sub-modules 2: plans, customer_subscriptions folder listing
Tables 2: sub_plans, sub_customer_subscriptions src/cluster_erp/modules/subscriptions/plans/models.py:23, src/cluster_erp/modules/subscriptions/customer_subscriptions/models.py:34
Entities in metadata 2: customer_subscription, subscription_plan src/cluster_erp/modules/subscriptions/module.py:149-152
Web app presence Catalogue app subscriptions src/cluster_erp/modules/app_store/catalog.json (entry subscriptions)
Desktop presence Generic widgets only; no folder in src/cluster_erp/desktop/modules/ folder

What the module does

  • A plan states what recurring product is sold, how often it bills, and at what price (src/cluster_erp/modules/subscriptions/plans/models.py:13-21).
  • A sales subscription takes its terms from an active plan; a purchase subscription has its terms entered directly against a vendor (src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:129-206).
  • Activation snapshots the plan's terms so that later plan changes do not rewrite history (src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:247-275).
  • A daily sweep renews or expires subscriptions whose period has ended (src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:348-390, src/cluster_erp/server/app.py:504-546).

Sub-modules

Sub-module Purpose Main entities Router Source
plans Sellable recurring plans SubscriptionPlan /api/v1/subscriptions/subscription-plans src/cluster_erp/modules/subscriptions/plans/routes.py:25
customer_subscriptions Customer and purchase subscriptions CustomerSubscription /api/v1/subscriptions (module root) src/cluster_erp/modules/subscriptions/customer_subscriptions/routes.py:31-34

Data model

Entity Table Key fields Notes Source
SubscriptionPlan sub_plans code, name, product_id, product_model_id, product_version_id, billing_cycle, interval_count, price_per_cycle, currency, setup_fee, trial_days, min_term_cycles, status product triple required; money columns Numeric(18, 4); tenant fields in extra src/cluster_erp/modules/subscriptions/plans/models.py:13-59
CustomerSubscription sub_customer_subscriptions subscription_no, direction, customer_id, vendor_id, plan_id, product triple, snapshot terms, period dates, auto_renew, status a check constraint requires a customer for sales and a vendor for purchase src/cluster_erp/modules/subscriptions/customer_subscriptions/models.py:23-109

Money values are Numeric columns and Decimal in schemas, and events carry amounts as strings (src/cluster_erp/modules/subscriptions/plans/models.py:43-47, src/cluster_erp/modules/subscriptions/plans/schemas.py:22-24, src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:415-444). See money and Decimal.

Screens and metadata

get_metadata declares a sidebar group Subscriptions (Turkish Abonelikler) with two list sections: Subscriptions for customer_subscription and Plans (Turkish Planlar) for subscription_plan (src/cluster_erp/modules/subscriptions/module.py:121-153). Billing cycle choices are Monthly, Quarterly, Semi-annual, and Annual (src/cluster_erp/modules/subscriptions/customer_subscriptions/metadata.py:40-45).

Status and actions

Plan statuses go draft to active to retired, with no way back (src/cluster_erp/modules/subscriptions/plans/services.py:101-117). Subscription statuses are draft, active, paused, cancelled, and expired (src/cluster_erp/modules/subscriptions/customer_subscriptions/models.py:97-100).

Action Label Condition Endpoint Permission Source
plan activate Activate status is draft POST /subscription-plans/{id}/activate subscription_plan.activate src/cluster_erp/modules/subscriptions/plans/metadata.py:100-107, src/cluster_erp/modules/subscriptions/plans/routes.py:99-108
plan retire Retire status is active POST /subscription-plans/{id}/retire subscription_plan.retire src/cluster_erp/modules/subscriptions/plans/metadata.py:108-115, src/cluster_erp/modules/subscriptions/plans/routes.py:111-120
activate Activate status is draft POST /{id}/activate customer_subscription.activate src/cluster_erp/modules/subscriptions/customer_subscriptions/metadata.py:141, src/cluster_erp/modules/subscriptions/customer_subscriptions/routes.py:125-130
pause Pause status is active POST /{id}/pause customer_subscription.pause src/cluster_erp/modules/subscriptions/customer_subscriptions/metadata.py:142, src/cluster_erp/modules/subscriptions/customer_subscriptions/routes.py:131-136
resume Resume status is paused POST /{id}/resume customer_subscription.resume src/cluster_erp/modules/subscriptions/customer_subscriptions/metadata.py:143
renew Renew Now status is active POST /{id}/renew customer_subscription.renew src/cluster_erp/modules/subscriptions/customer_subscriptions/metadata.py:144
cancel Cancel status is draft, active, or paused POST /{id}/cancel customer_subscription.cancel src/cluster_erp/modules/subscriptions/customer_subscriptions/metadata.py:146-151, src/cluster_erp/modules/subscriptions/customer_subscriptions/routes.py:151-161

The state diagram shows a subscription's lifecycle.

stateDiagram-v2
    [*] --> draft: create
    draft --> active: activate
    active --> paused: pause
    paused --> active: resume
    active --> active: renew or sweep renewal
    active --> expired: sweep, end reached or renewal off
    draft --> cancelled: cancel
    active --> cancelled: cancel
    paused --> cancelled: cancel
    cancelled --> [*]
    expired --> [*]

In prose: a subscription is created as draft; activate starts the first period; pause and resume move between active and paused; renew or the sweep advances the period of an active subscription; the sweep expires an active subscription past its end date or whose period ended with renewal off; cancel ends any subscription that is not already cancelled or expired (src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:247-399). Labels come from the metadata label dictionaries.

Business rules

  • A sales subscription needs a customer and an active plan; a purchase subscription needs a vendor, the full product triple, a price, a cycle, and a currency (src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:129-190).
  • subscription_no and the plan code are yearly business keys from next_code (src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:112, src/cluster_erp/modules/subscriptions/plans/services.py:65).
  • A period is the cycle length in months (1, 3, 6, or 12) times interval_count, anchored on the first period's day of month (src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:35-53, src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:328-339).
  • The sweep catches up every period due and emits one renewal per period (src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:365-385).
  • The amount in an event is unit price times quantity (src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:426-444).

Events and queries

Direction Contract class Handler or emitter Source
emits SubscriptionActivated, SubscriptionRenewed, SubscriptionCancelled, SubscriptionExpired SubscriptionService._emit src/cluster_erp/modules/subscriptions/customer_subscriptions/services.py:415-444, src/cluster_erp/core/contracts.py:2318-2352
answers query GetSubscriptionPlanById _handle_get_plan src/cluster_erp/modules/subscriptions/module.py:53
answers query GetCustomerSubscriptionById _handle_get_subscription src/cluster_erp/modules/subscriptions/module.py:54-56

A grep for the four event classes outside the module finds no subscriber at this commit.

Permissions

Permission key Used by Source
subscription_plan.read, .create, .update, .delete, .bulk_delete, .activate, .retire plan routes src/cluster_erp/modules/subscriptions/plans/routes.py:42-140
customer_subscription.read, .create, .update, .delete, .bulk_delete, .activate, .pause, .resume, .renew, .cancel subscription routes; .renew also guards the on-demand sweep src/cluster_erp/modules/subscriptions/customer_subscriptions/routes.py:51-197

The lifecycle codes are seeded as extra codes (src/cluster_erp/server/app.py:837-847).

Privacy, retention, and history

The module stores party ids of customers and vendors but no personal fields of its own, and it has no privacy_handlers.py. Changes are captured by change history; see change history. Tenant-defined values in extra are filtered by permission on read (src/cluster_erp/modules/subscriptions/customer_subscriptions/routes.py:42-48).

Analytics facts

This module has no analytics_facts.py.

Settings and reference data

The module reads no dedicated settings. Currencies are three-letter codes validated by pattern in the plan schema (src/cluster_erp/modules/subscriptions/plans/schemas.py:23). The daily sweep runs per tenant database under a leader lock (src/cluster_erp/server/app.py:504-546).

Tests

Found by file name in tests/ and web-client/.

Kind File Covers
pytest tests/test_subscription_math.py period math and event payloads (5 tests)
e2e web-client/_e2e_subscriptions.mjs plans and subscriptions in the web app

Discrepancies

Terms introduced

Term Code identifier Definition Turkish term Source
subscription plan SubscriptionPlan A sellable recurring product with its cycle and price. Plan src/cluster_erp/modules/subscriptions/plans/models.py:13
customer subscription CustomerSubscription A live recurring agreement with a customer or a vendor. Abonelik src/cluster_erp/modules/subscriptions/customer_subscriptions/models.py:23
subscription direction direction Whether a subscription is a sale to a customer or a purchase from a vendor. abonelik yönü src/cluster_erp/modules/subscriptions/customer_subscriptions/models.py:55

Verified against commit 92f8051 on 2026-11-13.

Verified against commit 92f8051 · 2026-11-13