Added prevailing wage calculator and custom math modifiers
CI / build (push) Has been skipped
CI / deploy (push) Successful in 50s

This commit is contained in:
2026-03-20 15:11:32 -05:00
parent 59c6211bb9
commit a3ac0feddf
12 changed files with 881 additions and 163 deletions
+20 -27
View File
@@ -11,6 +11,7 @@ import { ModifierRegistry } from '../utils/modifier-registry';
import { appStore } from '../store/appStore';
import { SupplierDropdown } from './ui/SupplierDropdown';
import ScopeTextTemplateModal from './ScopeTextTemplateModal';
import { getItemsPricingTotals } from '../utils/pricing';
interface ScopeCardProps {
scope: Scope;
@@ -51,20 +52,28 @@ const ScopeCard: Component<ScopeCardProps> = (props) => {
const scopeItems = createMemo(() => props.items.filter(i => !i.subScopeId));
const totals = createMemo(() => {
let subtotal = 0;
let markup = 0;
let contingency = 0;
let totalQuantity = 0;
const scopeLevelTotals = getItemsPricingTotals(scopeItems(), []);
let subtotal = scopeLevelTotals.subtotal;
let markup = scopeLevelTotals.markup;
let contingency = scopeLevelTotals.contingency;
let totalQuantity = scopeLevelTotals.quantity;
props.items.forEach(item => {
const base = item.quantity * item.unitPrice;
subtotal += base;
totalQuantity += item.quantity;
markup += item.markupType === 'percent' ? base * (item.markup / 100) : item.markup;
contingency += item.contingencyType === 'percent' ? base * (item.contingency / 100) : item.contingency;
let modifiersTotal = 0;
props.subScopes.forEach(ss => {
const ssItems = props.items.filter(i => i.subScopeId === ss.id);
const ssTotals = getItemsPricingTotals(ssItems, ss.modifiers || []);
subtotal += ssTotals.subtotal;
markup += ssTotals.markup;
contingency += ssTotals.contingency;
totalQuantity += ssTotals.quantity;
(ss.modifiers || []).forEach(m => {
if (!m.includeInTotal) return;
modifiersTotal += ModifierRegistry.calculate(m, ssTotals.total, ssItems);
});
});
// Add Management and Delivery
// Add Management and Delivery after all scope and sub-scope item totals are accounted for.
const mgmtTotal = props.scope.useManagementLogic === 'percent'
? subtotal * (props.scope.managementFee / 100)
: props.scope.managementFee;
@@ -73,22 +82,6 @@ const ScopeCard: Component<ScopeCardProps> = (props) => {
? subtotal * (props.scope.deliveryFee / 100)
: props.scope.deliveryFee;
let modifiersTotal = 0;
props.subScopes.forEach(ss => {
const ssItems = props.items.filter(i => i.subScopeId === ss.id);
const ssTotalWithMarkup = ssItems.reduce((sum, item) => {
const base = item.quantity * item.unitPrice;
const markup = item.markupType === 'percent' ? base * (item.markup / 100) : item.markup;
const contingency = item.contingencyType === 'percent' ? base * (item.contingency / 100) : item.contingency;
return sum + base + markup + contingency;
}, 0);
(ss.modifiers || []).forEach(m => {
if (!m.includeInTotal) return;
modifiersTotal += ModifierRegistry.calculate(m, ssTotalWithMarkup, ssItems);
});
});
return {
subtotal,
markup,