feat: improve patient flow and pricing workflow
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user