From 576b5970a58edf9e8e781a88d22078d9eadcb240 Mon Sep 17 00:00:00 2001 From: ewandor Date: Mon, 6 Mar 2023 17:05:49 +0100 Subject: [PATCH] Adding contract creation --- back/app/contract/__init__.py | 71 ++++++++++++++++++- back/app/contract/models.py | 63 +++++++++++++--- back/app/contract/schemas.py | 18 ++++- back/app/db.py | 5 +- .../app/views/contracts/drafts.component.ts | 69 +++++++++++++++++- 5 files changed, 210 insertions(+), 16 deletions(-) diff --git a/back/app/contract/__init__.py b/back/app/contract/__init__.py index a386e75f..b724b596 100644 --- a/back/app/contract/__init__.py +++ b/back/app/contract/__init__.py @@ -1,9 +1,76 @@ -from fastapi import APIRouter +from fastapi import Depends, HTTPException + +from ..core.routes import get_crud_router from .routes_draft import draft_router from .print import print_router -contract_router = APIRouter() +from .models import Contract, ContractDraft +from .schemas import ContractCreate, ContractRead, ContractUpdate + +from ..entity.models import Entity +from ..template.models import ProvisionTemplate + +contract_router = get_crud_router(Contract, ContractCreate, ContractRead, ContractUpdate) +del(contract_router.routes[0]) +del(contract_router.routes[2]) +del(contract_router.routes[2]) contract_router.include_router(draft_router, prefix="/draft", tags=["draft"], ) contract_router.include_router(print_router, prefix="/print", tags=["print"], ) + + +def can_create_contract(): + class User: + entity_id = '63d127bcf355de8e65a193e1' + return User() + + +@contract_router.post("/", response_description="Contract Successfully created") +async def create(item: ContractCreate, user=Depends(can_create_contract)) -> dict: + await item.validate_foreign_key() + + draft = await ContractDraft.get(item.draft_id) + + for v in draft.variables: + if not v.key or not v.value: + raise HTTPException(status_code=400, detail="Variable {} is invalid".format(v)) + + contract_dict = item.dict() + del(contract_dict['draft_id']) + + contract_dict['lawyer'] = await Entity.get(user.entity_id) + + contract_dict['name'] = draft.name + contract_dict['title'] = draft.title + parties = [] + for p in draft.parties: + parties.append({ + 'entity': await Entity.get(p.entity_id), + 'part': p.part, + 'representative': await Entity.get(p.representative_id) if p.representative_id else None + }) + + contract_dict['parties'] = parties + + provisions = [] + for p in draft.provisions: + p = p.provision + provision = await ProvisionTemplate.get(p.provision_template_id) if p.type == 'template' \ + else p + + provisions.append({ + 'title': replace_variables_in_value(draft.variables, provision.title), + 'body': replace_variables_in_value(draft.variables, provision.body) + }) + + contract_dict['provisions'] = provisions + + o = await Contract(**contract_dict).create() + return {"message": "Contract Successfully created", "id": o.id} + + +def replace_variables_in_value(variables, value: str): + for v in variables: + value = value.replace('%{}%'.format(v.key), v.value) + return value diff --git a/back/app/contract/models.py b/back/app/contract/models.py index 7343bfad..b8da5270 100644 --- a/back/app/contract/models.py +++ b/back/app/contract/models.py @@ -1,3 +1,5 @@ +import uuid + import datetime from typing import List, Literal from enum import Enum @@ -5,21 +7,22 @@ from enum import Enum from pydantic import BaseModel, Field from ..core.models import CrudDocument, RichtextSingleline, RichtextMultiline, DictionaryEntry +from ..entity.models import Entity class ContractStatus(str, Enum): - new = 'new' + published = 'published' signed = 'signed' - in_effect = 'in_effect' executed = 'executed' class ContractDraftStatus(str, Enum): - draft = 'draft' + in_progress = 'in_progress' + ready = 'ready' created = 'created' -class Party(BaseModel): +class DraftParty(BaseModel): entity_id: str = Field( foreignKey={ "reference": { @@ -40,6 +43,19 @@ class Party(BaseModel): ) +class Signature(BaseModel): + uuid: str + affixed: bool + + +class Party(BaseModel): + entity: Entity + part: str + representative: Entity = None + signature_uuid: str = str(uuid.uuid4()) + signature_affixed: bool = False + + class ProvisionGenuine(BaseModel): type: Literal['genuine'] = 'genuine' title: str = RichtextSingleline(props={"parametrized": True}) @@ -64,10 +80,15 @@ class DraftProvision(BaseModel): provision: ContractProvisionTemplateReference | ProvisionGenuine = Field(..., discriminator='type') +class Provision(BaseModel): + title: str + body: str + + class ContractDraft(CrudDocument): name: str title: str - parties: List[Party] + parties: List[DraftParty] provisions: List[DraftProvision] = Field( props={"items-per-row": "1", "numbered": True} ) @@ -75,6 +96,32 @@ class ContractDraft(CrudDocument): default=[], format="dictionary", ) - status: ContractDraftStatus = Field(default=ContractDraftStatus.draft) - location: str = "" - date: datetime.date = datetime.date(1970, 1, 1) + status: ContractDraftStatus = ContractDraftStatus.in_progress + + class Settings(CrudDocument.Settings): + 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) + } + + +class Contract(CrudDocument): + name: str + title: str + parties: List[Party] + provisions: List[Provision] = Field( + props={"items-per-row": "1", "numbered": True} + ) + status: ContractStatus = ContractStatus.published + location: str + date: datetime.date + + class Settings(CrudDocument.Settings): + # fulltext_search = ['label'] + + 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) + } diff --git a/back/app/contract/schemas.py b/back/app/contract/schemas.py index eddc0c10..223cc947 100644 --- a/back/app/contract/schemas.py +++ b/back/app/contract/schemas.py @@ -1,9 +1,9 @@ import datetime from typing import List -from pydantic import Field +from pydantic import BaseModel, Field -from .models import ContractDraft, DraftProvision, Party +from .models import ContractDraft, DraftProvision, Party, Contract from ..entity.models import Entity from ..core.schemas import Writer @@ -36,3 +36,17 @@ class ContractDraftCreate(Writer): class ContractDraftUpdate(ContractDraftCreate): pass + + +class ContractRead(Contract): + pass + + +class ContractCreate(Writer): + date: datetime.date + location: str + draft_id: str + + +class ContractUpdate(BaseModel): + pass diff --git a/back/app/db.py b/back/app/db.py index 8b987433..c83f4460 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 ContractDraft +from .contract.models import ContractDraft, Contract DATABASE_URL = "mongodb://root:example@mongo:27017/" @@ -17,5 +17,6 @@ async def init_db(): ) await init_beanie(database=client.db_name, - document_models=[User, AccessToken, Entity, ContractTemplate, ProvisionTemplate, ContractDraft, ], + document_models=[User, AccessToken, Entity, ContractTemplate, ProvisionTemplate, ContractDraft, + Contract, ], allow_index_dropping=True) diff --git a/front/app/src/app/views/contracts/drafts.component.ts b/front/app/src/app/views/contracts/drafts.component.ts index f48380a0..1a85d54a 100644 --- a/front/app/src/app/views/contracts/drafts.component.ts +++ b/front/app/src/app/views/contracts/drafts.component.ts @@ -3,6 +3,9 @@ import { FormlyFieldConfig } from "@ngx-formly/core"; import { FormGroup} from "@angular/forms"; import { CrudFormlyJsonschemaService } from "@common/crud/crud-formly-jsonschema.service"; import { CrudService } from "@common/crud/crud.service"; +import {ActivatedRoute, ParamMap} from "@angular/router"; + +import { formatDate } from "@angular/common"; export class BaseDraftsComponent { @@ -86,7 +89,69 @@ export class DraftsNewComponent extends BaseDraftsComponent implements OnInit { } @Component({ - templateUrl: '../base-view/templates/card.template.html' + template: ` + + + Preview + + + ` }) -export class DraftsCardComponent extends BaseDraftsComponent { +export class DraftsCardComponent extends BaseDraftsComponent implements OnInit { + resource_id: string | null = null;templateModel: {} = {}; + newContractFormfields: FormlyFieldConfig[] = []; + newContractForm: FormGroup = new FormGroup({}); + newContractModel: any = { + date: formatDate(new Date(),'YYYY-MM-dd', 'EN_US', 'CET'), + location: "Los Santos, SA", + draft_id: null + } + + fieldJson = { + type: "object", + properties: { + date: { + type: "string", + format: "date", + title: "Date" + }, + location: { + type: "string", + title: "Location" + }, + draft_id: { + type: "string", + title: "Contract Draft", + hidden: true + }, + }, + } + + constructor( + private route: ActivatedRoute, + private formlyJsonschema: CrudFormlyJsonschemaService, + private crudService: CrudService + ) { + super(); + } + + ngOnInit(): void { + if (this.resource_id === null) { + this.route.paramMap.subscribe((params: ParamMap) => { + this.resource_id = params.get('id') + }) + } + + this.newContractModel.draft_id = this.resource_id; + // @ts-ignore + this.newContractFormfields = [this.formlyJsonschema.toFieldConfig(this.fieldJson)]; + } + + publish() { + this.crudService.create('contract', this.newContractModel).subscribe((templateModel) => { + console.log(templateModel) + }); + } }