Skip to content

Commit

Permalink
feat: reassign number
Browse files Browse the repository at this point in the history
  • Loading branch information
shulcsm committed Dec 9, 2024
1 parent fe89f9a commit c4b06c3
Show file tree
Hide file tree
Showing 20 changed files with 248 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ jobs:

- name: Run tests
# For example, using `pytest`
run: uv run pytest test
run: uv run pytest
6 changes: 6 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@ ____________

3. Run `python manage.py migrate` to create the enumeration models.



Development
____________

DJANGO_SETTINGS_MODULE=enumeration.tests.settings django-admin makemigrations
4 changes: 2 additions & 2 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[pytest]
DJANGO_SETTINGS_MODULE = test.settings
pythonpath = . src
DJANGO_SETTINGS_MODULE = enumeration.tests.settings
pythonpath = src
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Generated by Django 4.2.17 on 2024-12-09 04:14

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("enumeration", "0001_initial"),
]

operations = [
migrations.AlterField(
model_name="counter",
name="id",
field=models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
migrations.AlterField(
model_name="gap",
name="id",
field=models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
migrations.AlterField(
model_name="sequence",
name="id",
field=models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
]
70 changes: 70 additions & 0 deletions src/enumeration/mixins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from django.db import models
from typing import Dict, TYPE_CHECKING
from enumeration.manager import get_number, format_number, ResetPeriod, truncate_date

if TYPE_CHECKING:
from enumeration.models import Sequence


class EnumeratedModelMixin(models.Model):
sequence = models.ForeignKey(
"enumeration.Sequence", null=True, on_delete=models.PROTECT
)

number = models.CharField(max_length=255, null=True, blank=True, db_index=True)
position = models.PositiveIntegerField(null=True)
counter = models.ForeignKey(
"enumeration.Counter", null=True, on_delete=models.PROTECT
)

def get_sequence(self) -> "Sequence":
raise NotImplementedError

def get_enumeration_context(self) -> Dict:
return {}

def assign_number(self):
if self.number:
raise RuntimeError("Number present")

if not self.sequence:
self.sequence = self.get_sequence()

self.number, self.position, self.counter_id = get_number(
sequence=self.sequence, **self.get_enumeration_context()
)

def reassign_number(self):
assert self.sequence and self.position and self.counter
ctx = self.get_enumeration_context()

# Sequecne never resets
if self.sequence.reset_period == ResetPeriod.NEVER:
# And correct counter
if self.counter.period is None:
self.number = format_number(
self.sequence.format,
position=self.position,
**ctx,
)
return
# sequnce resets
else:
# and correct counter period
if self.counter.period == truncate_date(
self.sequence.reset_period, ctx["date"]
):
self.number = format_number(
self.sequence.format,
position=self.position,
**ctx,
)
return

# get new number
self.number, self.position, self.counter_id = get_number(
sequence=self.sequence, **ctx
)

class Meta:
abstract = True
10 changes: 0 additions & 10 deletions src/enumeration/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from django.core.exceptions import ValidationError
from django.db import models

from enumeration.const import ResetPeriod
from enumeration.validators import validate_format

Expand Down Expand Up @@ -43,12 +42,3 @@ class Gap(models.Model):
position = models.PositiveIntegerField()

unique_together = ("counter", "position")


# class EnumeratedDocumentMixin(models.Model):
# sequence = models.ForeignKey(Sequence)
# position = models.PositiveIntegerField(null=True)
# number = models.CharField(max_length=255, null=True, blank=True)
#
# class Meta:
# abstract = True
File renamed without changes.
6 changes: 6 additions & 0 deletions src/enumeration/tests/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class TestConfig(AppConfig):
name = "enumeration.tests"
label = "enumeration_tests"
57 changes: 57 additions & 0 deletions src/enumeration/tests/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Generated by Django 4.2.17 on 2024-12-09 04:14

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
("enumeration", "0002_alter_counter_id_alter_gap_id_alter_sequence_id"),
]

operations = [
migrations.CreateModel(
name="Document",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"number",
models.CharField(
blank=True, db_index=True, max_length=255, null=True
),
),
("position", models.PositiveIntegerField(null=True)),
("date", models.DateField()),
(
"counter",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="enumeration.counter",
),
),
(
"sequence",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="enumeration.sequence",
),
),
],
options={
"abstract": False,
},
),
]
Empty file.
9 changes: 9 additions & 0 deletions src/enumeration/tests/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.db import models
from enumeration.mixins import EnumeratedModelMixin


class Document(EnumeratedModelMixin):
date = models.DateField()

def get_enumeration_context(self):
return {"date": self.date}
3 changes: 1 addition & 2 deletions test/settings.py → src/enumeration/tests/settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
DATABASE_ENGINE = "sqlite3"

DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
Expand All @@ -17,6 +15,7 @@
# 'django.contrib.auth',
# 'django.contrib.admin',
"enumeration",
"enumeration.tests",
]

SECRET_KEY = "enumeration"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
62 changes: 62 additions & 0 deletions src/enumeration/tests/test_model_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import pytest
from datetime import date
from enumeration.models import Sequence, ResetPeriod, Counter
from .models import Document


@pytest.fixture()
def sequence(db):
return Sequence.objects.create(format="YYMM###", reset_period=ResetPeriod.MONTHLY)


def test_assign_number(sequence):
d = Document(sequence=sequence, date=date(2024, 11, 5))
d.assign_number()
assert d.number == "2411001"
assert d.position == 1
assert d.counter == Counter.objects.get(
sequence=sequence, position=1, period=date(2024, 11, 1)
)

# can't assign
with pytest.raises(RuntimeError):
d.assign_number()


def test_reassing(sequence):

i = Document(sequence=sequence, date=date(2024, 11, 5))
i.assign_number()

assert i.number == "2411001"
assert i.position == 1
assert i.counter == Counter.objects.get(
sequence=sequence, position=1, period=date(2024, 11, 1)
)

# jump day in same month
i.date = date(2024, 11, 2)
i.reassign_number()

assert i.number == "2411001"
assert i.position == 1
assert i.counter == Counter.objects.get(
sequence=sequence, position=1, period=date(2024, 11, 1)
)

# move to next month
i.date = date(2024, 12, 2)
i.reassign_number()
assert i.number == "2412001"
assert i.position == 1
assert i.counter == Counter.objects.get(
sequence=sequence, position=1, period=date(2024, 12, 1)
)

i = Document(sequence=sequence, date=date(2024, 12, 1))
i.assign_number()
assert i.number == "2412002"
assert i.position == 2
assert i.counter == Counter.objects.get(
sequence=sequence, position=2, period=date(2024, 12, 1)
)

0 comments on commit c4b06c3

Please sign in to comment.