add(remaining): add a way to generate contracts only with remaining shipments
All checks were successful
Deploy Amap / deploy (push) Successful in 41s
All checks were successful
Deploy Amap / deploy (push) Successful in 41s
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
"""Router for contract resource"""
|
"""Router for contract resource"""
|
||||||
|
import datetime
|
||||||
import io
|
import io
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
import src.contracts.service as service
|
import src.contracts.service as service
|
||||||
import src.forms.service as form_service
|
import src.forms.service as form_service
|
||||||
|
import src.shipments.service as shipment_service
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
from sqlmodel import Session
|
from sqlmodel import Session
|
||||||
@@ -44,10 +46,15 @@ async def create_contract(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
remaining_shipments = shipment_service.get_remaining_shipments(
|
||||||
|
session,
|
||||||
|
new_contract.form.id,
|
||||||
|
datetime.datetime.today()
|
||||||
|
)
|
||||||
prices = service.generate_products_prices(
|
prices = service.generate_products_prices(
|
||||||
occasionals,
|
occasionals,
|
||||||
recurrents,
|
recurrents,
|
||||||
new_contract.form.shipments
|
remaining_shipments
|
||||||
)
|
)
|
||||||
recurrent_price = prices['recurrent']
|
recurrent_price = prices['recurrent']
|
||||||
total_price = prices['total']
|
total_price = prices['total']
|
||||||
@@ -111,7 +118,7 @@ async def get_base_contract_template(
|
|||||||
cheque_payment_method = list(filter(
|
cheque_payment_method = list(filter(
|
||||||
lambda x: x.name == "cheque", form.productor.payment_methods))
|
lambda x: x.name == "cheque", form.productor.payment_methods))
|
||||||
cheque_number = cheque_payment_method[0].max if len(
|
cheque_number = cheque_payment_method[0].max if len(
|
||||||
cheque_payment_method) > 0 else 3
|
cheque_payment_method) > 0 and cheque_payment_method[0].max is not None else 3
|
||||||
print(cheque_number, cheque_payment_method)
|
print(cheque_number, cheque_payment_method)
|
||||||
empty_contract = models.ContractPublic(
|
empty_contract = models.ContractPublic(
|
||||||
firstname='',
|
firstname='',
|
||||||
|
|||||||
@@ -49,6 +49,19 @@ def get_one(session: Session, shipment_id: int) -> models.ShipmentPublic:
|
|||||||
return session.get(models.Shipment, shipment_id)
|
return session.get(models.Shipment, shipment_id)
|
||||||
|
|
||||||
|
|
||||||
|
def get_remaining_shipments(session: Session, form_id: int, date: datetime.date) -> list[models.ShipmentPublic]:
|
||||||
|
statement = (
|
||||||
|
select(models.Shipment)
|
||||||
|
.join(
|
||||||
|
models.Form,
|
||||||
|
models.Shipment.form_id == models.Form.id
|
||||||
|
)
|
||||||
|
.where(models.Form.id == form_id)
|
||||||
|
.where(models.Shipment.date >= date)
|
||||||
|
)
|
||||||
|
return session.exec(statement.order_by(models.Shipment.name)).all()
|
||||||
|
|
||||||
|
|
||||||
def create_one(
|
def create_one(
|
||||||
session: Session,
|
session: Session,
|
||||||
shipment: models.ShipmentCreate) -> models.ShipmentPublic:
|
shipment: models.ShipmentCreate) -> models.ShipmentPublic:
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
"filter by productor": "filter by producer",
|
"filter by productor": "filter by producer",
|
||||||
"filter by season": "filter by season",
|
"filter by season": "filter by season",
|
||||||
"filter by type": "filter by type",
|
"filter by type": "filter by type",
|
||||||
"for this contract": "for this contract.",
|
"for this contract": "for this contract",
|
||||||
"for transfer method contact your referer or productor": "for bank transfer, contact your referent or producer.",
|
"for transfer method contact your referer or productor": "for bank transfer, contact your referent or producer.",
|
||||||
"form": "contract form",
|
"form": "contract form",
|
||||||
"form name": "contract form name",
|
"form name": "contract form name",
|
||||||
@@ -184,6 +184,8 @@
|
|||||||
"shipment products": "shipment products",
|
"shipment products": "shipment products",
|
||||||
"shipment products is necessary only for occasional products (if all products are recurrent leave empty)": "shipment products configuration is only necessary for occasional products (leave empty if all products are recurrent).",
|
"shipment products is necessary only for occasional products (if all products are recurrent leave empty)": "shipment products configuration is only necessary for occasional products (leave empty if all products are recurrent).",
|
||||||
"shipments": "shipments",
|
"shipments": "shipments",
|
||||||
|
"remaining_shipments_one": "remaining shipment",
|
||||||
|
"remaining_shipments_other": "remaining shipments",
|
||||||
"some contracts require a minimum value per shipment, ignore this field if it's not the case": "some contracts require a minimum value per shipment. Ignore this field if it does not apply to your contract.",
|
"some contracts require a minimum value per shipment, ignore this field if it's not the case": "some contracts require a minimum value per shipment. Ignore this field if it does not apply to your contract.",
|
||||||
"start": "start",
|
"start": "start",
|
||||||
"start date": "start date",
|
"start date": "start date",
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
"filter by productor": "filtrer par producteur·trice",
|
"filter by productor": "filtrer par producteur·trice",
|
||||||
"filter by season": "filtrer par saisons",
|
"filter by season": "filtrer par saisons",
|
||||||
"filter by type": "filtrer par type",
|
"filter by type": "filtrer par type",
|
||||||
"for this contract": "pour ce contrat.",
|
"for this contract": "pour ce contrat",
|
||||||
"for transfer method contact your referer or productor": "pour mettre en place le virement automatique, contactez votre référent ou le producteur.",
|
"for transfer method contact your referer or productor": "pour mettre en place le virement automatique, contactez votre référent ou le producteur.",
|
||||||
"form": "formulaire de contrat",
|
"form": "formulaire de contrat",
|
||||||
"form name": "nom du formulaire de contrat",
|
"form name": "nom du formulaire de contrat",
|
||||||
@@ -184,6 +184,8 @@
|
|||||||
"shipment products": "produits pour la livraison",
|
"shipment products": "produits pour la livraison",
|
||||||
"shipment products is necessary only for occasional products (if all products are recurrent leave empty)": "il est nécessaire de configurer les produits pour la livraison uniquement si il y a des produits occasionnels (laisser vide si tous les produits sont récurents).",
|
"shipment products is necessary only for occasional products (if all products are recurrent leave empty)": "il est nécessaire de configurer les produits pour la livraison uniquement si il y a des produits occasionnels (laisser vide si tous les produits sont récurents).",
|
||||||
"shipments": "livraisons",
|
"shipments": "livraisons",
|
||||||
|
"remaining_shipments_one": "livraison restante",
|
||||||
|
"remaining_shipments_other": "livraisons restantes",
|
||||||
"some contracts require a minimum value per shipment, ignore this field if it's not the case": "certains contrats nécessitent une valeur minimum par livraison. Ce champ peut être ignoré s’il ne s’applique pas à votre contrat.",
|
"some contracts require a minimum value per shipment, ignore this field if it's not the case": "certains contrats nécessitent une valeur minimum par livraison. Ce champ peut être ignoré s’il ne s’applique pas à votre contrat.",
|
||||||
"start": "début",
|
"start": "début",
|
||||||
"start date": "date de début",
|
"start date": "date de début",
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { useParams } from "react-router";
|
|||||||
import { computePrices } from "./price";
|
import { computePrices } from "./price";
|
||||||
import { ContractCheque } from "@/components/PaymentMethods/Cheque";
|
import { ContractCheque } from "@/components/PaymentMethods/Cheque";
|
||||||
import { tranformProducts, type ContractInputs } from "@/services/resources/contracts";
|
import { tranformProducts, type ContractInputs } from "@/services/resources/contracts";
|
||||||
|
import type { Shipment } from "@/services/resources/shipments";
|
||||||
|
|
||||||
export function Contract() {
|
export function Contract() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@@ -71,12 +72,22 @@ export function Contract() {
|
|||||||
return form?.productor?.products;
|
return form?.productor?.products;
|
||||||
}, [form]);
|
}, [form]);
|
||||||
|
|
||||||
|
const remainingShipments = useMemo(() => {
|
||||||
|
const currentDate = new Date();
|
||||||
|
return form?.shipments.reduce((acc, shipment) => {
|
||||||
|
if (new Date(shipment.date) > currentDate) {
|
||||||
|
return [...acc, shipment];
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, [] as Shipment[])
|
||||||
|
}, [form])
|
||||||
|
|
||||||
const price = useMemo(() => {
|
const price = useMemo(() => {
|
||||||
if (!allProducts) {
|
if (!allProducts) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const productValues = Object.entries(inputForm.getValues().products);
|
const productValues = Object.entries(inputForm.getValues().products);
|
||||||
return computePrices(productValues, allProducts, form?.shipments.length);
|
return computePrices(productValues, allProducts, remainingShipments?.length);
|
||||||
}, [inputForm, allProducts, form?.shipments]);
|
}, [inputForm, allProducts, form?.shipments]);
|
||||||
|
|
||||||
const inputRefs = useRef<Record<string, HTMLInputElement | null>>({
|
const inputRefs = useRef<Record<string, HTMLInputElement | null>>({
|
||||||
@@ -229,7 +240,7 @@ export function Contract() {
|
|||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<Title order={3}>{t("shipments", { capfirst: true })}</Title>
|
<Title order={3}>{t("shipments", { capfirst: true })}</Title>
|
||||||
<Text>{`${t("there is", { capfirst: true })} ${shipments.length} ${shipments.length > 1 ? t("shipments") : t("shipment")} ${t("for this contract")}`}</Text>
|
<Text>{`${t("there is", { capfirst: true })} ${shipments.length} ${shipments.length > 1 ? t("shipments") : t("shipment")} ${t("for this contract")} :`}</Text>
|
||||||
<List>
|
<List>
|
||||||
{shipments.map((shipment) => (
|
{shipments.map((shipment) => (
|
||||||
<List.Item key={shipment.id}>
|
<List.Item key={shipment.id}>
|
||||||
@@ -243,6 +254,20 @@ export function Contract() {
|
|||||||
</List.Item>
|
</List.Item>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
|
<Text>{`${t("there is", { capfirst: true })} ${remainingShipments?.length} ${t("remaining_shipments", {count: remainingShipments?.length})} :`}</Text>
|
||||||
|
<List>
|
||||||
|
{remainingShipments?.map((shipment) => (
|
||||||
|
<List.Item key={shipment.id}>
|
||||||
|
{`${shipment.name} :
|
||||||
|
${new Date(shipment.date).toLocaleDateString("fr-FR", {
|
||||||
|
weekday: "long",
|
||||||
|
year: "numeric",
|
||||||
|
month: "long",
|
||||||
|
day: "numeric",
|
||||||
|
})}`}
|
||||||
|
</List.Item>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
{productsRecurent.length > 0 ? (
|
{productsRecurent.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<Title order={3}>{t("recurrent products", { capfirst: true })}</Title>
|
<Title order={3}>{t("recurrent products", { capfirst: true })}</Title>
|
||||||
@@ -256,12 +281,12 @@ export function Contract() {
|
|||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
{shipments.some((shipment) => shipment.products.length > 0) ? (
|
{remainingShipments?.some((shipment) => shipment.products.length > 0) ? (
|
||||||
<>
|
<>
|
||||||
<Title order={3}>{t("occasional products", { capfirst: true })}</Title>
|
<Title order={3}>{t("occasional products", { capfirst: true })}</Title>
|
||||||
<Text>{t("select products per shipment", { capfirst: true })}</Text>
|
<Text>{t("select products per shipment", { capfirst: true })}</Text>
|
||||||
<Accordion defaultValue={"0"}>
|
<Accordion defaultValue={"0"}>
|
||||||
{shipments.map((shipment, index) => (
|
{remainingShipments?.map((shipment, index) => (
|
||||||
<ShipmentForm
|
<ShipmentForm
|
||||||
minimumPrice={form.minimum_shipment_value}
|
minimumPrice={form.minimum_shipment_value}
|
||||||
shipment={shipment}
|
shipment={shipment}
|
||||||
|
|||||||
Reference in New Issue
Block a user