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 && ( )} +