-
Notifications
You must be signed in to change notification settings - Fork 1
fix: Project screen budget data and decimal precision #166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -431,18 +431,19 @@ export const projectDetailsService = { | |
| lineType === 'Both Budget and Billable' || | ||
| lineType === 'Both_x0020_Budget_x0020_and_x0020_Billable'; | ||
|
|
||
| // Hours Planned: sum quantity from Resource Budget lines only (hours only apply to resources) | ||
| // Convert quantity to hours using unit of measure conversion factor | ||
| // Hours Planned: sum quantity from Billable Resource lines (the contracted project budget) | ||
| // Budget lines are weekly allocations from the Plan screen and are not included here | ||
| const resourceLines = planningLines.filter( | ||
| (line: BCJobPlanningLine) => line.type === 'Resource' | ||
| ); | ||
| hoursPlanned = resourceLines | ||
| .filter((line: BCJobPlanningLine) => isBudgetLine(line.lineType)) | ||
| .reduce( | ||
| (sum: number, line: BCJobPlanningLine) => | ||
| sum + convertToHours(line.number, line.quantity, uomConversionMap), | ||
| 0 | ||
| ); | ||
| const billableResourceLines = resourceLines.filter((line: BCJobPlanningLine) => | ||
| isBillableLine(line.lineType) | ||
| ); | ||
| hoursPlanned = billableResourceLines.reduce( | ||
| (sum: number, line: BCJobPlanningLine) => | ||
| sum + convertToHours(line.number, line.quantity, uomConversionMap), | ||
| 0 | ||
| ); | ||
|
|
||
| // Extract unit price per resource from planning lines as fallback | ||
| // (only if Resource Card doesn't have unitPrice set) | ||
|
|
@@ -456,31 +457,31 @@ export const projectDetailsService = { | |
| } | ||
| } | ||
|
|
||
| // Budget Cost: sum totalCost from ALL Budget lines with breakdown by type | ||
| const budgetLines = planningLines.filter((line: BCJobPlanningLine) => | ||
| isBudgetLine(line.lineType) | ||
| // Billable lines represent the contracted project budget | ||
| // Budget lines are weekly allocations from the Plan screen and are not included in budget/price totals | ||
| const billableLines = planningLines.filter((line: BCJobPlanningLine) => | ||
| isBillableLine(line.lineType) | ||
| ); | ||
| budgetCost = budgetLines.reduce( | ||
| (sum: number, line: BCJobPlanningLine) => sum + line.totalCost, | ||
|
|
||
| // Budget Cost: sum totalPrice from Billable lines (contracted budget) with breakdown by type | ||
| budgetCost = billableLines.reduce( | ||
| (sum: number, line: BCJobPlanningLine) => sum + line.totalPrice, | ||
| 0 | ||
| ); | ||
|
Comment on lines
+460
to
470
|
||
| budgetCostBreakdown = { | ||
| resource: budgetLines | ||
| resource: billableLines | ||
| .filter((line: BCJobPlanningLine) => line.type === 'Resource') | ||
| .reduce((sum: number, line: BCJobPlanningLine) => sum + line.totalCost, 0), | ||
| item: budgetLines | ||
| .reduce((sum: number, line: BCJobPlanningLine) => sum + line.totalPrice, 0), | ||
| item: billableLines | ||
| .filter((line: BCJobPlanningLine) => line.type === 'Item') | ||
| .reduce((sum: number, line: BCJobPlanningLine) => sum + line.totalCost, 0), | ||
| glAccount: budgetLines | ||
| .reduce((sum: number, line: BCJobPlanningLine) => sum + line.totalPrice, 0), | ||
| glAccount: billableLines | ||
| .filter((line: BCJobPlanningLine) => line.type === 'G/L Account') | ||
| .reduce((sum: number, line: BCJobPlanningLine) => sum + line.totalCost, 0), | ||
| .reduce((sum: number, line: BCJobPlanningLine) => sum + line.totalPrice, 0), | ||
| total: budgetCost, | ||
| }; | ||
|
|
||
| // Billable Price: sum totalPrice from ALL Billable lines with breakdown by type | ||
| const billableLines = planningLines.filter((line: BCJobPlanningLine) => | ||
| isBillableLine(line.lineType) | ||
| ); | ||
| // Billable Price: sum totalPrice from Billable lines with breakdown by type | ||
| billablePrice = billableLines.reduce( | ||
| (sum: number, line: BCJobPlanningLine) => sum + line.totalPrice, | ||
| 0 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
getResourceUnitsOfMeasure()fails, the code silently falls back to an empty UOM map. In that caseconvertToHours/convertFromHourswill behave like identity functions, potentially reintroducing the DAY/HOUR UOM bug and writing incorrect quantities back to BC. Consider surfacing an error (e.g., toast) and preventing save until UOM data is available (or retrying fetch on submit).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Low risk since empty map means identity conversion (hours pass through as-is, which is correct for HOUR-based resources). Will consider adding error surfacing in a follow-up.