feat: podpora neplatících osob u objednávek
CI / Generate TypeScript types (push) Successful in 14s
CI / Server unit tests (push) Successful in 20s
CI / Build server (push) Successful in 24s
CI / Build client (push) Successful in 33s
CI / Playwright E2E tests (push) Successful in 1m17s
CI / Build and push Docker image (push) Successful in 39s
CI / Notify (push) Successful in 2s

This commit is contained in:
2026-06-05 11:31:55 +02:00
parent c2bbf7ea60
commit c85842267a
5 changed files with 103 additions and 48 deletions
+67
View File
@@ -0,0 +1,67 @@
import { OrderGroup, OrderGroupMember } from "../../../types";
/**
* Pomocné funkce pro výpočet částek ve skupinových objednávkách.
*
* Klíčové pravidlo: poplatky (balné + doprava + spropitné) se rozpočítávají
* pouze mezi "aktivní" strávníky — tedy ty, kteří si reálně něco objednali.
* Kdo si nic neobjedná (typicky objednávající, který nakupuje jen pro ostatní),
* neplatí nic a nezapočítává se mu ani poměrná část poplatků.
*/
/** Parametry poplatků a slevy potřebné k výpočtu částky člena. */
export type GroupFeeParams = {
/** Celkové poplatky skupiny v haléřích (balné + doprava + spropitné). */
totalFees: number;
/** Typ slevy ('percent' = procenta, 'fixed' = pevná částka v haléřích). */
discountType?: string;
/** Hodnota slevy — procenta, nebo pevná částka v haléřích dle discountType. */
discountValue?: number;
};
/** Vrátí true, pokud si člen něco objednal (má kladnou částku nebo příplatek). */
export function isActiveMember(member: OrderGroupMember): boolean {
return (member.amount ?? 0) + (member.surchargeAmount ?? 0) > 0;
}
/** Počet aktivních strávníků — jen mezi ně se dělí poplatky. */
export function countActiveMembers(members: OrderGroup["members"]): number {
return Object.values(members).filter(isActiveMember).length;
}
/** Celkové poplatky skupiny (balné + doprava + spropitné) v haléřích. */
export function totalGroupFees(group: OrderGroup): number {
return (group.fees ?? 0) + (group.shipping ?? 0) + (group.tip ?? 0);
}
/** Poměrná část poplatků na jednoho aktivního strávníka v haléřích. */
export function computeFeeShare(totalFees: number, activeCount: number): number {
return activeCount > 0 ? Math.round(totalFees / activeCount) : 0;
}
/**
* Celková částka, kterou má člen zaplatit (v haléřích).
* Neaktivní člen (nic si neobjednal) platí 0 — nepodílí se ani na poplatcích.
*
* @param member člen skupiny
* @param params poplatky a sleva
* @param feeShare poměrná část poplatků na osobu (viz computeFeeShare)
* @param activeCount počet aktivních strávníků (dělitel pevné slevy)
*/
export function computeMemberTotal(
member: OrderGroupMember,
params: GroupFeeParams,
feeShare: number,
activeCount: number,
): number {
if (!isActiveMember(member)) return 0;
const base = member.amount ?? 0;
const surcharge = member.surchargeAmount ?? 0;
const discountValue = params.discountValue ?? 0;
const discount = discountValue > 0
? (params.discountType === 'percent'
? Math.round((base + surcharge) * discountValue / 100)
: Math.round(discountValue / activeCount))
: 0;
return base + surcharge + feeShare - discount;
}