Sequence Document & Module Choices
Developer guide for the Enezaframework sequence generation. Part of the Sequence Generation series.
Table of Contents
- Overview
- Default Choices
- Defining Custom Document Choices
- Defining Custom Module Choices
- How the Loaders Work
- Fallback and Warnings
- Related Guides
Overview
SequenceConfig.documents and SequenceConfig.modules draw their choices from loader functions rather than fixed classes. A project can replace either set with its own TextChoices class through settings, letting the admin show only the document types and modules the project uses.
flowchart LR
S1["settings.MY_PROJECT_NUMBER_SEQUENCE_DOCUMENT"] --> L1["get_number_sequences_choices()"]
S2["settings.MY_PROJECT_MODULES"] --> L2["get_modules_choices()"]
L1 --> C1["documents choices"]
L2 --> C2["modules choices"]
L1 -.->|not set| D1["NumberSequencesDocument"]
L2 -.->|not set| D2["Modules"]Default Choices
The framework defaults live in enezaframework/models/choices.py:
NumberSequencesDocument(:5-68) — around 60 document types includingCUSTOMER = 'CUST',VENDOR = 'VEND',INVOICE = 'INVC',PURCHASE_ORDER = 'PO',PRODUCT = 'PRD',EMPLOYEE = 'EMP', and journal/report types.Modules(:93-120) — module categories includingGENERAL_LEDGER = 'GL',ACCOUNTS_PAYABLE = 'AP',ACCOUNTS_RECEIVABLE = 'AR',INVENTORY_MANAGEMENT = 'IM',PAYROLL = 'PR'.
Use the default values directly in document_name when you do not override choices.
Defining Custom Document Choices
# myapp/choices.py
from django.db import models
class ProjectDocumentTypes(models.TextChoices):
CUSTOMER = 'CUST', "Customer"
VENDOR = 'VEND', "Vendor"
INVOICE = 'INV', "Invoice"
PURCHASE_ORDER = 'PO', "Purchase Order"
QUOTATION = 'QT', "Quotation"
DELIVERY_NOTE = 'DN', "Delivery Note"
# settings.py
MY_PROJECT_NUMBER_SEQUENCE_DOCUMENT = 'myapp.choices.ProjectDocumentTypes'
For a document type to work end to end, the same value must appear in all three places:
| Place | Uses |
|---|---|
The model's document_name attribute |
ProjectDocumentTypes.CUSTOMER ('CUST') |
| The choices class stored in settings | the same 'CUST' value |
The admin SequenceConfig.documents |
selected from the same choices |
A value used in a model but absent from the configured choices cannot be selected in admin, so no active config will exist and generate_sequence() raises.
Defining Custom Module Choices
# myapp/choices.py
from django.db import models
class ProjectModules(models.TextChoices):
CRM = 'CRM', "Customer Relationship Management"
FINANCE = 'FIN', "Finance"
INVENTORY = 'INV', "Inventory Management"
PURCHASING = 'PUR', "Purchasing"
SALES = 'SAL', "Sales"
# settings.py
MY_PROJECT_MODULES = 'myapp.choices.ProjectModules'
Modules are organizational only; they do not affect the generated number.
How the Loaders Work
# enezaframework/models/choices.py:70-90
def get_number_sequences_choices():
choices_path = getattr(settings, 'MY_PROJECT_NUMBER_SEQUENCE_DOCUMENT', None)
if choices_path:
try:
return import_string(choices_path)
except (ImportError, AttributeError) as e:
warnings.warn(
f"Could not import {choices_path}: {e}. Using default choices."
)
return NumberSequencesDocument
get_modules_choices() (models/choices.py:122-149) is identical in shape with MY_PROJECT_MODULES and Modules.
Both SequenceConfig fields call the loader at class definition time (choices=get_number_sequences_choices().choices), so the resolved choices are baked into the model when the module is imported.
Fallback and Warnings
| Situation | Result |
|---|---|
| Setting unset | Framework default class is used. |
| Setting points to a missing module/attribute | A warnings.warn is emitted and the default class is used. |
| Setting points to a valid class | That class supplies the choices. |
Example warning:
WARNING: Could not import myapp.choices.ProjectDocumentTypes: No module named 'myapp.choices'. Using default choices.
Because the fallback is silent apart from the warning, a typo in the dotted path shows up as unexpected choices in admin rather than an error.