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)
+ });
+ }
}