Better feedback on draft publication
This commit is contained in:
@@ -6,7 +6,7 @@ from ..core.routes import get_crud_router
|
||||
from .routes_draft import draft_router
|
||||
from .print import print_router
|
||||
|
||||
from .models import Contract, ContractDraft, Party, replace_variables_in_value
|
||||
from .models import Contract, ContractDraft, ContractDraftStatus, Party, replace_variables_in_value
|
||||
from .schemas import ContractCreate, ContractRead, ContractUpdate
|
||||
|
||||
from ..entity.models import Entity
|
||||
@@ -64,6 +64,8 @@ async def create(item: ContractCreate, user=Depends(get_current_user)) -> dict:
|
||||
contract_dict['provisions'] = provisions
|
||||
|
||||
o = await Contract(**contract_dict).create()
|
||||
|
||||
await draft.update({"$set": {"status": ContractDraftStatus.published}})
|
||||
return {"message": "Contract Successfully created", "id": o.id}
|
||||
|
||||
|
||||
@@ -89,11 +91,11 @@ async def affix_signature(signature_id: str, signature_file: UploadFile = File(.
|
||||
if signature.signature_affixed:
|
||||
raise HTTPException(status_code=400, detail="Signature already affixed")
|
||||
|
||||
with open("media/signatures/{}.png".format(signature_id), "wb") as buffer:
|
||||
with open(f'media/signatures/{signature_id}.png', "wb") as buffer:
|
||||
shutil.copyfileobj(signature_file.file, buffer)
|
||||
|
||||
update_query = {"$set": {
|
||||
'parties.{}.signature_affixed'.format(signature_index): True
|
||||
f'parties.{signature_index}.signature_affixed': True
|
||||
}}
|
||||
signature.signature_affixed = True
|
||||
if contract.is_signed():
|
||||
|
||||
@@ -19,7 +19,7 @@ class ContractStatus(str, Enum):
|
||||
class ContractDraftStatus(str, Enum):
|
||||
in_progress = 'in_progress'
|
||||
ready = 'ready'
|
||||
created = 'created'
|
||||
published = 'published'
|
||||
|
||||
|
||||
class DraftParty(BaseModel):
|
||||
@@ -29,7 +29,8 @@ class DraftParty(BaseModel):
|
||||
"resource": "entity",
|
||||
"schema": "Entity",
|
||||
}
|
||||
}
|
||||
},
|
||||
default=""
|
||||
)
|
||||
part: str
|
||||
representative_id: str = Field(
|
||||
@@ -59,8 +60,8 @@ class Party(BaseModel):
|
||||
|
||||
class ProvisionGenuine(BaseModel):
|
||||
type: Literal['genuine'] = 'genuine'
|
||||
title: str = RichtextSingleline(props={"parametrized": True})
|
||||
body: str = RichtextMultiline(props={"parametrized": True})
|
||||
title: str = RichtextSingleline(props={"parametrized": True}, default="")
|
||||
body: str = RichtextMultiline(props={"parametrized": True}, default="")
|
||||
|
||||
|
||||
class ContractProvisionTemplateReference(BaseModel):
|
||||
@@ -73,7 +74,8 @@ class ContractProvisionTemplateReference(BaseModel):
|
||||
"displayedFields": ['title', 'body']
|
||||
},
|
||||
},
|
||||
props={"parametrized": True}
|
||||
props={"parametrized": True},
|
||||
default=""
|
||||
)
|
||||
|
||||
|
||||
@@ -98,6 +100,7 @@ class ContractDraft(CrudDocument):
|
||||
format="dictionary",
|
||||
)
|
||||
status: ContractDraftStatus = ContractDraftStatus.in_progress
|
||||
todo: List[str] = []
|
||||
|
||||
class Settings(CrudDocument.Settings):
|
||||
bson_encoders = {
|
||||
@@ -106,6 +109,40 @@ class ContractDraft(CrudDocument):
|
||||
hour=0, minute=0, second=0)
|
||||
}
|
||||
|
||||
async def check_is_ready(self):
|
||||
if self.status == ContractDraftStatus.published:
|
||||
return
|
||||
|
||||
self.todo = []
|
||||
if len(self.parties) < 2:
|
||||
self.todo.append('Contract must have at least two parties')
|
||||
if len(self.provisions) < 1:
|
||||
self.todo.append('Contract must have at least one provision')
|
||||
|
||||
for p in self.parties:
|
||||
if not p.entity_id:
|
||||
self.todo.append('All parties must have an associated entity`')
|
||||
|
||||
for p in self.provisions:
|
||||
if p.provision.type == "genuine" and not (p.provision.title and p.provision.body):
|
||||
self.todo.append('Empty genuine provision')
|
||||
elif p.provision.type == "template" and not p.provision.provision_template_id:
|
||||
self.todo.append('Empty template provision')
|
||||
|
||||
for v in self.variables:
|
||||
if not (v.key and v.value):
|
||||
self.todo.append('Empty variable')
|
||||
|
||||
if self.todo:
|
||||
self.status = ContractDraftStatus.in_progress
|
||||
else:
|
||||
self.status = ContractDraftStatus.ready
|
||||
|
||||
await self.update({"$set": {
|
||||
"status": self.status,
|
||||
"todo": self.todo
|
||||
}})
|
||||
|
||||
|
||||
class Contract(CrudDocument):
|
||||
name: str
|
||||
|
||||
@@ -84,8 +84,8 @@ async def preview_draft(draft_id: str) -> str:
|
||||
return await render_print('localhost', draft)
|
||||
|
||||
|
||||
@print_router.get("/preview/{signature_id}", response_class=HTMLResponse)
|
||||
async def preview_contract(signature_id: str) -> str:
|
||||
@print_router.get("/preview/signature/{signature_id}", response_class=HTMLResponse)
|
||||
async def preview_contract_by_signature(signature_id: str) -> str:
|
||||
contract = await Contract.find_by_signature_id(signature_id)
|
||||
for p in contract.parties:
|
||||
if p.signature_affixed:
|
||||
@@ -94,6 +94,16 @@ async def preview_contract(signature_id: str) -> str:
|
||||
return await render_print('localhost', contract)
|
||||
|
||||
|
||||
@print_router.get("/preview/{contract_id}", response_class=HTMLResponse)
|
||||
async def preview_contract(contract_id: str) -> str:
|
||||
contract = await Contract.get(contract_id)
|
||||
for p in contract.parties:
|
||||
if p.signature_affixed:
|
||||
p.signature_png = retrieve_signature_png(f'media/signatures/{p.signature_uuid}.png')
|
||||
|
||||
return await render_print('localhost', contract)
|
||||
|
||||
|
||||
@print_router.get("/pdf/{contract_id}", response_class=FileResponse)
|
||||
async def create_pdf(contract_id: str) -> str:
|
||||
contract = await Contract.get(contract_id)
|
||||
|
||||
@@ -1,7 +1,47 @@
|
||||
from fastapi import APIRouter
|
||||
from beanie import PydanticObjectId
|
||||
from fastapi import HTTPException, Depends
|
||||
|
||||
from ..core.routes import get_crud_router
|
||||
from .models import ContractDraft
|
||||
from ..user.manager import get_current_user
|
||||
|
||||
from .models import ContractDraft, ContractDraftStatus
|
||||
from .schemas import ContractDraftCreate, ContractDraftRead, ContractDraftUpdate
|
||||
|
||||
draft_router = get_crud_router(ContractDraft, ContractDraftCreate, ContractDraftRead, ContractDraftUpdate)
|
||||
|
||||
del(draft_router.routes[0])
|
||||
del(draft_router.routes[2])
|
||||
|
||||
|
||||
@draft_router.post("/", response_description="Contract Draft added to the database")
|
||||
async def create(item: ContractDraftCreate, user=Depends(get_current_user)) -> dict:
|
||||
await item.validate_foreign_key()
|
||||
o = await ContractDraft(**item.dict()).create()
|
||||
await o.check_is_ready()
|
||||
|
||||
return {"message": "Contract Draft added successfully", "id": o.id}
|
||||
|
||||
|
||||
@draft_router.put("/{id}", response_description="Contract Draft record updated")
|
||||
async def update(id: PydanticObjectId, req: ContractDraftUpdate, user=Depends(get_current_user)) -> ContractDraftRead:
|
||||
req = {k: v for k, v in req.dict().items() if v is not None}
|
||||
update_query = {"$set": {
|
||||
field: value for field, value in req.items()
|
||||
}}
|
||||
|
||||
item = await ContractDraft.get(id)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Contract Draft record not found!"
|
||||
)
|
||||
if item.status == ContractDraftStatus.published:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Contract Draft has already been published"
|
||||
)
|
||||
|
||||
await item.update(update_query)
|
||||
await item.check_is_ready()
|
||||
|
||||
return ContractDraftRead(**item.dict())
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import List
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from .models import ContractDraft, DraftProvision, Party, Contract
|
||||
from .models import ContractDraft, DraftProvision, DraftParty, Contract
|
||||
|
||||
from ..entity.models import Entity
|
||||
from ..core.schemas import Writer
|
||||
@@ -17,14 +17,12 @@ class ContractDraftRead(ContractDraft):
|
||||
class ContractDraftCreate(Writer):
|
||||
name: str
|
||||
title: str
|
||||
parties: List[Party]
|
||||
parties: List[DraftParty]
|
||||
provisions: List[DraftProvision]
|
||||
variables: List[DictionaryEntry] = Field(
|
||||
default=[],
|
||||
format="dictionary",
|
||||
)
|
||||
location: str = ""
|
||||
date: datetime.date = datetime.date(1, 1, 1)
|
||||
|
||||
async def validate_foreign_key(self):
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user