Compare commits
2 Commits
a9e9f97c14
...
ea5093f2c2
| Author | SHA1 | Date | |
|---|---|---|---|
| ea5093f2c2 | |||
| b542fd40a6 |
@@ -7,7 +7,8 @@ from beanie import PydanticObjectId
|
|||||||
from pydantic import BaseModel, Field, ConfigDict
|
from pydantic import BaseModel, Field, ConfigDict
|
||||||
from pydantic.json_schema import SkipJsonSchema
|
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.core.filter import Filter, FilterSchema
|
||||||
from firm.entity.models import Entity
|
from firm.entity.models import Entity
|
||||||
|
|
||||||
@@ -98,15 +99,6 @@ class ContractDraft(CrudDocument):
|
|||||||
status: ContractDraftStatus = Field(default=ContractDraftStatus.in_progress, title="Statut")
|
status: ContractDraftStatus = Field(default=ContractDraftStatus.in_progress, title="Statut")
|
||||||
todo: List[str] = Field(default=[], title="Reste à faire")
|
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):
|
async def check_is_ready(self, db):
|
||||||
if self.status == ContractDraftStatus.published:
|
if self.status == ContractDraftStatus.published:
|
||||||
return
|
return
|
||||||
@@ -150,6 +142,11 @@ class Contract(CrudDocument):
|
|||||||
Contrat publié. Les contrats ne peuvent pas être modifiés.
|
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
|
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")
|
name: str = Field(title="Nom")
|
||||||
title: str = Field(title="Titre")
|
title: str = Field(title="Titre")
|
||||||
parties: List[Party] = Field(title="Parties")
|
parties: List[Party] = Field(title="Parties")
|
||||||
@@ -170,15 +167,6 @@ class Contract(CrudDocument):
|
|||||||
contract_label = f"{contract_label} - {self.date.strftime('%m/%d/%Y')}"
|
contract_label = f"{contract_label} - {self.date.strftime('%m/%d/%Y')}"
|
||||||
return contract_label
|
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
|
@classmethod
|
||||||
async def find_by_signature_id(cls, db, signature_id: UUID):
|
async def find_by_signature_id(cls, db, signature_id: UUID):
|
||||||
request = {'parties': {"$elemMatch": {"signature_uuid": str(signature_id) }}}
|
request = {'parties': {"$elemMatch": {"signature_uuid": str(signature_id) }}}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from fastapi import HTTPException, Depends
|
|||||||
|
|
||||||
from hub.auth import get_current_user
|
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.db import get_db_client
|
||||||
from firm.entity.models import Entity
|
from firm.entity.models import Entity
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ class Registry:
|
|||||||
self.instance = instance
|
self.instance = instance
|
||||||
self.firm = firm
|
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):
|
async def set_user(self, user):
|
||||||
for firm in user.firms:
|
for firm in user.firms:
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
from datetime import datetime, UTC
|
from datetime import datetime, UTC
|
||||||
from typing import Optional
|
from typing import Optional, TypedDict, ClassVar
|
||||||
|
|
||||||
from beanie import PydanticObjectId
|
from beanie import PydanticObjectId
|
||||||
from motor.motor_asyncio import AsyncIOMotorCollection
|
from motor.motor_asyncio import AsyncIOMotorCollection
|
||||||
from pydantic import BaseModel, Field, computed_field
|
from pydantic import BaseModel, Field, computed_field
|
||||||
|
|
||||||
|
class CrudDocumentConfig(TypedDict, total=False):
|
||||||
|
fulltext_search: list[str]
|
||||||
|
indexes: list[str]
|
||||||
|
|
||||||
|
|
||||||
class CrudDocument(BaseModel):
|
class CrudDocument(BaseModel):
|
||||||
|
document_config: ClassVar[CrudDocumentConfig] = CrudDocumentConfig()
|
||||||
|
|
||||||
id: Optional[PydanticObjectId] = Field(default=None)
|
id: Optional[PydanticObjectId] = Field(default=None)
|
||||||
created_at: datetime = Field(default=datetime.now(UTC), nullable=False, title="Créé le")
|
created_at: datetime = Field(default=datetime.now(UTC), nullable=False, title="Créé le")
|
||||||
created_by: Optional[PydanticObjectId] = Field(default=None, title="Créé par")
|
created_by: Optional[PydanticObjectId] = Field(default=None, title="Créé par")
|
||||||
@@ -17,16 +23,13 @@ class CrudDocument(BaseModel):
|
|||||||
def _id(self):
|
def _id(self):
|
||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
@computed_field
|
@computed_field(title="Label")
|
||||||
def label(self) -> str:
|
def label(self) -> str:
|
||||||
return self.compute_label()
|
return self.compute_label()
|
||||||
|
|
||||||
def compute_label(self) -> str:
|
def compute_label(self) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
class Settings:
|
|
||||||
fulltext_search = []
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _collection_name(cls):
|
def _collection_name(cls):
|
||||||
return cls.__name__
|
return cls.__name__
|
||||||
@@ -35,6 +38,10 @@ class CrudDocument(BaseModel):
|
|||||||
def _get_collection(cls, db) -> AsyncIOMotorCollection:
|
def _get_collection(cls, db) -> AsyncIOMotorCollection:
|
||||||
return db.get_collection(cls._collection_name())
|
return db.get_collection(cls._collection_name())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_index(cls, db, index):
|
||||||
|
cls._get_collection(db).create_index(index)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create(cls, db, create_schema):
|
async def create(cls, db, create_schema):
|
||||||
model_dict = create_schema.model_dump() | {"created_by": db.partner.id, "updated_by": db.partner.id}
|
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})
|
await cls._get_collection(db).delete_one({"_id": model.id})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def text_area(*args, **kwargs):
|
def text_area(*args, **kwargs):
|
||||||
kwargs['widget'] = {
|
kwargs['widget'] = {
|
||||||
"formlyConfig": {
|
"formlyConfig": {
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ from typing import Any
|
|||||||
from beanie import PydanticObjectId
|
from beanie import PydanticObjectId
|
||||||
from pydantic import Field
|
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.core.schemas import Writer, Reader
|
||||||
from firm.entity.schemas import EntityIndividualCreate, EntityCorporationCreate, EntityRead
|
from firm.entity.schemas import EntityIndividualCreate, EntityCorporationCreate, EntityRead
|
||||||
|
|
||||||
|
class CurrentFirm(CrudDocument):
|
||||||
class CurrentFirmModel(CrudDocument):
|
|
||||||
instance: str = Field()
|
instance: str = Field()
|
||||||
firm: str = Field()
|
firm: str = Field()
|
||||||
entity_id: PydanticObjectId = Field()
|
entity_id: PydanticObjectId = Field()
|
||||||
@@ -60,6 +59,10 @@ class CurrentFirmSchemaUpdate(Writer):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class Partner(CrudDocument):
|
class Partner(CrudDocument):
|
||||||
|
document_config = CrudDocumentConfig(
|
||||||
|
indexes=["user_id", "entity_id"],
|
||||||
|
)
|
||||||
|
|
||||||
user_id: PydanticObjectId = Field()
|
user_id: PydanticObjectId = Field()
|
||||||
entity_id: PydanticObjectId = Field()
|
entity_id: PydanticObjectId = Field()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
from firm.core.depends import get_authed_tenant_registry, get_uninitialized_registry
|
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.models import Entity, Employee
|
||||||
from firm.entity.schemas import EntityRead
|
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")
|
@current_firm_router.get("/", response_model=CurrentFirmSchemaRead, response_description=f"Current Firm records retrieved")
|
||||||
async def read(reg=Depends(get_authed_tenant_registry)) -> CurrentFirmSchemaRead:
|
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)
|
firm_entity = await Entity.get(reg.db, document.entity_id)
|
||||||
partner = await Partner.get_by_user_id(reg.db, reg.user.id)
|
partner = await Partner.get_by_user_id(reg.db, reg.user.id)
|
||||||
partner = await Entity.get(reg.db, partner.entity_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))
|
corporation_schema.entity_data.employees.append(Employee(entity_id=owner_entity.id, position=schema.position))
|
||||||
corp = await Entity.create(reg.db, corporation_schema)
|
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,
|
instance=reg.instance,
|
||||||
firm=reg.firm,
|
firm=reg.firm,
|
||||||
entity_id=corp.id,
|
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")
|
@current_firm_router.put("/", response_description=f"Current Firm record updated")
|
||||||
async def update(schema: CurrentFirmSchemaUpdate, reg=Depends(get_authed_tenant_registry)) -> CurrentFirmSchemaRead:
|
async def update(schema: CurrentFirmSchemaUpdate, reg=Depends(get_authed_tenant_registry)) -> CurrentFirmSchemaRead:
|
||||||
document = await CurrentFirmModel.get_current(reg.db)
|
document = await CurrentFirm.get_current(reg.db)
|
||||||
document = await CurrentFirmModel.update(reg.db, document, schema)
|
document = await CurrentFirm.update(reg.db, document, schema)
|
||||||
return CurrentFirmSchemaRead.from_model(document)
|
return CurrentFirmSchemaRead.from_model(document)
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ client = motor.motor_asyncio.AsyncIOMotorClient(
|
|||||||
DATABASE_URL, uuidRepresentation="standard"
|
DATABASE_URL, uuidRepresentation="standard"
|
||||||
)
|
)
|
||||||
|
|
||||||
async def init_db():
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def stop_db():
|
async def stop_db():
|
||||||
client.close()
|
client.close()
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from datetime import date, datetime
|
from datetime import date
|
||||||
from typing import List, Literal, Optional
|
from typing import List, Literal, Optional
|
||||||
|
|
||||||
from pydantic import Field, BaseModel, ConfigDict
|
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.models import CrudDocument, ForeignKey
|
||||||
from firm.core.filter import Filter, FilterSchema
|
from firm.core.filter import Filter, FilterSchema
|
||||||
@@ -18,10 +18,10 @@ class Individual(EntityType):
|
|||||||
model_config = ConfigDict(title='Particulier')
|
model_config = ConfigDict(title='Particulier')
|
||||||
|
|
||||||
type: Literal['individual'] = 'individual'
|
type: Literal['individual'] = 'individual'
|
||||||
firstname: Indexed(str) = Field(title='Prénom')
|
firstname: str = Field(title='Prénom')
|
||||||
middlename: Indexed(str) = Field(default="", title='Autres prénoms')
|
middlename: str = Field(default="", title='Autres prénoms')
|
||||||
lastname: Indexed(str) = Field(title='Nom de famille')
|
lastname: str = Field(title='Nom de famille')
|
||||||
surnames: List[Indexed(str)] = Field(
|
surnames: List[str] = Field(
|
||||||
default=[],
|
default=[],
|
||||||
props={"items_per_row": "4", "numbered": True},
|
props={"items_per_row": "4", "numbered": True},
|
||||||
title="Surnoms"
|
title="Surnoms"
|
||||||
@@ -32,14 +32,14 @@ class Individual(EntityType):
|
|||||||
@property
|
@property
|
||||||
def label(self) -> str:
|
def label(self) -> str:
|
||||||
# if len(self.surnames) > 0:
|
# 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}"
|
return f"{self.firstname} {self.lastname}"
|
||||||
|
|
||||||
|
|
||||||
class Employee(BaseModel):
|
class Employee(BaseModel):
|
||||||
model_config = ConfigDict(title='Fiche Employé')
|
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é')
|
entity_id: PydanticObjectId = ForeignKey("entities", "Entity", title='Employé')
|
||||||
|
|
||||||
|
|
||||||
@@ -47,8 +47,8 @@ class Corporation(EntityType):
|
|||||||
model_config = ConfigDict(title='Entreprise')
|
model_config = ConfigDict(title='Entreprise')
|
||||||
|
|
||||||
type: Literal['corporation'] = 'corporation'
|
type: Literal['corporation'] = 'corporation'
|
||||||
title: Indexed(str) = Field(title='Dénomination sociale')
|
title: str = Field(title='Dénomination sociale')
|
||||||
activity: Indexed(str) = Field(title='Activité')
|
activity: str = Field(title='Activité')
|
||||||
employees: List[Employee] = Field(default=[], title='Employés')
|
employees: List[Employee] = Field(default=[], title='Employés')
|
||||||
|
|
||||||
|
|
||||||
@@ -72,15 +72,6 @@ class Entity(CrudDocument):
|
|||||||
return ""
|
return ""
|
||||||
return self.entity_data.label
|
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 EntityFilters(FilterSchema):
|
||||||
class Constants(Filter.Constants):
|
class Constants(Filter.Constants):
|
||||||
|
|||||||
31
api/rpk-api/firm/init_db.py
Normal file
31
api/rpk-api/firm/init_db.py
Normal 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()
|
||||||
@@ -36,9 +36,6 @@ class ProvisionTemplate(CrudDocument):
|
|||||||
def compute_label(self) -> str:
|
def compute_label(self) -> str:
|
||||||
return f"{self.name} - \"{unescape(remove_html_tags(self.title))}\""
|
return f"{self.name} - \"{unescape(remove_html_tags(self.title))}\""
|
||||||
|
|
||||||
class Settings(CrudDocument.Settings):
|
|
||||||
fulltext_search = ['name', 'title', 'body']
|
|
||||||
|
|
||||||
|
|
||||||
class ProvisionTemplateReference(BaseModel):
|
class ProvisionTemplateReference(BaseModel):
|
||||||
model_config = ConfigDict(title="Clause")
|
model_config = ConfigDict(title="Clause")
|
||||||
@@ -67,9 +64,6 @@ class ContractTemplate(CrudDocument):
|
|||||||
def compute_label(self) -> str:
|
def compute_label(self) -> str:
|
||||||
return f"{self.name} - \"{unescape(remove_html_tags(self.title))}\""
|
return f"{self.name} - \"{unescape(remove_html_tags(self.title))}\""
|
||||||
|
|
||||||
class Settings(CrudDocument.Settings):
|
|
||||||
fulltext_search = ['name', 'title']
|
|
||||||
|
|
||||||
|
|
||||||
class ContractTemplateFilters(FilterSchema):
|
class ContractTemplateFilters(FilterSchema):
|
||||||
class Constants(Filter.Constants):
|
class Constants(Filter.Constants):
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from hub import hub_router
|
|||||||
from hub.db import init_db as hub_init_db
|
from hub.db import init_db as hub_init_db
|
||||||
|
|
||||||
from firm import firm_router
|
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__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -189,7 +189,7 @@
|
|||||||
},
|
},
|
||||||
"corporation": {
|
"corporation": {
|
||||||
"type": "Entreprise",
|
"type": "Entreprise",
|
||||||
"title": "Titre",
|
"title": "Dénomination sociale",
|
||||||
"activity": "Activité",
|
"activity": "Activité",
|
||||||
"employees": "Employés",
|
"employees": "Employés",
|
||||||
"resource_title": "Entreprise"
|
"resource_title": "Entreprise"
|
||||||
|
|||||||
Reference in New Issue
Block a user