From a288d32ec9f9d47ea3222948cd31e964f4c88f66 Mon Sep 17 00:00:00 2001 From: ewandor Date: Sat, 11 Feb 2023 18:07:50 +0100 Subject: [PATCH] Contract Drafts modules --- back/app/contract/models.py | 68 +++++++++++++------ back/app/contract/routes.py | 6 +- back/app/contract/schemas.py | 34 +++++----- back/app/db.py | 4 +- back/app/main.py | 2 +- front/app/src/app/app-routing.module.ts | 6 ++ .../app/layout/sidenav/sidenav.component.ts | 5 ++ .../contracts/contracts-routing.module.ts | 44 ++++++++++++ .../app/views/contracts/contracts.module.ts | 23 +++++++ .../app/views/contracts/drafts.component.ts | 39 +++++++++++ 10 files changed, 187 insertions(+), 44 deletions(-) create mode 100644 front/app/src/app/views/contracts/contracts-routing.module.ts create mode 100644 front/app/src/app/views/contracts/contracts.module.ts create mode 100644 front/app/src/app/views/contracts/drafts.component.ts diff --git a/back/app/contract/models.py b/back/app/contract/models.py index 21f8f2ad..cfc78bc8 100644 --- a/back/app/contract/models.py +++ b/back/app/contract/models.py @@ -1,16 +1,9 @@ -from datetime import datetime -from typing import List +from typing import List, Literal from enum import Enum from pydantic import BaseModel, Field -from beanie import Document -from ..entity.models import Entity - - -class ContractType(str, Enum): - employment = 'employment' - location = 'location' +from ..core.models import CrudDocument, RichtextSingleline, RichtextMultiline, DictionaryEntry class ContractStatus(str, Enum): @@ -20,21 +13,54 @@ class ContractStatus(str, Enum): executed = 'executed' +class ContractDraftStatus(str, Enum): + draft = 'draft' + created = 'created' + + class Party(BaseModel): - entity: Entity + entity_id: str = Field( + foreignKey={ + "reference": { + "resource": "entity", + "schema": "Entity", + } + } + ) part: str -class Clause(BaseModel): +class ProvisionGenuine(BaseModel): + type: Literal['genuine'] = 'genuine' + title: str = RichtextSingleline(props={"parametrized": True}) + body: str = RichtextMultiline(props={"parametrized": True}) + + +class ContractProvisionTemplateReference(BaseModel): + type: Literal['template'] = 'template' + provision_template_id: str = Field( + foreignKey={ + "reference": { + "resource": "template/provision", + "schema": "ProvisionTemplate", + "displayedFields": ['title', 'body'] + }, + }, + props={"parametrized": True} + ) + + +class DraftProvision(BaseModel): + provision: ContractProvisionTemplateReference | ProvisionGenuine = Field(..., discriminator='type') + + +class ContractDraft(CrudDocument): name: str - body: str - - -class Contract(Document): - _id: str - type: ContractType + title: str parties: List[Party] - clauses: List[Clause] - status: ContractStatus = Field(default=ContractStatus.new) - created_at: datetime = Field(default=datetime.utcnow(), nullable=False) - updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False) + provisions: List[DraftProvision] + variables: List[DictionaryEntry] = Field( + default=[], + format="dictionary", + ) + status: ContractDraftStatus = Field(default=ContractDraftStatus.draft) diff --git a/back/app/contract/routes.py b/back/app/contract/routes.py index 707a7909..54acb83a 100644 --- a/back/app/contract/routes.py +++ b/back/app/contract/routes.py @@ -1,5 +1,5 @@ from ..core.routes import get_crud_router -from .models import Contract -from .schemas import ContractCreate, ContractRead, ContractUpdate +from .models import ContractDraft +from .schemas import ContractDraftCreate, ContractDraftRead, ContractDraftUpdate -router = get_crud_router(Contract, ContractCreate, ContractRead, ContractUpdate) +router = get_crud_router(ContractDraft, ContractDraftCreate, ContractDraftRead, ContractDraftUpdate) diff --git a/back/app/contract/schemas.py b/back/app/contract/schemas.py index 1f1699e5..733764ff 100644 --- a/back/app/contract/schemas.py +++ b/back/app/contract/schemas.py @@ -1,36 +1,36 @@ -import uuid -from datetime import datetime + from typing import List -from pydantic import BaseModel, validator +from pydantic import Field -from beanie import PydanticObjectId +from .models import ContractDraft, DraftProvision, Party -from .models import Contract, ContractType, Clause from ..entity.models import Entity from ..core.schemas import Writer +from ..core.models import DictionaryEntry -class ContractRead(Contract): +class ContractDraftRead(ContractDraft): pass -class PartyCreate(BaseModel): - entity: PydanticObjectId - part: str - - -class ContractCreate(Writer): - type: ContractType - parties: List[PartyCreate] - clauses: List[Clause] +class ContractDraftCreate(Writer): + name: str + title: str + parties: List[Party] + provisions: List[DraftProvision] + variables: List[DictionaryEntry] = Field( + default=[], + format="dictionary", + ) async def validate_foreign_key(self): + return for p in self.parties: p.entity = await Entity.get(p.entity) if p.entity is None: raise ValueError -class ContractUpdate(BaseModel): - status: str +class ContractDraftUpdate(ContractDraftCreate): + pass diff --git a/back/app/db.py b/back/app/db.py index bdc7ee2d..8b987433 100644 --- a/back/app/db.py +++ b/back/app/db.py @@ -6,7 +6,7 @@ from .user import User, AccessToken from .entity.models import Entity from .template.models import ContractTemplate, ProvisionTemplate from .order.models import Order -from .contract.models import Contract +from .contract.models import ContractDraft DATABASE_URL = "mongodb://root:example@mongo:27017/" @@ -17,5 +17,5 @@ async def init_db(): ) await init_beanie(database=client.db_name, - document_models=[User, AccessToken, Entity, ContractTemplate, ProvisionTemplate, Order, Contract, ], + document_models=[User, AccessToken, Entity, ContractTemplate, ProvisionTemplate, ContractDraft, ], allow_index_dropping=True) diff --git a/back/app/main.py b/back/app/main.py index 2eb25bd4..1e51f1e7 100644 --- a/back/app/main.py +++ b/back/app/main.py @@ -25,7 +25,7 @@ app.include_router(user_router, prefix="/users", tags=["users"], ) app.include_router(entity_router, prefix="/entity", tags=["entity"], ) app.include_router(order_router, prefix="/order", tags=["order"], ) app.include_router(template_router, prefix="/template", tags=["template"], ) -app.include_router(contract_router, prefix="/contract", tags=["contract"], ) +app.include_router(contract_router, prefix="/contract-draft", tags=["contract-draft"], ) if __name__ == '__main__': import uvicorn diff --git a/front/app/src/app/app-routing.module.ts b/front/app/src/app/app-routing.module.ts index 82fa9221..4873a96a 100644 --- a/front/app/src/app/app-routing.module.ts +++ b/front/app/src/app/app-routing.module.ts @@ -1,5 +1,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; +import {ContractsModule} from "./views/contracts/contracts.module"; const routes: Routes = [ { @@ -29,6 +30,11 @@ const routes: Routes = [ loadChildren: () => import('./views/templates/templates.module').then((m) => m.TemplatesModule) }, + { + path: 'contract-drafts', + loadChildren: () => + import('./views/contracts/contracts.module').then((m) => m.ContractsModule) + }, ] } ]; diff --git a/front/app/src/app/layout/sidenav/sidenav.component.ts b/front/app/src/app/layout/sidenav/sidenav.component.ts index f7288471..f066ac82 100644 --- a/front/app/src/app/layout/sidenav/sidenav.component.ts +++ b/front/app/src/app/layout/sidenav/sidenav.component.ts @@ -31,6 +31,11 @@ export class SidenavComponent { link: "/templates/contracts", icon: IconNamesEnum.FileCodeFill }, + { + title: "Contracts Drafts", + link: "/contract-drafts", + icon: IconNamesEnum.PencilSquare + }, ] } diff --git a/front/app/src/app/views/contracts/contracts-routing.module.ts b/front/app/src/app/views/contracts/contracts-routing.module.ts new file mode 100644 index 00000000..4214b29e --- /dev/null +++ b/front/app/src/app/views/contracts/contracts-routing.module.ts @@ -0,0 +1,44 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { DraftCardComponent, DraftListComponent, DraftNewComponent } from "./drafts.component"; + + +const routes: Routes = [ + { + path: '', + data: { + title: 'Entities', + }, + children: [ + { path: '', redirectTo: 'list', pathMatch: 'full' }, + { + path: 'list', + component: DraftListComponent, + data: { + title: 'List', + }, + }, + { + path: 'new', + component: DraftNewComponent, + data: { + title: 'New', + }, + }, + { + path: ':id', + component: DraftCardComponent, + data: { + title: 'Card', + }, + }, + ], + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class ContractsRoutingModule {} diff --git a/front/app/src/app/views/contracts/contracts.module.ts b/front/app/src/app/views/contracts/contracts.module.ts new file mode 100644 index 00000000..d060407c --- /dev/null +++ b/front/app/src/app/views/contracts/contracts.module.ts @@ -0,0 +1,23 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { ContractsRoutingModule } from './contracts-routing.module'; +import { CrudModule } from '@common/crud/crud.module' +import { DraftCardComponent, DraftListComponent, DraftNewComponent } from "./drafts.component"; + + + +@NgModule({ + imports: [ + CommonModule, + CrudModule, + ContractsRoutingModule + ], + declarations: [ + DraftListComponent, + DraftNewComponent, + DraftCardComponent, + ] +}) +export class ContractsModule { +} diff --git a/front/app/src/app/views/contracts/drafts.component.ts b/front/app/src/app/views/contracts/drafts.component.ts new file mode 100644 index 00000000..1ffb742a --- /dev/null +++ b/front/app/src/app/views/contracts/drafts.component.ts @@ -0,0 +1,39 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, ParamMap } from '@angular/router'; + + +export class BaseEntitiesComponent { + protected resource: string = "contract-draft"; + protected schema: string = "ContractDraft"; +} + +@Component({ + template: '' +}) +export class DraftListComponent extends BaseEntitiesComponent { + columns = ['label', 'address', 'entity_data.type'] +} + +@Component({ + template: '' +}) +export class DraftNewComponent extends BaseEntitiesComponent { +} + +@Component({ + template: '' +}) +export class DraftCardComponent extends BaseEntitiesComponent implements OnInit { + + resource_id: string | null = null; + + constructor(private route: ActivatedRoute,) { + super(); + } + + ngOnInit(): void { + this.route.paramMap.subscribe((params: ParamMap) => { + this.resource_id = params.get('id') + }) + } +} \ No newline at end of file