add contract pdf generation

This commit is contained in:
2026-02-14 23:59:44 +01:00
parent 7e42fbe106
commit f440cef59e
42 changed files with 1299 additions and 123 deletions

View File

@@ -1,3 +1,108 @@
from fastapi import APIRouter
from fastapi import APIRouter, Depends
from fastapi.responses import StreamingResponse
from src.database import get_session
from sqlmodel import Session
import src.forms.service as form_service
import src.shipments.service as shipment_service
import src.products.service as product_service
from src.contracts.generate_contract import generate_html_contract
import src.models as models
from src.messages import PDFerrorOccured
import io
router = APIRouter(prefix='/contracts')
def find_dict_in_list(lst, key, value):
for i, dic in enumerate(lst):
if dic[key].id == value:
return i
return -1
def extract_products(session: Session, contract: dict):
planned = []
recurrent = []
for key in contract.keys():
key_list = key.split("-")
if "planned" in key:
shipment_id = int(key_list[1])
product_id = int(key_list[2])
shipment = shipment_service.get_one(session, shipment_id)
product = product_service.get_one(session, product_id)
existing_id = find_dict_in_list(planned, "shipment", shipment_id)
if existing_id >= 0:
planned[existing_id]["products"].append({
"product": product,
"quantity": contract[key],
})
planned[existing_id]['price'] += compute_product_price(product, contract[key])
else:
planned.append({
"shipment": shipment,
"price": compute_product_price(product, contract[key]),
"products": [{
"product": product,
"quantity": contract[key],
}]
})
if "recurrent" in key:
product_id = int(key_list[1])
product = product_service.get_one(session, product_id)
recurrent.append({
"product": product,
"quantity": contract[key]
})
return planned, recurrent
def compute_product_price(product: models.Product, quantity: int, nb_shipment: int = 1):
product_quantity_unit = 1 if product.unit == models.Unit.KILO else 1000
final_quantity = quantity if product.price else quantity / product_quantity_unit
final_price = product.price if product.price else product.price_kg
return final_price * final_quantity * nb_shipment
def compute_recurrent_prices(products_quantities: list[dict], nb_shipment: int):
result = 0
for product_quantity in products_quantities:
product = product_quantity['product']
quantity = product_quantity['quantity']
result += compute_product_price(product, quantity, nb_shipment)
return result
def compute_planned_prices(planned: list[dict]):
result = 0
for plan in planned:
result += plan['price']
return result
@router.post('/')
async def create_contract(
contract: models.ContractBase,
session: Session = Depends(get_session)
):
form = form_service.get_one(session, contract.form_id)
planned, recurrent = extract_products(session, contract.contract)
recurrent_price = compute_recurrent_prices(recurrent, len(form.shipments))
total_price = '{:10.2f}'.format(recurrent_price + compute_planned_prices(planned))
# TODO: Store contract
# TODO: send contract to referer
# TODO: Store contract informations ?
try:
pdf_bytes = generate_html_contract(
form,
contract.contract,
planned,
recurrent,
'{:10.2f}'.format(recurrent_price),
total_price
)
pdf_file = io.BytesIO(pdf_bytes)
contract_id = f'{contract.contract['firstname']}_{contract.contract['lastname']}_{form.productor.type}_{form.season}'
except:
raise HTTPException(status_code=400, detail=PDFerrorOccured)
return StreamingResponse(
pdf_file,
media_type="application/pdf",
headers={
"Content-Disposition": f"attachement; filename=contract_{contract_id}.pdf"
}
)