Files
lab-app/lib/core/services/pricing_service.dart
2026-06-12 00:04:53 +03:00

88 lines
2.5 KiB
Dart

import '../../models/clinic_discount.dart';
import '../../models/job.dart';
import '../../models/prosthetic_product.dart';
class PricingBreakdown {
const PricingBreakdown({
required this.billableUnits,
required this.unitPrice,
required this.baseAmount,
required this.discountAmount,
required this.finalAmount,
required this.appliedDiscounts,
});
final int billableUnits;
final double unitPrice;
final double baseAmount;
final double discountAmount;
final double finalAmount;
final List<ClinicDiscount> appliedDiscounts;
}
class PricingService {
PricingService._();
static final instance = PricingService._();
int billableUnitsForType(ProstheticType type, int memberCount) {
final safeCount = memberCount <= 0 ? 1 : memberCount;
return switch (type) {
ProstheticType.tamProtez || ProstheticType.parsiyel => 1,
_ => safeCount,
};
}
String unitLabelForType(ProstheticType type) {
return switch (type) {
ProstheticType.tamProtez || ProstheticType.parsiyel => 'vaka',
_ => 'diş',
};
}
PricingBreakdown calculate({
required ProstheticProduct product,
required ProstheticType prostheticType,
required int memberCount,
required String clinicTenantId,
required List<ClinicDiscount> discounts,
}) {
final billableUnits = billableUnitsForType(prostheticType, memberCount);
final unitPrice = product.unitPrice ?? 0;
final baseAmount = unitPrice * billableUnits;
final applicable = discounts.where((discount) {
if (!discount.isActive) return false;
if (!(discount.appliesToAll || discount.clinicTenantId == clinicTenantId)) {
return false;
}
if (!(discount.appliesToAllTypes ||
discount.prostheticType == prostheticType.value)) {
return false;
}
if (discount.minQuantity > 0 && billableUnits < discount.minQuantity) {
return false;
}
return true;
}).toList();
double running = baseAmount;
for (final discount in applicable) {
running = discount.discountType == DiscountType.percentage
? running * (1 - discount.discountValue / 100)
: running - discount.discountValue;
}
final finalAmount = running.clamp(0, double.infinity).toDouble();
return PricingBreakdown(
billableUnits: billableUnits,
unitPrice: unitPrice,
baseAmount: baseAmount,
discountAmount: (baseAmount - finalAmount)
.clamp(0, double.infinity)
.toDouble(),
finalAmount: finalAmount,
appliedDiscounts: applicable,
);
}
}