Initial local backup snapshot
This commit is contained in:
commit
acd9e14ba5
367 changed files with 118038 additions and 0 deletions
298
shared/sallePricing.ts
Normal file
298
shared/sallePricing.ts
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
export type SalleUsageType = "conventionne" | "occasionnel";
|
||||
export type SalleReservationFrequency = "demi_journee" | "journee" | "mensuel";
|
||||
export type SalleWorkflowQuoteStatus = "a_preparer" | "en_attente_association" | "accepte" | "refuse";
|
||||
export type SalleWorkflowDirectorStatus = "a_transmettre" | "en_attente_signature" | "signee";
|
||||
export type SalleWorkflowPaymentStatus = "en_attente_paiement" | "paiement_partiel" | "paiement_recu" | "paiement_valide";
|
||||
|
||||
export type SallePricingLineItem = {
|
||||
salleId: string;
|
||||
salleNom: string;
|
||||
categoryLabel: string;
|
||||
usageType: SalleUsageType;
|
||||
frequency: SalleReservationFrequency;
|
||||
quantity: number;
|
||||
unitAmountCents: number;
|
||||
totalAmountCents: number;
|
||||
};
|
||||
|
||||
export type SallePricingSummary = {
|
||||
usageType: SalleUsageType;
|
||||
frequency: SalleReservationFrequency;
|
||||
quantity: number;
|
||||
lineItems: SallePricingLineItem[];
|
||||
totalAmountCents: number;
|
||||
unsupportedSalles: Array<{
|
||||
salleId: string;
|
||||
salleNom: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type SalleWorkflowData = {
|
||||
usageType?: SalleUsageType;
|
||||
frequency?: SalleReservationFrequency;
|
||||
conditionsFinancieresText?: string;
|
||||
decisionAdministrativeText?: string;
|
||||
pricing?: SallePricingSummary;
|
||||
quoteStatus?: SalleWorkflowQuoteStatus;
|
||||
quoteSentAt?: string;
|
||||
quoteRespondedAt?: string;
|
||||
quotePdfUrl?: string;
|
||||
quotePdfName?: string;
|
||||
administrativeDecisionPdfUrl?: string;
|
||||
administrativeDecisionPdfName?: string;
|
||||
directorStatus?: SalleWorkflowDirectorStatus;
|
||||
directorTransmissionAt?: string;
|
||||
directorSignedAt?: string;
|
||||
directorSignedByUserId?: number;
|
||||
directorSignedByName?: string;
|
||||
directorReturnComment?: string;
|
||||
directorReturnedAt?: string;
|
||||
signedQuotePdfUrl?: string;
|
||||
signedQuotePdfName?: string;
|
||||
signedDecisionPdfUrl?: string;
|
||||
signedDecisionPdfName?: string;
|
||||
signedRequestPdfUrl?: string;
|
||||
signedRequestPdfName?: string;
|
||||
invoicePdfUrl?: string;
|
||||
invoicePdfName?: string;
|
||||
invoiceGeneratedAt?: string;
|
||||
paymentStatus?: SalleWorkflowPaymentStatus;
|
||||
paymentDueDate?: string;
|
||||
amountReceivedCents?: number;
|
||||
paymentReceivedAt?: string;
|
||||
paymentValidatedAt?: string;
|
||||
paymentReference?: string;
|
||||
paymentNotes?: string;
|
||||
finalNotificationSentAt?: string;
|
||||
};
|
||||
|
||||
type SalleTariffDefinition = {
|
||||
salleId: string;
|
||||
salleNom: string;
|
||||
categoryLabel: string;
|
||||
pricing: Partial<Record<SalleUsageType, Partial<Record<SalleReservationFrequency, number>>>>;
|
||||
};
|
||||
|
||||
export const SALLE_USAGE_TYPE_LABELS: Record<SalleUsageType, string> = {
|
||||
conventionne: "Conventionné",
|
||||
occasionnel: "Occasionnel",
|
||||
};
|
||||
|
||||
export const SALLE_FREQUENCY_LABELS: Record<SalleReservationFrequency, string> = {
|
||||
demi_journee: "Demi-journée",
|
||||
journee: "Journée",
|
||||
mensuel: "Mensuel",
|
||||
};
|
||||
|
||||
export const SALLE_WORKFLOW_QUOTE_STATUS_LABELS: Record<SalleWorkflowQuoteStatus, string> = {
|
||||
a_preparer: "À préparer",
|
||||
en_attente_association: "En attente de l'association",
|
||||
accepte: "Accepté par l'association",
|
||||
refuse: "Refusé par l'association",
|
||||
};
|
||||
|
||||
export const SALLE_WORKFLOW_DIRECTOR_STATUS_LABELS: Record<SalleWorkflowDirectorStatus, string> = {
|
||||
a_transmettre: "À transmettre à la Directrice",
|
||||
en_attente_signature: "En attente de signature",
|
||||
signee: "Signée",
|
||||
};
|
||||
|
||||
export const SALLE_WORKFLOW_PAYMENT_STATUS_LABELS: Record<SalleWorkflowPaymentStatus, string> = {
|
||||
en_attente_paiement: "En attente de paiement",
|
||||
paiement_partiel: "Paiement partiel",
|
||||
paiement_recu: "Paiement reçu",
|
||||
paiement_valide: "Paiement validé",
|
||||
};
|
||||
|
||||
const SALLE_TARIFFS: SalleTariffDefinition[] = [
|
||||
{
|
||||
salleId: "bureau_11_17",
|
||||
salleNom: "Bureau 11–17 m²",
|
||||
categoryLabel: "Bureau 11–17 m²",
|
||||
pricing: {
|
||||
conventionne: {
|
||||
journee: 1216,
|
||||
mensuel: 18819,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
salleId: "salle_toucan",
|
||||
salleNom: "Salle TOUCAN",
|
||||
categoryLabel: "Salle de conférence - Formation",
|
||||
pricing: {
|
||||
conventionne: {
|
||||
demi_journee: 7673,
|
||||
journee: 15345,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
salleId: "salle_ibis",
|
||||
salleNom: "Salle IBIS",
|
||||
categoryLabel: "Espace formation",
|
||||
pricing: {
|
||||
conventionne: {
|
||||
demi_journee: 8173,
|
||||
journee: 15845,
|
||||
mensuel: 25000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
salleId: "salle_pelican",
|
||||
salleNom: "Salle PELICAN",
|
||||
categoryLabel: "Espace formation",
|
||||
pricing: {
|
||||
conventionne: {
|
||||
demi_journee: 8173,
|
||||
journee: 15845,
|
||||
mensuel: 25000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
salleId: "hall_amphitheatre",
|
||||
salleNom: "Hall-Amphithéâtre",
|
||||
categoryLabel: "Hall ouvert - 343,34 m²",
|
||||
pricing: {
|
||||
conventionne: {
|
||||
demi_journee: 5000,
|
||||
journee: 10000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
salleId: "dojo",
|
||||
salleNom: "DOJO",
|
||||
categoryLabel: "Dojo",
|
||||
pricing: {
|
||||
conventionne: {
|
||||
mensuel: 65000,
|
||||
},
|
||||
occasionnel: {
|
||||
mensuel: 25000,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const CONDITIONS_FINANCIERES_SALLE_TEXT = `CONDITIONS FINANCIERES - LOCATION DES ESPACES
|
||||
La mise a disposition d'un espace au sein de la Maison de la Jeunesse des Savanes « Melissa ALVES » est soumise aux conditions suivantes :
|
||||
1. Tarification
|
||||
Les tarifs appliques sont ceux votes par le Conseil Communautaire, actualises au 1er septembre 2025.
|
||||
Le montant est calcule automatiquement en fonction :
|
||||
de l'espace choisi
|
||||
de la duree (journee, demi-journee, mensuel)
|
||||
du type d'utilisateur (conventionne / occasionnel)
|
||||
2. Acompte
|
||||
Un acompte peut etre demande selon la nature de l'evenement.
|
||||
3. Annulation
|
||||
Toute annulation doit etre signalee 48 heures a l'avance pour un eventuel remboursement de l'acompte.
|
||||
4. Responsabilite
|
||||
L'association est responsable :
|
||||
des participants
|
||||
du public
|
||||
des dommages eventuels
|
||||
du respect des regles de securite
|
||||
Une attestation de responsabilite civile couvrant la periode doit etre fournie.
|
||||
5. Entretien des locaux
|
||||
Il est interdit de manger dans les salles.
|
||||
Les espaces doivent etre rendus propres et en bon etat.`;
|
||||
|
||||
export function buildDecisionAdministrativeText(input: {
|
||||
espace: string;
|
||||
dates: string;
|
||||
horaires: string;
|
||||
association: string;
|
||||
}) {
|
||||
return `DECISION ADMINISTRATIVE PRIORITAIRE
|
||||
La presente decision atteste que la Maison de la Jeunesse des Savanes « Melissa ALVES » donne un avis favorable a la mise a disposition de l'espace suivant :
|
||||
Espace : ${input.espace}
|
||||
Dates : ${input.dates}
|
||||
Horaires : ${input.horaires}
|
||||
Association : ${input.association}
|
||||
Cette decision est transmise avant validation finale et ne vaut pas autorisation definitive.
|
||||
La mise a disposition devient effective uniquement apres :
|
||||
validation du devis (si facturation)
|
||||
signature de la Directrice
|
||||
reception de l'attestation de responsabilite civile`;
|
||||
}
|
||||
|
||||
export function getSalleTariffDefinition(salleId: string) {
|
||||
return SALLE_TARIFFS.find((entry) => entry.salleId === salleId) || null;
|
||||
}
|
||||
|
||||
export function listReservationDates(start: string, end: string) {
|
||||
if (!start || !end) return [] as string[];
|
||||
const startDate = new Date(`${start}T12:00:00`);
|
||||
const endDate = new Date(`${end}T12:00:00`);
|
||||
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime()) || startDate > endDate) {
|
||||
return [] as string[];
|
||||
}
|
||||
|
||||
const values: string[] = [];
|
||||
const cursor = new Date(startDate);
|
||||
while (cursor <= endDate) {
|
||||
values.push(cursor.toISOString().slice(0, 10));
|
||||
cursor.setDate(cursor.getDate() + 1);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
export function getReservationUnitQuantity(input: {
|
||||
frequency: SalleReservationFrequency;
|
||||
dateReservation?: string;
|
||||
dateFinReservation?: string;
|
||||
}) {
|
||||
if (input.frequency === "mensuel") return 1;
|
||||
const dates = listReservationDates(input.dateReservation || "", input.dateFinReservation || input.dateReservation || "");
|
||||
return Math.max(dates.length, 1);
|
||||
}
|
||||
|
||||
export function computeSallePricing(input: {
|
||||
sallesIds: string[];
|
||||
usageType: SalleUsageType;
|
||||
frequency: SalleReservationFrequency;
|
||||
dateReservation?: string;
|
||||
dateFinReservation?: string;
|
||||
}) {
|
||||
const quantity = getReservationUnitQuantity(input);
|
||||
const summary: SallePricingSummary = {
|
||||
usageType: input.usageType,
|
||||
frequency: input.frequency,
|
||||
quantity,
|
||||
lineItems: [],
|
||||
totalAmountCents: 0,
|
||||
unsupportedSalles: [],
|
||||
};
|
||||
|
||||
input.sallesIds.forEach((salleId) => {
|
||||
const salle = getSalleTariffDefinition(salleId);
|
||||
if (!salle) {
|
||||
summary.unsupportedSalles.push({ salleId, salleNom: salleId });
|
||||
return;
|
||||
}
|
||||
|
||||
const unitAmountCents = salle.pricing[input.usageType]?.[input.frequency];
|
||||
if (typeof unitAmountCents !== "number") {
|
||||
summary.unsupportedSalles.push({ salleId, salleNom: salle.salleNom });
|
||||
return;
|
||||
}
|
||||
|
||||
const lineItem: SallePricingLineItem = {
|
||||
salleId,
|
||||
salleNom: salle.salleNom,
|
||||
categoryLabel: salle.categoryLabel,
|
||||
usageType: input.usageType,
|
||||
frequency: input.frequency,
|
||||
quantity,
|
||||
unitAmountCents,
|
||||
totalAmountCents: unitAmountCents * quantity,
|
||||
};
|
||||
summary.lineItems.push(lineItem);
|
||||
summary.totalAmountCents += lineItem.totalAmountCents;
|
||||
});
|
||||
|
||||
return summary;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue