Compare commits

...

5 Commits

Author SHA1 Message Date
872e27e7e4 Initializable Firm 2025-04-16 22:39:09 +02:00
5bdb754f1c Switching foreign jkey to PydanticObjectId 2025-04-16 22:38:06 +02:00
15b77ff09f Changing role to position in comployee model 2025-04-16 21:32:49 +02:00
b0c4128e01 Shaping CurrentFirmSchemaCreate arch 2025-04-16 19:43:00 +02:00
e5a2539ec6 Adding UiSchema capacities to CrudForm 2025-04-16 19:42:28 +02:00
10 changed files with 87 additions and 47 deletions

View File

@@ -3,6 +3,7 @@ from typing import List, Literal, Optional
from enum import Enum
from uuid import UUID
from beanie import PydanticObjectId
from pydantic import BaseModel, Field
from firm.core.models import CrudDocument, RichtextSingleline, RichtextMultiline, DictionaryEntry
@@ -24,7 +25,7 @@ class ContractDraftStatus(str, Enum):
class DraftParty(BaseModel):
entity_id: str = Field(
entity_id: PydanticObjectId = Field(
foreignKey={
"reference": {
"resource": "entity",
@@ -35,7 +36,7 @@ class DraftParty(BaseModel):
title="Partie"
)
part: str = Field(title="Rôle")
representative_id: str = Field(
representative_id: PydanticObjectId = Field(
foreignKey={
"reference": {
"resource": "entity",
@@ -73,7 +74,7 @@ class ProvisionGenuine(BaseModel):
class ContractProvisionTemplateReference(BaseModel):
type: Literal['template'] = ContractProvisionType.template
provision_template_id: str = Field(
provision_template_id: PydanticObjectId = Field(
foreignKey={
"reference": {
"resource": "template/provision",

View File

@@ -12,11 +12,11 @@ class Registry:
self.instance = instance
self.firm = firm
self.current_firm = CurrentFirmModel.get(self.db)
self.current_firm = CurrentFirmModel.get_current(self.db)
def set_user(self, user):
for firm in user.firms:
if firm.instance == self.instance and firm.firm == firm:
if firm.instance == self.instance and firm.firm == self.firm:
self.user = user
self.db.user = user
return

View File

@@ -9,9 +9,9 @@ from pydantic import BaseModel, Field, computed_field
class CrudDocument(BaseModel):
id: Optional[PydanticObjectId] = Field(default=None)
created_at: datetime = Field(default=datetime.now(UTC), nullable=False, title="Créé le")
created_by: str = Field(nullable=False, title="Créé par")
created_by: Optional[PydanticObjectId] = Field(default=None, title="Créé par")
updated_at: datetime = Field(default_factory=lambda: datetime.now(UTC), nullable=False, title="Modifié le")
updated_by: str = Field(nullable=False, title="Modifié par")
updated_by: Optional[PydanticObjectId] = Field(default=None, title="Modifié par")
@property
def _id(self):
@@ -37,7 +37,7 @@ class CrudDocument(BaseModel):
@classmethod
async def create(cls, db, create_schema):
model_dict = create_schema.model_dump() | {"created_by": db.user, "updated_by":db.user}
model_dict = create_schema.model_dump() | {"created_by": db.user.id, "updated_by": db.user.id}
document = cls.model_validate(model_dict).model_dump(mode="json")
result = await cls._get_collection(db).insert_one(document)
@@ -66,8 +66,9 @@ class CrudDocument(BaseModel):
@classmethod
async def update(cls, db, model, update_schema):
model_dict = update_schema.model_dump(mode="json") | {"updated_by": db.user.id}
update_query = {
"$set": {field: value for field, value in update_schema.model_dump(mode="json").items() if field!= "id" }
"$set": {field: value for field, value in model_dict.items() if field!= "id" }
}
await cls._get_collection(db).update_one({"_id": model.id}, update_query)

View File

@@ -1,5 +1,6 @@
from typing import Any
from beanie import PydanticObjectId
from pydantic import Field
from firm.core.models import CrudDocument
@@ -8,12 +9,11 @@ from firm.entity.schemas import EntityIndividualCreate, EntityCorporationCreate
class CurrentFirmModel(CrudDocument):
instance: str
firm: str
name: str = Field(nullable=False)
# primary_color: str = Field()
# secondary_color: str = Field()
instance: str = Field()
firm: str = Field()
entity_id: PydanticObjectId = Field()
primary_color: str = Field()
secondary_color: str = Field()
def __eq__(self, other: Any) -> bool:
if isinstance(other, dict):
@@ -21,10 +21,10 @@ class CurrentFirmModel(CrudDocument):
return super().__eq__(other)
def compute_label(self) -> str:
return self.name
return f"{self.instance} / {self.firm}"
@classmethod
async def get(cls, db):
async def get_current(cls, db):
document = await cls._get_collection(db).find_one({})
if not document:
return None
@@ -39,7 +39,15 @@ class CurrentFirmSchemaRead(Reader):
class CurrentFirmSchemaCreate(Writer):
corporation: EntityCorporationCreate = Field(title="Informations sur la firme")
owner: EntityIndividualCreate = Field(title="Informations sur le dirigeant")
position: str = Field(title="Poste")
primary_color: str = Field()
secondary_color: str = Field()
class CurrentFirmSchemaUpdate(Writer):
pass
class Partner(CrudDocument):
user_id: PydanticObjectId = Field()
entity_id: PydanticObjectId = Field()

View File

@@ -1,22 +1,36 @@
from fastapi import APIRouter, Depends
from firm.core.depends import get_logged_tenant_db_cursor, get_uninitialized_tenant_db_cursor
from firm.current_firm import CurrentFirmModel, CurrentFirmSchemaRead, CurrentFirmSchemaCreate, CurrentFirmSchemaUpdate
from firm.core.depends import get_authed_tenant_registry, get_uninitialized_registry
from firm.current_firm import CurrentFirmModel, CurrentFirmSchemaRead, CurrentFirmSchemaCreate, CurrentFirmSchemaUpdate, Partner
from firm.entity.models import Entity, Employee
current_firm_router = APIRouter()
@current_firm_router.get("/", response_model=CurrentFirmSchemaRead, response_description=f"Current Firm records retrieved")
async def read(db=Depends(get_logged_tenant_db_cursor)) -> CurrentFirmSchemaRead:
return CurrentFirmSchemaRead.from_model(**CurrentFirmModel.get(db))
async def read(reg=Depends(get_authed_tenant_registry)) -> CurrentFirmSchemaRead:
document = await CurrentFirmModel.get_current(reg.db)
return CurrentFirmSchemaRead.from_model(document)
@current_firm_router.post("/", response_description=f"Current Firm added to the database")
async def create(schema: CurrentFirmSchemaCreate, db=Depends(get_uninitialized_tenant_db_cursor)) -> CurrentFirmSchemaRead:
await schema.validate_foreign_key(db)
record = await CurrentFirmModel.create(db, schema)
return CurrentFirmSchemaRead.from_model(record)
async def create(schema: CurrentFirmSchemaCreate, reg=Depends(get_uninitialized_registry)) -> CurrentFirmSchemaRead:
owner_entity = await Entity.create(reg.db, schema.owner)
Partner.create(reg.db, Partner(user_id=reg.user.id, entity_id=owner_entity.id))
corporation_schema = schema.corporation
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(
instance=reg.instance,
firm=reg.firm,
entity_id=corp.id,
primary_color=schema.primary_color,
secondary_color=schema.secondary_color,
))
return await CurrentFirmSchemaRead.from_model(document)
@current_firm_router.put("/", response_description=f"Current Firm record updated")
async def update(schema: CurrentFirmSchemaUpdate, db=Depends(get_logged_tenant_db_cursor)) -> CurrentFirmSchemaRead:
record = await CurrentFirmModel.get(db)
record = await CurrentFirmModel.update(db, record, schema)
return CurrentFirmSchemaRead.from_model(record)
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)
return CurrentFirmSchemaRead.from_model(document)

View File

@@ -2,7 +2,7 @@ from datetime import date, datetime
from typing import List, Literal, Optional
from pydantic import Field, BaseModel
from beanie import Indexed
from beanie import Indexed, PydanticObjectId
from firm.core.models import CrudDocument
from firm.core.filter import Filter, FilterSchema
@@ -38,15 +38,16 @@ class Individual(EntityType):
class Employee(BaseModel):
role: Indexed(str) = Field(title='Poste')
entity_id: str = Field(foreignKey={
"reference": {
"resource": "entity",
"schema": "Entity",
"condition": "entity_data.type=individual"
}
},
title='Employé'
position: Indexed(str) = Field(title='Poste')
entity_id: PydanticObjectId = Field(
foreignKey={
"reference": {
"resource": "entity",
"schema": "Entity",
"condition": "entity_data.type=individual"
}
},
title='Employé'
)
class Config:

View File

@@ -1,6 +1,7 @@
from typing import List
from html import unescape
from beanie import PydanticObjectId
from pydantic import BaseModel, Field
from firm.core.models import CrudDocument, RichtextMultiline, RichtextSingleline, DictionaryEntry
@@ -8,7 +9,7 @@ from firm.core.filter import Filter, FilterSchema
class PartyTemplate(BaseModel):
entity_id: str = Field(
entity_id: PydanticObjectId = Field(
foreignKey={
"reference": {
"resource": "entity",
@@ -19,7 +20,7 @@ class PartyTemplate(BaseModel):
title="Partie"
)
part: str = Field(title="Rôle")
representative_id: str = Field(
representative_id: PydanticObjectId = Field(
foreignKey={
"reference": {
"resource": "entity",
@@ -61,7 +62,7 @@ class ProvisionTemplate(CrudDocument):
class ProvisionTemplateReference(BaseModel):
provision_template_id: str = Field(
provision_template_id: PydanticObjectId = Field(
foreignKey={
"reference": {
"resource": "template/provision",

View File

@@ -1,14 +1,15 @@
import validator from "@rjsf/validator-ajv8";
import Form from "@rjsf/mui";
import { RegistryFieldsType, RegistryWidgetsType } from "@rjsf/utils";
import { RegistryFieldsType, RegistryWidgetsType, UiSchema } from "@rjsf/utils";
import { useEffect, useState } from "react";
import { jsonschemaProvider } from "../providers/jsonschema-provider";
import { useForm } from "@refinedev/core";
import CrudTextWidget from "./widgets/crud-text-widget";
import UnionEnumField from "./fields/union-enum";
type Props = {
type CrudFormProps = {
schemaName: string,
uiSchema?: UiSchema,
resource: string,
id?: string,
//onSubmit: (data: IChangeEvent, event: FormEvent<any>) => void
@@ -23,7 +24,8 @@ const customFields: RegistryFieldsType = {
AnyOfField: UnionEnumField
}
export const CrudForm: React.FC<Props> = ({ schemaName, resource, id, onSuccess }) => {
export const CrudForm: React.FC<CrudFormProps> = (props) => {
const { schemaName, uiSchema, resource, id, onSuccess } = props;
const { onFinish, query, formLoading } = useForm({
resource: resource,
action: id === undefined ? "create" : "edit",
@@ -55,6 +57,7 @@ export const CrudForm: React.FC<Props> = ({ schemaName, resource, id, onSuccess
return (
<Form
schema={schema}
uiSchema={uiSchema === undefined ? {} : uiSchema}
formData={record}
onChange={(e) => setFormData(e.formData)}
onSubmit={(e) => onFinish(e.formData)}

View File

@@ -1,12 +1,16 @@
import {FormContextType, getTemplate, RJSFSchema, StrictRJSFSchema, WidgetProps} from "@rjsf/utils";
import ForeignKeyWidget from "./foreign-key";
import Typography from "@mui/material/Typography";
export default function CrudTextWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
props: WidgetProps<T, S, F>
) {
if (props.schema.hasOwnProperty("foreign_key")) {
const { schema } = props;
if (schema.hasOwnProperty("foreign_key")) {
return (<ForeignKeyWidget {...props} />);
} else if (schema.hasOwnProperty("const")) {
return <Typography >{schema.const as string}</Typography>;
} else {
const { options, registry } = props;
const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>('BaseInputTemplate', registry, options);

View File

@@ -49,7 +49,14 @@ const FirmInitForm = (props: FirmInitFormPros) => {
return (
<>
<h1>Initialization of {`${currentFirm.instance} / ${currentFirm.firm}`}</h1>
<CrudForm schemaName={"CurrentFirmSchemaCreate"} resource={`/firm/${currentFirm.instance}/${currentFirm.firm}`} />
<CrudForm
schemaName={"CurrentFirmSchemaCreate"}
resource={`firm/${currentFirm.instance}/${currentFirm.firm}/`}
uiSchema={{
corporation: {entity_data: {employees: {"ui:style": {"display": "none"}}}},
}}
/>
</>
)
}