Compare commits

...

2 Commits

Author SHA1 Message Date
ea5093f2c2 Handling mongo indexes in firm 2025-05-04 02:26:06 +02:00
b542fd40a6 Renaming Collection CurrentFirmModel to CurrentFirm 2025-05-04 00:26:22 +02:00
11 changed files with 75 additions and 65 deletions

View File

@@ -7,7 +7,8 @@ from beanie import PydanticObjectId
from pydantic import BaseModel, Field, ConfigDict
from pydantic.json_schema import SkipJsonSchema
from firm.core.models import CrudDocument, RichtextSingleline, RichtextMultiline, DictionaryEntry, ForeignKey
from firm.core.models import CrudDocument, RichtextSingleline, RichtextMultiline, DictionaryEntry, ForeignKey, \
CrudDocumentConfig
from firm.core.filter import Filter, FilterSchema
from firm.entity.models import Entity
@@ -98,15 +99,6 @@ class ContractDraft(CrudDocument):
status: ContractDraftStatus = Field(default=ContractDraftStatus.in_progress, title="Statut")
todo: List[str] = Field(default=[], title="Reste à faire")
class Settings(CrudDocument.Settings):
fulltext_search = ['name', 'title']
bson_encoders = {
datetime.date: lambda dt: dt if hasattr(dt, 'hour')
else datetime.datetime(year=dt.year, month=dt.month, day=dt.day,
hour=0, minute=0, second=0)
}
async def check_is_ready(self, db):
if self.status == ContractDraftStatus.published:
return
@@ -150,6 +142,11 @@ class Contract(CrudDocument):
Contrat publié. Les contrats ne peuvent pas être modifiés.
Ils peuvent seulement être signés par les parties et imprimés par l'avocat
"""
model_config = ConfigDict(title='Contrat')
document_config = CrudDocumentConfig(
indexes=["parties.signature_uuid"],
)
name: str = Field(title="Nom")
title: str = Field(title="Titre")
parties: List[Party] = Field(title="Parties")
@@ -170,15 +167,6 @@ class Contract(CrudDocument):
contract_label = f"{contract_label} - {self.date.strftime('%m/%d/%Y')}"
return contract_label
class Settings(CrudDocument.Settings):
fulltext_search = ['name', 'title']
bson_encoders = {
datetime.date: lambda dt: dt if hasattr(dt, 'hour')
else datetime.datetime(year=dt.year, month=dt.month, day=dt.day,
hour=0, minute=0, second=0)
}
@classmethod
async def find_by_signature_id(cls, db, signature_id: UUID):
request = {'parties': {"$elemMatch": {"signature_uuid": str(signature_id) }}}

View File

@@ -2,7 +2,7 @@ from fastapi import HTTPException, Depends
from hub.auth import get_current_user
from firm.current_firm import CurrentFirmModel, Partner
from firm.current_firm import CurrentFirm, Partner
from firm.db import get_db_client
from firm.entity.models import Entity
@@ -16,7 +16,7 @@ class Registry:
self.instance = instance
self.firm = firm
self.current_firm = CurrentFirmModel.get_current(self.db)
self.current_firm = CurrentFirm.get_current(self.db)
async def set_user(self, user):
for firm in user.firms:

View File

@@ -1,12 +1,18 @@
from datetime import datetime, UTC
from typing import Optional
from typing import Optional, TypedDict, ClassVar
from beanie import PydanticObjectId
from motor.motor_asyncio import AsyncIOMotorCollection
from pydantic import BaseModel, Field, computed_field
class CrudDocumentConfig(TypedDict, total=False):
fulltext_search: list[str]
indexes: list[str]
class CrudDocument(BaseModel):
document_config: ClassVar[CrudDocumentConfig] = CrudDocumentConfig()
id: Optional[PydanticObjectId] = Field(default=None)
created_at: datetime = Field(default=datetime.now(UTC), nullable=False, title="Créé le")
created_by: Optional[PydanticObjectId] = Field(default=None, title="Créé par")
@@ -17,16 +23,13 @@ class CrudDocument(BaseModel):
def _id(self):
return self.id
@computed_field
@computed_field(title="Label")
def label(self) -> str:
return self.compute_label()
def compute_label(self) -> str:
return ""
class Settings:
fulltext_search = []
@classmethod
def _collection_name(cls):
return cls.__name__
@@ -35,6 +38,10 @@ class CrudDocument(BaseModel):
def _get_collection(cls, db) -> AsyncIOMotorCollection:
return db.get_collection(cls._collection_name())
@classmethod
def create_index(cls, db, index):
cls._get_collection(db).create_index(index)
@classmethod
async def create(cls, db, create_schema):
model_dict = create_schema.model_dump() | {"created_by": db.partner.id, "updated_by": db.partner.id}
@@ -84,7 +91,6 @@ class CrudDocument(BaseModel):
await cls._get_collection(db).delete_one({"_id": model.id})
def text_area(*args, **kwargs):
kwargs['widget'] = {
"formlyConfig": {

View File

@@ -3,12 +3,11 @@ from typing import Any
from beanie import PydanticObjectId
from pydantic import Field
from firm.core.models import CrudDocument
from firm.core.models import CrudDocument, CrudDocumentConfig
from firm.core.schemas import Writer, Reader
from firm.entity.schemas import EntityIndividualCreate, EntityCorporationCreate, EntityRead
class CurrentFirmModel(CrudDocument):
class CurrentFirm(CrudDocument):
instance: str = Field()
firm: str = Field()
entity_id: PydanticObjectId = Field()
@@ -60,6 +59,10 @@ class CurrentFirmSchemaUpdate(Writer):
pass
class Partner(CrudDocument):
document_config = CrudDocumentConfig(
indexes=["user_id", "entity_id"],
)
user_id: PydanticObjectId = Field()
entity_id: PydanticObjectId = Field()

View File

@@ -1,7 +1,7 @@
from fastapi import APIRouter, Depends
from firm.core.depends import get_authed_tenant_registry, get_uninitialized_registry
from firm.current_firm import CurrentFirmModel, CurrentFirmSchemaRead, CurrentFirmSchemaCreate, CurrentFirmSchemaUpdate, Partner
from firm.current_firm import CurrentFirm, CurrentFirmSchemaRead, CurrentFirmSchemaCreate, CurrentFirmSchemaUpdate, Partner
from firm.entity.models import Entity, Employee
from firm.entity.schemas import EntityRead
@@ -9,7 +9,7 @@ current_firm_router = APIRouter()
@current_firm_router.get("/", response_model=CurrentFirmSchemaRead, response_description=f"Current Firm records retrieved")
async def read(reg=Depends(get_authed_tenant_registry)) -> CurrentFirmSchemaRead:
document = await CurrentFirmModel.get_current(reg.db)
document = await CurrentFirm.get_current(reg.db)
firm_entity = await Entity.get(reg.db, document.entity_id)
partner = await Partner.get_by_user_id(reg.db, reg.user.id)
partner = await Entity.get(reg.db, partner.entity_id)
@@ -31,7 +31,7 @@ async def create(schema: CurrentFirmSchemaCreate, reg=Depends(get_uninitialized_
corporation_schema.entity_data.employees.append(Employee(entity_id=owner_entity.id, position=schema.position))
corp = await Entity.create(reg.db, corporation_schema)
document = await CurrentFirmModel.create(reg.db, CurrentFirmModel(
document = await CurrentFirm.create(reg.db, CurrentFirm(
instance=reg.instance,
firm=reg.firm,
entity_id=corp.id,
@@ -42,6 +42,6 @@ async def create(schema: CurrentFirmSchemaCreate, reg=Depends(get_uninitialized_
@current_firm_router.put("/", response_description=f"Current Firm record updated")
async def update(schema: CurrentFirmSchemaUpdate, reg=Depends(get_authed_tenant_registry)) -> CurrentFirmSchemaRead:
document = await CurrentFirmModel.get_current(reg.db)
document = await CurrentFirmModel.update(reg.db, document, schema)
document = await CurrentFirm.get_current(reg.db)
document = await CurrentFirm.update(reg.db, document, schema)
return CurrentFirmSchemaRead.from_model(document)

View File

@@ -11,9 +11,6 @@ client = motor.motor_asyncio.AsyncIOMotorClient(
DATABASE_URL, uuidRepresentation="standard"
)
async def init_db():
pass
async def stop_db():
client.close()

View File

@@ -1,8 +1,8 @@
from datetime import date, datetime
from datetime import date
from typing import List, Literal, Optional
from pydantic import Field, BaseModel, ConfigDict
from beanie import Indexed, PydanticObjectId
from beanie import PydanticObjectId
from firm.core.models import CrudDocument, ForeignKey
from firm.core.filter import Filter, FilterSchema
@@ -18,10 +18,10 @@ class Individual(EntityType):
model_config = ConfigDict(title='Particulier')
type: Literal['individual'] = 'individual'
firstname: Indexed(str) = Field(title='Prénom')
middlename: Indexed(str) = Field(default="", title='Autres prénoms')
lastname: Indexed(str) = Field(title='Nom de famille')
surnames: List[Indexed(str)] = Field(
firstname: str = Field(title='Prénom')
middlename: str = Field(default="", title='Autres prénoms')
lastname: str = Field(title='Nom de famille')
surnames: List[str] = Field(
default=[],
props={"items_per_row": "4", "numbered": True},
title="Surnoms"
@@ -32,14 +32,14 @@ class Individual(EntityType):
@property
def label(self) -> str:
# if len(self.surnames) > 0:
# return '{} "{}" {}'.format(self.firstname, self.surnames[0], self.lastname)
# return f"{self.firstname} \"{self.surnames[0]}\" {self.lastname}"
return f"{self.firstname} {self.lastname}"
class Employee(BaseModel):
model_config = ConfigDict(title='Fiche Employé')
position: Indexed(str) = Field(title='Poste')
position: str = Field(title='Poste')
entity_id: PydanticObjectId = ForeignKey("entities", "Entity", title='Employé')
@@ -47,8 +47,8 @@ class Corporation(EntityType):
model_config = ConfigDict(title='Entreprise')
type: Literal['corporation'] = 'corporation'
title: Indexed(str) = Field(title='Dénomination sociale')
activity: Indexed(str) = Field(title='Activité')
title: str = Field(title='Dénomination sociale')
activity: str = Field(title='Activité')
employees: List[Employee] = Field(default=[], title='Employés')
@@ -72,15 +72,6 @@ class Entity(CrudDocument):
return ""
return self.entity_data.label
class Settings(CrudDocument.Settings):
fulltext_search = ['label']
bson_encoders = {
date: lambda dt: dt if hasattr(dt, 'hour')
else datetime(year=dt.year, month=dt.month, day=dt.day,
hour=0, minute=0, second=0)
}
class EntityFilters(FilterSchema):
class Constants(Filter.Constants):

View File

@@ -0,0 +1,31 @@
import logging
from firm.contract.models import Contract, ContractDraft
from firm.core.depends import Registry
from firm.current_firm import CurrentFirm, Partner
from firm.db import client
from firm.entity.models import Entity
from firm.template.models import ContractTemplate, ProvisionTemplate
from hub.firm import Firm
collections = [CurrentFirm, Entity, Partner, Contract, ContractDraft, ContractTemplate, ProvisionTemplate]
logger = logging.getLogger('uvicorn.error')
async def create_documents_indexes(db):
for collection in collections:
if "indexes" in collection.document_config:
for field in collection.document_config["indexes"]:
collection.create_index(db, field)
async def init_all_db():
logger.info("[FRM] Creating index for firms")
for firm in await Firm.find({}).to_list():
reg = Registry(client, firm.instance, firm.firm)
await reg.current_firm
await create_documents_indexes(reg.db)
async def init_db():
await init_all_db()

View File

@@ -36,9 +36,6 @@ class ProvisionTemplate(CrudDocument):
def compute_label(self) -> str:
return f"{self.name} - \"{unescape(remove_html_tags(self.title))}\""
class Settings(CrudDocument.Settings):
fulltext_search = ['name', 'title', 'body']
class ProvisionTemplateReference(BaseModel):
model_config = ConfigDict(title="Clause")
@@ -67,9 +64,6 @@ class ContractTemplate(CrudDocument):
def compute_label(self) -> str:
return f"{self.name} - \"{unescape(remove_html_tags(self.title))}\""
class Settings(CrudDocument.Settings):
fulltext_search = ['name', 'title']
class ContractTemplateFilters(FilterSchema):
class Constants(Filter.Constants):

View File

@@ -5,7 +5,7 @@ from hub import hub_router
from hub.db import init_db as hub_init_db
from firm import firm_router
from firm.db import init_db as firm_init_db
from firm.init_db import init_db as firm_init_db
if __name__ == '__main__':

View File

@@ -189,7 +189,7 @@
},
"corporation": {
"type": "Entreprise",
"title": "Titre",
"title": "Dénomination sociale",
"activity": "Activité",
"employees": "Employés",
"resource_title": "Entreprise"