diff --git a/papermerge/core/db/__init__.py b/papermerge/core/db/__init__.py
index 1857d1999..33141af11 100644
--- a/papermerge/core/db/__init__.py
+++ b/papermerge/core/db/__init__.py
@@ -17,14 +17,6 @@
update_doc_type,
)
from .doc_ver import get_doc_ver, get_last_doc_ver
-from .document_types import (
- create_document_type,
- delete_document_type,
- document_type_cf_count,
- get_document_type,
- get_document_types,
- update_document_type,
-)
from .engine import get_engine
from .exceptions import UserNotFound
from .folders import get_folder
@@ -75,15 +67,9 @@
"get_custom_field",
"delete_custom_field",
"update_custom_field",
- "get_document_types",
- "create_document_type",
- "get_document_type",
- "delete_document_type",
- "update_document_type",
"update_doc_cfv",
"get_doc_cfv",
"update_doc_type",
"get_docs_by_type",
- "document_type_cf_count",
"get_docs_count_by_type",
]
diff --git a/papermerge/core/db/custom_fields.py b/papermerge/core/db/custom_fields.py
index 28433fc61..3a7c73751 100644
--- a/papermerge/core/db/custom_fields.py
+++ b/papermerge/core/db/custom_fields.py
@@ -5,13 +5,14 @@
from sqlalchemy.orm import Session
from papermerge.core import schemas
-from papermerge.core.db import models
+
+from .models import CustomField
logger = logging.getLogger(__name__)
def get_custom_fields(session: Session) -> list[schemas.CustomField]:
- stmt = select(models.CustomField)
+ stmt = select(CustomField)
db_items = session.scalars(stmt).all()
result = [schemas.CustomField.model_validate(db_item) for db_item in db_items]
@@ -25,7 +26,7 @@ def create_custom_field(
user_id: uuid.UUID,
extra_data: str | None = None,
) -> schemas.CustomField:
- cfield = models.CustomField(
+ cfield = CustomField(
id=uuid.uuid4(),
name=name,
type=type,
@@ -42,14 +43,14 @@ def create_custom_field(
def get_custom_field(
session: Session, custom_field_id: uuid.UUID
) -> schemas.CustomField:
- stmt = select(models.CustomField).where(models.CustomField.id == custom_field_id)
+ stmt = select(CustomField).where(CustomField.id == custom_field_id)
db_item = session.scalars(stmt).unique().one()
result = schemas.CustomField.model_validate(db_item)
return result
def delete_custom_field(session: Session, custom_field_id: uuid.UUID):
- stmt = select(models.CustomField).where(models.CustomField.id == custom_field_id)
+ stmt = select(CustomField).where(CustomField.id == custom_field_id)
cfield = session.execute(stmt).scalars().one()
session.delete(cfield)
session.commit()
@@ -58,7 +59,7 @@ def delete_custom_field(session: Session, custom_field_id: uuid.UUID):
def update_custom_field(
session: Session, custom_field_id: uuid.UUID, attrs: schemas.UpdateCustomField
) -> schemas.CustomField:
- stmt = select(models.CustomField).where(models.CustomField.id == custom_field_id)
+ stmt = select(CustomField).where(CustomField.id == custom_field_id)
cfield = session.execute(stmt).scalars().one()
session.add(cfield)
diff --git a/papermerge/core/db/doc.py b/papermerge/core/db/doc.py
index 6a71ec3e1..2dbe7a94b 100644
--- a/papermerge/core/db/doc.py
+++ b/papermerge/core/db/doc.py
@@ -18,10 +18,10 @@
Page,
)
from papermerge.core.exceptions import InvalidDateFormat
+from papermerge.core.features.document_types.db import document_type_cf_count
from papermerge.core.types import OrderEnum
from .common import get_ancestors
-from .document_types import document_type_cf_count
def str2date(value: str | None) -> Optional[datetime.date]:
diff --git a/papermerge/core/db/models.py b/papermerge/core/db/models.py
index deefe89ee..5e2a88646 100644
--- a/papermerge/core/db/models.py
+++ b/papermerge/core/db/models.py
@@ -143,7 +143,7 @@ class Document(Node):
ocr: Mapped[bool]
ocr_status: Mapped[str]
- document_type: Mapped["DocumentType"] = relationship(
+ document_type: Mapped["DocumentType"] = relationship( # noqa: F821
primaryjoin="DocumentType.id == Document.document_type_id",
)
document_type_id: Mapped[UUID] = mapped_column(ForeignKey("document_types.id"))
@@ -276,15 +276,3 @@ class CustomFieldValue(Base):
def __repr__(self):
return f"CustomFieldValue(ID={self.id})"
-
-
-class DocumentType(Base):
- __tablename__ = "document_types"
-
- id: Mapped[UUID] = mapped_column(primary_key=True)
- name: Mapped[str]
- custom_fields: Mapped[list["CustomField"]] = relationship(
- secondary="document_type_custom_field"
- )
- user_id: Mapped[UUID] = mapped_column(ForeignKey("core_user.id"))
- created_at: Mapped[datetime] = mapped_column(insert_default=func.now())
diff --git a/papermerge/core/features/document_types/db/__init__.py b/papermerge/core/features/document_types/db/__init__.py
new file mode 100644
index 000000000..39444ea2e
--- /dev/null
+++ b/papermerge/core/features/document_types/db/__init__.py
@@ -0,0 +1,19 @@
+from .api import (
+ create_document_type,
+ delete_document_type,
+ document_type_cf_count,
+ get_document_type,
+ get_document_types,
+ update_document_type,
+)
+from .orm import DocumentType
+
+__all__ = [
+ "document_type_cf_count",
+ "create_document_type",
+ "get_document_types",
+ "get_document_type",
+ "delete_document_type",
+ "update_document_type",
+ "DocumentType",
+]
diff --git a/papermerge/core/db/document_types.py b/papermerge/core/features/document_types/db/api.py
similarity index 74%
rename from papermerge/core/db/document_types.py
rename to papermerge/core/features/document_types/db/api.py
index 7ef55a660..78bed0aa9 100644
--- a/papermerge/core/db/document_types.py
+++ b/papermerge/core/features/document_types/db/api.py
@@ -5,13 +5,15 @@
from sqlalchemy.orm import Session
from papermerge.core import schemas
-from papermerge.core.db import models
+from papermerge.core.db.models import CustomField
+
+from .orm import DocumentType
logger = logging.getLogger(__name__)
def get_document_types(session: Session) -> list[schemas.DocumentType]:
- stmt = select(models.DocumentType)
+ stmt = select(DocumentType)
db_items = session.scalars(stmt).all()
result = [schemas.DocumentType.model_validate(db_item) for db_item in db_items]
@@ -20,7 +22,7 @@ def get_document_types(session: Session) -> list[schemas.DocumentType]:
def document_type_cf_count(session: Session, document_type_id: uuid.UUID):
"""count number of custom fields associated to document type"""
- stmt = select(models.DocumentType).where(models.DocumentType.id == document_type_id)
+ stmt = select(DocumentType).where(DocumentType.id == document_type_id)
dtype = session.scalars(stmt).one()
return len(dtype.custom_fields)
@@ -30,18 +32,20 @@ def create_document_type(
name: str,
user_id: uuid.UUID,
custom_field_ids: list[uuid.UUID] | None = None,
+ path_template: str | None = None,
) -> schemas.DocumentType:
if custom_field_ids is None:
cf_ids = []
else:
cf_ids = custom_field_ids
- stmt = select(models.CustomField).where(models.CustomField.id.in_(cf_ids))
+ stmt = select(CustomField).where(CustomField.id.in_(cf_ids))
custom_fields = session.execute(stmt).scalars().all()
- dtype = models.DocumentType(
+ dtype = DocumentType(
id=uuid.uuid4(),
name=name,
custom_fields=custom_fields,
+ path_template=path_template,
user_id=user_id,
)
session.add(dtype)
@@ -53,14 +57,14 @@ def create_document_type(
def get_document_type(
session: Session, document_type_id: uuid.UUID
) -> schemas.DocumentType:
- stmt = select(models.DocumentType).where(models.DocumentType.id == document_type_id)
+ stmt = select(DocumentType).where(DocumentType.id == document_type_id)
db_item = session.scalars(stmt).unique().one()
result = schemas.DocumentType.model_validate(db_item)
return result
def delete_document_type(session: Session, document_type_id: uuid.UUID):
- stmt = select(models.DocumentType).where(models.DocumentType.id == document_type_id)
+ stmt = select(DocumentType).where(DocumentType.id == document_type_id)
cfield = session.execute(stmt).scalars().one()
session.delete(cfield)
session.commit()
@@ -69,12 +73,10 @@ def delete_document_type(session: Session, document_type_id: uuid.UUID):
def update_document_type(
session: Session, document_type_id: uuid.UUID, attrs: schemas.UpdateDocumentType
) -> schemas.DocumentType:
- stmt = select(models.DocumentType).where(models.DocumentType.id == document_type_id)
+ stmt = select(DocumentType).where(DocumentType.id == document_type_id)
doc_type = session.execute(stmt).scalars().one()
- stmt = select(models.CustomField).where(
- models.CustomField.id.in_(attrs.custom_field_ids)
- )
+ stmt = select(CustomField).where(CustomField.id.in_(attrs.custom_field_ids))
custom_fields = session.execute(stmt).scalars().all()
if attrs.name:
@@ -83,6 +85,8 @@ def update_document_type(
if attrs.custom_field_ids:
doc_type.custom_fields = custom_fields
+ doc_type.path_template = attrs.path_template
+
session.add(doc_type)
session.commit()
result = schemas.DocumentType.model_validate(doc_type)
diff --git a/papermerge/core/features/document_types/db/orm.py b/papermerge/core/features/document_types/db/orm.py
new file mode 100644
index 000000000..8a0fb9bc5
--- /dev/null
+++ b/papermerge/core/features/document_types/db/orm.py
@@ -0,0 +1,20 @@
+from datetime import datetime
+from uuid import UUID
+
+from sqlalchemy import ForeignKey, func
+from sqlalchemy.orm import Mapped, mapped_column, relationship
+
+from papermerge.core.db.base import Base
+
+
+class DocumentType(Base):
+ __tablename__ = "document_types"
+
+ id: Mapped[UUID] = mapped_column(primary_key=True)
+ name: Mapped[str]
+ path_template: Mapped[str]
+ custom_fields: Mapped[list["CustomField"]] = relationship( # noqa: F821
+ secondary="document_type_custom_field"
+ )
+ user_id: Mapped[UUID] = mapped_column(ForeignKey("core_user.id"))
+ created_at: Mapped[datetime] = mapped_column(insert_default=func.now())
diff --git a/papermerge/core/models/document_type.py b/papermerge/core/features/document_types/models.py
similarity index 92%
rename from papermerge/core/models/document_type.py
rename to papermerge/core/features/document_types/models.py
index 55fd8f70a..6a3336d0b 100644
--- a/papermerge/core/models/document_type.py
+++ b/papermerge/core/features/document_types/models.py
@@ -10,6 +10,7 @@ class DocumentType(models.Model):
user = models.ForeignKey(
"User", related_name="document_types", on_delete=models.CASCADE
)
+ path_template = models.CharField(max_length=2048, null=True)
created_at = models.DateTimeField(
"created_at",
default=timezone.now,
diff --git a/papermerge/core/routers/document_types.py b/papermerge/core/features/document_types/router.py
similarity index 85%
rename from papermerge/core/routers/document_types.py
rename to papermerge/core/features/document_types/router.py
index 2b70cff2d..db0ec1491 100644
--- a/papermerge/core/routers/document_types.py
+++ b/papermerge/core/features/document_types/router.py
@@ -5,12 +5,13 @@
from fastapi import APIRouter, Depends, HTTPException, Security
from sqlalchemy.exc import NoResultFound
-from papermerge.core import db, schemas, utils
+from papermerge.core import schemas, utils
from papermerge.core.auth import get_current_user, scopes
-
-from .common import OPEN_API_GENERIC_JSON_DETAIL
-from .paginator import PaginatorGeneric, paginate
-from .params import CommonQueryParams
+from papermerge.core.db import Session, get_session
+from papermerge.core.features.document_types import db
+from papermerge.core.routers.common import OPEN_API_GENERIC_JSON_DETAIL
+from papermerge.core.routers.paginator import PaginatorGeneric, paginate
+from papermerge.core.routers.params import CommonQueryParams
router = APIRouter(
prefix="/document-types",
@@ -26,7 +27,7 @@ def get_document_types_without_pagination(
user: Annotated[
schemas.User, Security(get_current_user, scopes=[scopes.DOCUMENT_TYPE_VIEW])
],
- db_session: db.Session = Depends(db.get_session),
+ db_session: Session = Depends(get_session),
):
"""Get all document types without pagination/filtering/sorting
@@ -44,7 +45,7 @@ def get_document_types(
schemas.User, Security(get_current_user, scopes=[scopes.CUSTOM_FIELD_VIEW])
],
params: CommonQueryParams = Depends(),
- db_session: db.Session = Depends(db.get_session),
+ db_session: Session = Depends(get_session),
):
"""Get all (paginated) document types
@@ -60,7 +61,7 @@ def get_document_type(
user: Annotated[
schemas.User, Security(get_current_user, scopes=[scopes.DOCUMENT_TYPE_VIEW])
],
- db_session: db.Session = Depends(db.get_session),
+ db_session: Session = Depends(get_session),
):
"""Get document type
@@ -80,7 +81,7 @@ def create_document_type(
user: Annotated[
schemas.User, Security(get_current_user, scopes=[scopes.DOCUMENT_TYPE_CREATE])
],
- db_session: db.Session = Depends(db.get_session),
+ db_session: Session = Depends(get_session),
) -> schemas.DocumentType:
"""Creates document type
@@ -90,6 +91,7 @@ def create_document_type(
document_type = db.create_document_type(
db_session,
name=dtype.name,
+ path_template=dtype.path_template,
custom_field_ids=dtype.custom_field_ids,
user_id=user.id,
)
@@ -118,7 +120,7 @@ def delete_document_type(
user: Annotated[
schemas.User, Security(get_current_user, scopes=[scopes.DOCUMENT_TYPE_DELETE])
],
- db_session: db.Session = Depends(db.get_session),
+ db_session: Session = Depends(get_session),
) -> None:
"""Deletes document type
@@ -140,7 +142,7 @@ def update_document_type(
cur_user: Annotated[
schemas.User, Security(get_current_user, scopes=[scopes.DOCUMENT_TYPE_UPDATE])
],
- db_session: db.Session = Depends(db.get_session),
+ db_session: Session = Depends(get_session),
) -> schemas.DocumentType:
"""Updates document type
diff --git a/papermerge/core/schemas/document_types.py b/papermerge/core/features/document_types/schema.py
similarity index 74%
rename from papermerge/core/schemas/document_types.py
rename to papermerge/core/features/document_types/schema.py
index 362c76269..7f2bb377c 100644
--- a/papermerge/core/schemas/document_types.py
+++ b/papermerge/core/features/document_types/schema.py
@@ -2,12 +2,13 @@
from pydantic import BaseModel, ConfigDict
-from .custom_fields import CustomField
+from papermerge.core.schemas.custom_fields import CustomField
class DocumentType(BaseModel):
id: UUID
name: str
+ path_template: str | None = None
custom_fields: list[CustomField]
# Config
@@ -16,6 +17,7 @@ class DocumentType(BaseModel):
class CreateDocumentType(BaseModel):
name: str
+ path_template: str | None = None
custom_field_ids: list[UUID]
# Config
@@ -24,4 +26,5 @@ class CreateDocumentType(BaseModel):
class UpdateDocumentType(BaseModel):
name: str | None = None
+ path_template: str | None = None
custom_field_ids: list[UUID] | None = None
diff --git a/papermerge/core/features/document_types/tests/conftest.py b/papermerge/core/features/document_types/tests/conftest.py
new file mode 100644
index 000000000..d457df8fa
--- /dev/null
+++ b/papermerge/core/features/document_types/tests/conftest.py
@@ -0,0 +1,76 @@
+import pytest
+from fastapi import FastAPI
+from fastapi.testclient import TestClient
+from sqlalchemy.orm import Session
+
+from papermerge.core import schemas
+from papermerge.core.auth.scopes import SCOPES
+from papermerge.core.db import create_custom_field
+from papermerge.core.db.engine import engine
+from papermerge.core.features.document_types import db
+from papermerge.core.models import User
+from papermerge.core.routers import register_routers as reg_core_routers
+from papermerge.core.schemas import CustomFieldType
+from papermerge.core.utils import base64
+from papermerge.test.baker_recipes import user_recipe
+from papermerge.test.types import AuthTestClient
+
+
+@pytest.fixture()
+def auth_api_client(user: User):
+ app = FastAPI()
+ reg_core_routers(app)
+
+ middle_part = base64.encode(
+ {
+ "sub": str(user.id),
+ "preferred_username": user.username,
+ "email": user.email,
+ "scopes": list(SCOPES.keys()),
+ }
+ )
+ token = f"abc.{middle_part}.xyz"
+
+ test_client = TestClient(app, headers={"Authorization": f"Bearer {token}"})
+
+ return AuthTestClient(test_client=test_client, user=user)
+
+
+@pytest.fixture
+def make_custom_field(db_session: Session, user: User):
+ def _make_custom_field(name: str, type: schemas.CustomFieldType):
+ return create_custom_field(
+ db_session,
+ name=name,
+ type=type,
+ user_id=user.id,
+ )
+
+ return _make_custom_field
+
+
+@pytest.fixture
+def make_document_type(db_session: Session, user: User, make_custom_field):
+ cf = make_custom_field(name="some-random-cf", type=CustomFieldType.boolean)
+
+ def _make_document_type(name: str, path_template: str | None = None):
+ return db.create_document_type(
+ db_session,
+ name=name,
+ custom_field_ids=[cf.id],
+ path_template=path_template,
+ user_id=user.id,
+ )
+
+ return _make_document_type
+
+
+@pytest.fixture()
+def user() -> User:
+ return user_recipe.make()
+
+
+@pytest.fixture()
+def db_session():
+ with Session(engine) as session:
+ yield session
diff --git a/tests/core/routes/test_document_types.py b/papermerge/core/features/document_types/tests/test_router.py
similarity index 58%
rename from tests/core/routes/test_document_types.py
rename to papermerge/core/features/document_types/tests/test_router.py
index d6509145b..3e8cd4852 100644
--- a/tests/core/routes/test_document_types.py
+++ b/papermerge/core/features/document_types/tests/test_router.py
@@ -3,10 +3,54 @@
from sqlalchemy.orm import Session
from papermerge.core import schemas
-from papermerge.core.db import models
+from papermerge.core.features.document_types.db import DocumentType
from papermerge.test.types import AuthTestClient
+@pytest.mark.django_db(transaction=True)
+def test_create_document_type_with_path_template(
+ auth_api_client: AuthTestClient, db_session: Session
+):
+ count_before = db_session.query(func.count(DocumentType.id)).scalar()
+ assert count_before == 0
+
+ response = auth_api_client.post(
+ "/document-types/",
+ json={
+ "name": "Invoice",
+ "path_template": "/home/My ZDF/",
+ "custom_field_ids": [],
+ },
+ )
+
+ assert response.status_code == 201, response.json()
+
+ count_after = db_session.query(func.count(DocumentType.id)).scalar()
+ assert count_after == 1
+
+ document_type = schemas.DocumentType.model_validate(response.json())
+ assert document_type.name == "Invoice"
+ assert document_type.path_template == "/home/My ZDF/"
+
+
+@pytest.mark.django_db(transaction=True)
+def test_update_document_type_with_path_template(
+ make_document_type, auth_api_client: AuthTestClient, db_session: Session
+):
+ doc_type = make_document_type(name="ZDF", path_template="/home/")
+ response = auth_api_client.patch(
+ f"/document-types/{doc_type.id}",
+ json={
+ "name": "Invoice",
+ "path_template": "/home/My ZDF/updated/",
+ "custom_field_ids": [],
+ },
+ )
+
+ document_type = schemas.DocumentType.model_validate(response.json())
+ assert document_type.path_template == "/home/My ZDF/updated/"
+
+
@pytest.mark.django_db(transaction=True)
def test_create_document_type(
make_custom_field, auth_api_client: AuthTestClient, db_session: Session
@@ -14,7 +58,7 @@ def test_create_document_type(
cf1: schemas.CustomField = make_custom_field(name="shop", type="text")
cf2: schemas.CustomField = make_custom_field(name="total", type="monetary")
- count_before = db_session.query(func.count(models.DocumentType.id)).scalar()
+ count_before = db_session.query(func.count(DocumentType.id)).scalar()
assert count_before == 0
response = auth_api_client.post(
@@ -24,7 +68,7 @@ def test_create_document_type(
assert response.status_code == 201, response.json()
- count_after = db_session.query(func.count(models.DocumentType.id)).scalar()
+ count_after = db_session.query(func.count(DocumentType.id)).scalar()
assert count_after == 1
document_type = schemas.DocumentType.model_validate(response.json())
@@ -72,11 +116,11 @@ def test_delete_document_type(
make_document_type,
):
doc_type = make_document_type(name="Invoice")
- count_before = db_session.query(func.count(models.DocumentType.id)).scalar()
+ count_before = db_session.query(func.count(DocumentType.id)).scalar()
assert count_before == 1
response = auth_api_client.delete(f"/document-types/{doc_type.id}")
assert response.status_code == 204, response.json()
- count_after = db_session.query(func.count(models.DocumentType.id)).scalar()
+ count_after = db_session.query(func.count(DocumentType.id)).scalar()
assert count_after == 0
diff --git a/papermerge/core/migrations/0004_documenttype_path_template.py b/papermerge/core/migrations/0004_documenttype_path_template.py
new file mode 100644
index 000000000..9aa3ff124
--- /dev/null
+++ b/papermerge/core/migrations/0004_documenttype_path_template.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.13 on 2024-10-18 09:35
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0003_alter_customfield_type"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="documenttype",
+ name="path_template",
+ field=models.CharField(max_length=2048, null=True),
+ ),
+ ]
diff --git a/papermerge/core/models/document.py b/papermerge/core/models/document.py
index 8d2c3febf..8a42b4d53 100644
--- a/papermerge/core/models/document.py
+++ b/papermerge/core/models/document.py
@@ -9,6 +9,7 @@
from pikepdf import Pdf
from papermerge.core import constants as const
+from papermerge.core.features.document_types.models import DocumentType
from papermerge.core.lib.path import DocumentPath, PagePath
from papermerge.core.lib.storage import copy_file
from papermerge.core.models import utils
@@ -22,7 +23,6 @@
from papermerge.core.storage import abs_path
from papermerge.core.utils import image as image_utils
-from .document_type import DocumentType
from .document_version import DocumentVersion
from .node import BaseTreeNode
from .page import Page
diff --git a/papermerge/core/models/document_type_custom_field.py b/papermerge/core/models/document_type_custom_field.py
index 98f65a92c..1cedb9c37 100644
--- a/papermerge/core/models/document_type_custom_field.py
+++ b/papermerge/core/models/document_type_custom_field.py
@@ -1,7 +1,8 @@
from django.db import models
+from papermerge.core.features.document_types.models import DocumentType
+
from .custom_field import CustomField
-from .document_type import DocumentType
class DocumentTypeCustomField(models.Model):
diff --git a/papermerge/core/routers/__init__.py b/papermerge/core/routers/__init__.py
index 7cffe0d4c..f34d2797b 100644
--- a/papermerge/core/routers/__init__.py
+++ b/papermerge/core/routers/__init__.py
@@ -4,10 +4,12 @@
from django.conf import settings
from fastapi import FastAPI
+from papermerge.core.features.document_types.router import (
+ router as document_types_router,
+)
from papermerge.core.log import log_task_routes
from .custom_fields import router as custom_fields_router
-from .document_types import router as document_types_router
from .document_version import router as document_versions_router
from .documents import router as documents_router
from .folders import router as folders_router
diff --git a/papermerge/core/schemas/__init__.py b/papermerge/core/schemas/__init__.py
index 25ad02357..9122134f1 100644
--- a/papermerge/core/schemas/__init__.py
+++ b/papermerge/core/schemas/__init__.py
@@ -1,5 +1,11 @@
from pydantic import BaseModel
+from papermerge.core.features.document_types.schema import (
+ CreateDocumentType,
+ DocumentType,
+ UpdateDocumentType,
+)
+
from .custom_fields import (
CFV,
CreateCustomField,
@@ -9,7 +15,6 @@
DocumentCFV,
UpdateCustomField,
)
-from .document_types import CreateDocumentType, DocumentType, UpdateDocumentType
from .documents import (
CreateDocument,
Document,
diff --git a/pyproject.toml b/pyproject.toml
index 9d536a1b0..97c98e4d9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -102,7 +102,7 @@ model-bakery = "^1.5.0"
pytest-asyncio = "^0.21.0"
[tool.taskipy.tasks]
-test = "DJANGO_SETTINGS_MODULE=tests.settings PAPERMERGE__MAIN__API_PREFIX='' pytest tests/ --disable-warnings"
+test = "DJANGO_SETTINGS_MODULE=tests.settings PAPERMERGE__MAIN__API_PREFIX='' pytest"
# run following commands from docker/dev only
worker = "celery -A config worker -c 5"
server = "uvicorn config.asgi:fastapp --app-dir docker/dev/ --log-config docker/cloud/etc/logging.yaml"
diff --git a/tests/conftest.py b/tests/conftest.py
index 7bf289ba6..b74ddbc05 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -6,6 +6,7 @@
from papermerge.core import db, schemas
from papermerge.core.auth.scopes import SCOPES
+from papermerge.core.features.document_types.db import create_document_type
from papermerge.core.models import User
from papermerge.core.routers import register_routers as reg_core_routers
from papermerge.core.schemas import CustomFieldType
@@ -91,7 +92,7 @@ def make_document_type(db_session: Session, user: User, make_custom_field):
cf = make_custom_field(name="some-random-cf", type=CustomFieldType.boolean)
def _make_document_type(name: str):
- return db.create_document_type(
+ return create_document_type(
db_session,
name=name,
custom_field_ids=[cf.id],
@@ -107,7 +108,7 @@ def document_type_groceries(db_session: Session, user: User, make_custom_field):
cf2 = make_custom_field(name="Total", type=CustomFieldType.monetary)
cf3 = make_custom_field(name="EffectiveDate", type=CustomFieldType.date)
- return db.create_document_type(
+ return create_document_type(
db_session,
name="Groceries",
custom_field_ids=[cf1.id, cf2.id, cf3.id],
@@ -135,7 +136,7 @@ def document_type_with_two_integer_cf(
cf1 = make_custom_field(name="int-name1", type=CustomFieldType.int)
cf2 = make_custom_field(name="int-name2", type=CustomFieldType.int)
- return db.create_document_type(
+ return create_document_type(
db_session,
name="document_type_with_two_integer_cf",
custom_field_ids=[cf1.id, cf2.id],
@@ -149,7 +150,7 @@ def document_type_with_one_date_cf( # cf = custom field
):
cf1 = make_custom_field(name="date-name1", type=CustomFieldType.date)
- return db.create_document_type(
+ return create_document_type(
db_session,
name="document_type_with_one_date_cf",
custom_field_ids=[cf1.id],
@@ -163,7 +164,7 @@ def document_type_with_one_string_cf( # cf = custom field
):
cf1 = make_custom_field(name="string-name1", type=CustomFieldType.text)
- return db.create_document_type(
+ return create_document_type(
db_session,
name="document_type_with_one_string_cf",
custom_field_ids=[cf1.id],
diff --git a/tests/core/models/test_document.py b/tests/core/models/test_document.py
index c6e56aacb..9cbe53928 100644
--- a/tests/core/models/test_document.py
+++ b/tests/core/models/test_document.py
@@ -15,6 +15,7 @@
from papermerge.core import db, schemas
from papermerge.core.db.doc import str2date
from papermerge.core.db.models import CustomField, CustomFieldValue
+from papermerge.core.features.document_types import db as db_dtype_api
from papermerge.core.models import Document, User
from papermerge.core.storage import abs_path
from papermerge.core.types import OrderEnum
@@ -587,7 +588,7 @@ def test_get_docs_by_type_missmatching_type(db_session: Session, make_document_r
CustomField.name.in_(["Total", "EffectiveDate"])
)
custom_field_ids = list([row.id for row in db_session.execute(stmt)])
- billType = db.create_document_type(
+ billType = db_dtype_api.create_document_type(
db_session,
name="Bill",
custom_field_ids=custom_field_ids,
@@ -754,26 +755,30 @@ def test_document_type_cf_count_1(db_session: Session, user: User, make_custom_f
name="some-random-cf2", type=schemas.CustomFieldType.boolean
)
- dtype1 = db.create_document_type(
+ dtype1 = db_dtype_api.create_document_type(
db_session,
name="document_type_1",
custom_field_ids=[cf1.id, cf2.id],
user_id=user.id,
)
- assert db.document_type_cf_count(db_session, document_type_id=dtype1.id) == 2
+ assert (
+ db_dtype_api.document_type_cf_count(db_session, document_type_id=dtype1.id) == 2
+ )
@pytest.mark.django_db(transaction=True)
def test_document_type_cf_count_without_cf(db_session: Session, user: User):
# document type does not have any custom field associated
- dtype1 = db.create_document_type(
+ dtype1 = db_dtype_api.create_document_type(
db_session,
name="document_type_1",
user_id=user.id,
)
- actual_cf_count = db.document_type_cf_count(db_session, document_type_id=dtype1.id)
+ actual_cf_count = db_dtype_api.document_type_cf_count(
+ db_session, document_type_id=dtype1.id
+ )
assert actual_cf_count == 0
@@ -784,7 +789,7 @@ def test_get_docs_count_by_type(db_session, user: User):
2. Expected result should be that number of the documents in this
type is 0
"""
- dtype1 = db.create_document_type(
+ dtype1 = db_dtype_api.create_document_type(
db_session,
name="document_type_1",
user_id=user.id,
@@ -801,7 +806,7 @@ def test_get_docs_count_by_type_with_two_document(db_session, user: User):
and validate that `db.get_docs_count_by_type` returns 2
"""
DOCS_COUNT = 2
- dtype = db.create_document_type(
+ dtype = db_dtype_api.create_document_type(
db_session,
name="document_type_1",
user_id=user.id,
diff --git a/ui2/src/features/document-types/apiSlice.ts b/ui2/src/features/document-types/apiSlice.ts
index 3f0c92438..14d9cffa5 100644
--- a/ui2/src/features/document-types/apiSlice.ts
+++ b/ui2/src/features/document-types/apiSlice.ts
@@ -1,11 +1,6 @@
import {apiSlice} from "@/features/api/slice"
-import type {
- DocType,
- DocTypeUpdate,
- NewDocType,
- Paginated,
- PaginatedArgs
-} from "@/types"
+import type {Paginated, PaginatedArgs} from "@/types"
+import type {DocType, DocTypeUpdate, NewDocType} from "./types"
import {PAGINATION_DEFAULT_ITEMS_PER_PAGES} from "@/cconstants"
diff --git a/ui2/src/features/document-types/components/Details.tsx b/ui2/src/features/document-types/components/Details.tsx
index b7c91523b..f52fe343c 100644
--- a/ui2/src/features/document-types/components/Details.tsx
+++ b/ui2/src/features/document-types/components/Details.tsx
@@ -2,7 +2,7 @@ import {Box, Breadcrumbs, Group, Loader, LoadingOverlay} from "@mantine/core"
import {Link, useNavigation} from "react-router-dom"
import {useGetDocumentTypeQuery} from "@/features/document-types/apiSlice"
-import type {DocType} from "@/types"
+import type {DocType} from "../types"
import {DeleteDocumentTypeButton} from "./DeleteButton"
import DocumentTypeForm from "./DocumentTypeForm"
import EditButton from "./EditButton"
diff --git a/ui2/src/features/document-types/components/DocumentTypeForm.tsx b/ui2/src/features/document-types/components/DocumentTypeForm.tsx
index a78f29c6f..a8b2f2329 100644
--- a/ui2/src/features/document-types/components/DocumentTypeForm.tsx
+++ b/ui2/src/features/document-types/components/DocumentTypeForm.tsx
@@ -1,6 +1,14 @@
import CopyButton from "@/components/CopyButton"
-import type {CustomField, DocType} from "@/types"
-import {Box, Fieldset, Skeleton, Table, TextInput} from "@mantine/core"
+import type {CustomField} from "@/types"
+import {
+ Box,
+ Fieldset,
+ Skeleton,
+ Table,
+ TextInput,
+ Textarea
+} from "@mantine/core"
+import type {DocType} from "../types"
type Args = {
documentType: DocType | null
@@ -29,6 +37,14 @@ export default function DocumentTypeForm({documentType}: Args) {
{hasCustomFields && (
)}
+