Skip to content

Commit

Permalink
Merge pull request #61 from kwheelan/42-new-detail-sheet
Browse files Browse the repository at this point in the history
Adjust app to fit new detail sheet
  • Loading branch information
kwheelan authored Jul 30, 2024
2 parents f093b81 + 3d81469 commit 2aad965
Show file tree
Hide file tree
Showing 21 changed files with 144 additions and 90 deletions.
Binary file not shown.
3 changes: 1 addition & 2 deletions src/js/components/accordion/accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {Baseline, CurrentFund, Fund, Supplemental, FundLookupTable} from '../../
import { formatCurrency, cleanString } from "../../utils/common_utils.js";
import Table from "../table/table.js";
import { visitPage } from '../../views/view_logic.js';
import { TARGET } from '../../constants/';

function redirectForEdit(){
const row = document.querySelector(`.active-editing`);
Expand Down Expand Up @@ -161,7 +160,7 @@ export const Accordion = {
const suppAmount = document.querySelector('#supp-title .top-line-amount')
suppAmount.textContent = formatCurrency(supp.total());
// color-code baseline
if (baseline.total() <= TARGET){
if (baseline.total() <= Baseline.target()){
baselineAmount.style.color = 'green';
} else {
baselineAmount.style.color = 'red';
Expand Down
3 changes: 3 additions & 0 deletions src/js/components/form/subcomponents/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ function createDropdown(dataArray) {
// Creating a select element
const selectElement = document.createElement('select');

// add a default blank option to the dataArray
dataArray = [''].concat(dataArray);

// Looping through the array and creating an option for each element
dataArray.forEach(item => {
const optionElement = document.createElement('option');
Expand Down
3 changes: 1 addition & 2 deletions src/js/components/sidebar/sidebar.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import './sidebar.css'

import { formatCurrency } from "../../utils/common_utils.js";
import { TARGET } from '../../constants/';
import {Baseline, Supplemental} from '../../models/';


Expand All @@ -28,7 +27,7 @@ function showSidebar() {
header.style.width = `${contentWidth - parseInt(sideBarWidth, 10)}px`;

// add target to sidebar
addTarget(TARGET);
addTarget(Baseline.target());

// add event listener to resize content if window is adjusted
window.addEventListener('resize', showSidebar);
Expand Down
25 changes: 15 additions & 10 deletions src/js/components/tooltip/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { FISCAL_YEAR } from '../../constants/';
import Cell from '../table/subcomponents/cells';
import { formatCurrency } from '../../utils/common_utils';
import CurrentPage from '../../models/current_page';
import { excelSerialDateToJSDate } from '../../utils/XLSX_handlers';

import './tooltip.css'

Expand Down Expand Up @@ -68,7 +69,7 @@ function showFinalPersonnelCost(row){
function showFICA(row){
const fica = parseFloat(Cell.getText(row, 'fica'));
const ficaPercentage = (fica * 100).toFixed(2);
const message = `This total is overtime wages plus overtime salary plus FICA (payroll tax),
const message = `This total is overtime / holiday / shift premium pay, plus FICA (payroll tax),
which is ${ficaPercentage}% for this cost center.`
editTooltipText(message);
}
Expand All @@ -77,7 +78,9 @@ function showCPA(row){
const cpa = parseFloat(Cell.getText(row, 'cpa'));
const description = Cell.getText(row, 'cpa-description');
const vendor = Cell.getText(row, 'vendor');
const contract_end = Cell.getText(row, 'contract-end');
var contract_end = Cell.getText(row, 'contract-end');
// convert to normal date format from excel
contract_end = excelSerialDateToJSDate(contract_end);
const remaining = Cell.getValue(row, 'remaining');
if (cpa) {
var message = `<strong>CPA #${cpa}</strong>`;
Expand Down Expand Up @@ -162,25 +165,27 @@ export const Tooltip = {
show : showTooltip,

linkAll : () => {
linkAccountStringCol();
switch(CurrentPage.load()){
case 'personnel' :
linkAccountStringCol();
// linkAccountStringCol();
linkSalaryCol();
linkTotalPersonnelCostCol();
break;
case 'overtime':
linkTotalOTCol();
// linkAccountStringCol();
break;
case 'nonpersonnel':
linkAccountStringCol();
// linkAccountStringCol();
linkCPACol();
break;
case 'revenue':
linkAccountStringCol();
break;
case 'new-inits':
linkAccountStringCol();
break;
// case 'revenue':
// linkAccountStringCol();
// break;
// case 'new-inits':
// linkAccountStringCol();
// break;
default:
break;

Expand Down
5 changes: 0 additions & 5 deletions src/js/constants/app_constants.js

This file was deleted.

36 changes: 36 additions & 0 deletions src/js/constants/budget_constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Set to equal current fiscal year
export var FISCAL_YEAR = '26';

// object categories (from obj part of account string)
export const OBJ_CATEGORIES = {
list : [
// 'Salaries & Wages',
// 'Employee Benefits',
'Professional & Contractual Services',
'Operating Supplies',
'Operating Services',
'Equipment Acquisition',
'Capital Outlays',
'Fixed Charges',
'Other Expenses'
]
}

// from the drop-down menu
export const EMPLOYEE_TYPES = [
'Regular',
'TASS',
'Seasonal',
'Uniform Fire',
'Uniform Police',
'Appointed',
'Elected',
'Long Term Disability'
]

export const OT_OBJECTS = [
'601300 - Salar-Overtime-Gen City',
'601305 - Salaries-Overtime-Police Unif',
'601310 - Salaries-Overtime-Fire Unif',
'602300 - Wages-Overtime-Gen City'
]
26 changes: 12 additions & 14 deletions src/js/constants/excel_constants.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { FISCAL_YEAR } from "./budget_constants";

// sheets to expect on detail sheet
export const SHEETS = {
'FTE, Salary-Wage, & Benefits' : 'personnel' ,
'Overtime & Other Personnel' : 'overtime',
'Non-Personnel Operating' : 'nonpersonnel',
'Non-Personnel' : 'nonpersonnel',
'Revenue' : 'revenue'
}

export const OBJ_CATEGORIES = {
list : [
// 'Salaries & Wages',
// 'Employee Benefits',
'Professional & Contractual Services',
'Operating Supplies',
'Operating Services',
'Equipment Acquisition',
'Capital Outlays',
'Fixed Charges',
'Other Expenses'
]
}
// where to find the general fund target
export const TARGET_CELL_ADDRESS = 'C14'

export const TOTAL_COLUMNS = {
'personnel': 'Total Sal/Wag & Ben Request',
'overtime':`FY${FISCAL_YEAR} Total OT/SP/Hol + FICA Request`,
'nonpersonnel': `FY${FISCAL_YEAR} Departmental Request Total`,
'revenue': `FY${FISCAL_YEAR} Departmental Estimate`
};
2 changes: 1 addition & 1 deletion src/js/constants/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './app_constants';
export * from './budget_constants';
export * from './excel_constants';
2 changes: 1 addition & 1 deletion src/js/models/account_string.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

import CurrentFund from "./current_fund";

export const AccountString = {
getNumber: function(input) {
Expand Down
2 changes: 2 additions & 0 deletions src/js/models/baseline.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export class Baseline {
});
}

static target() { return localStorage.getItem('target') };

personnel() {
let total = 0;
this.funds.forEach(fund => {
Expand Down
15 changes: 2 additions & 13 deletions src/js/models/fund.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import { colSum } from "../utils/common_utils";
import { FISCAL_YEAR } from '../constants/';
import { TOTAL_COLUMNS } from '../constants/';

// Class to hold information on a specific fund and table
class StoredTable {
Expand All @@ -11,18 +11,7 @@ class StoredTable {
}

totalCol() {
switch(this.page){
case 'personnel':
return 'Total Cost';
case 'overtime':
return 'Total Cost (including benefits)';
case 'nonpersonnel':
return `FY${FISCAL_YEAR} Request`;
case 'revenue':
return `Departmental Request Total`;
default:
break;
}
return TOTAL_COLUMNS[this.page];
}
getSum() {
// fill with zero until there is something saved in storage
Expand Down
35 changes: 32 additions & 3 deletions src/js/utils/XLSX_handlers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


import { SHEETS } from '../constants/';
import { SHEETS, TARGET_CELL_ADDRESS } from '../constants/';
import FundLookupTable from '../models/fund_lookup_table.js';
import { removeNewLines } from './common_utils.js';
import Baseline from '../models/baseline.js';
Expand Down Expand Up @@ -81,7 +81,7 @@ export function processWorkbook(arrayBuffer) {
}

// But also save the possible services
else if (sheetName == 'Drop-Downs'){
else if (sheetName == 'Drop-Down Menus'){
const sheet = workbook.Sheets[sheetName];
// Convert the sheet to JSON to easily manipulate data
const sheetData = XLSX.utils.sheet_to_json(sheet, { header: 1 });
Expand All @@ -100,6 +100,17 @@ export function processWorkbook(arrayBuffer) {
Services.save(cleanedServicesColumn);
}
}

else if(sheetName == 'Dept Summary'){
const sheet = workbook.Sheets[sheetName];
// get and save TARGET for general fund
if(sheet[TARGET_CELL_ADDRESS]) {
const cellValue = sheet[TARGET_CELL_ADDRESS].v; // Access the cell value
localStorage.setItem('target', cellValue);
} else {
console.error(`Cell ${TARGET_CELL_ADDRESS} not found in sheet ${sheetName}`);
}
}
});

console.log('all excel data saved');
Expand Down Expand Up @@ -154,4 +165,22 @@ export function downloadXLSX() {
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}

export function excelSerialDateToJSDate(serial) {

if (!serial) { return null };
// Excel considers 1900-01-01 as day 1, but JavaScript's Date considers
// 1970-01-01 as day 0. Therefore, we calculate the number of milliseconds
// between 1900-01-01 and 1970-01-01.
const excelEpoch = new Date(Date.UTC(1899, 11, 30)); // JavaScript Consider December month as '11'

// Calculate the JS date by adding serial days to the epoch date
const date = new Date(excelEpoch.getTime() + (serial * 24 * 60 * 60 * 1000));

// Set the time part to zero (midnight)
date.setUTCHours(0, 0, 0, 0);

// Return the date part of the ISO string
return date.toISOString().split('T')[0];
}
1 change: 1 addition & 0 deletions src/js/utils/common_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export function removeNewLines(str){
str = str.replaceAll(/[\r\n]+/g, " ");
// remove any extra spaces or trailing/leading whitespace
str = str.replaceAll(' ', ' ');
str = str.replaceAll(' ', ' ');
str = str.replace(/^\s+|\s+$/g, '');
return str;
}
Expand Down
2 changes: 1 addition & 1 deletion src/js/views/00_welcome.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class WelcomeView extends View {
// initialize links in buttons
document.getElementById('step-upload').addEventListener('click', () => visitPage('upload'));
document.getElementById('step-initiatives').addEventListener('click', () => visitPage('new-inits'));
document.getElementById('step-revenue').addEventListener('click', () => visitPage('revenue'));
document.getElementById('step-revenue').addEventListener('click', () => visitPage('baseline-landing'));
document.getElementById('step-finish').addEventListener('click', () => visitPage('summary'));

}
Expand Down
14 changes: 8 additions & 6 deletions src/js/views/03_revenue.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,28 @@ import Table from '../components/table/table.js';

export class RevenueView extends View {

constructor() {
constructor(fiscal_year) {
super();
this.page_state = 'revenue';
this.prompt = 'Review and edit revenue line items.';
this.prompt = `Review and edit revenue line items. If you change the estimate or
notice an error in an account string, please note it in the notes column. Click edit
to change values in a row.`;
this.subtitle = 'Revenues';
this.table = new RevenueTable();
this.table = new RevenueTable(fiscal_year);
}
}

class RevenueTable extends ViewTable {

constructor() {
constructor(fiscal_year) {
super();

// add additional revenue columns to the table
this.columns = this.columns.concat([
{ title: 'Recurring or One-Time', className: 'recurring'},
{ title: 'Object Category', className: 'object-category'},
{ title: 'Departmental Request Total', className: 'request', isCost: true},
{ title: 'Departmental Request Notes', className: 'notes'},
{ title: `FY${fiscal_year} Departmental Estimate`, className: 'request', isCost: true},
{ title: 'Departmental Estimate Notes', className: 'notes'},
]);

this.noDataMessage = 'No revenues for this fund.'
Expand Down
7 changes: 5 additions & 2 deletions src/js/views/04_personnel.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Form from "../components/form/form.js";

import { Services, FundLookupTable } from '../models/';
import { unformatCurrency } from "../utils/common_utils.js";
import { EMPLOYEE_TYPES } from '../constants/budget_constants.js';

export class PersonnelView extends View {

Expand All @@ -30,10 +31,11 @@ class PersonnelTable extends ViewTable {
// add additional personnel columns to the table
this.columns = this.columns.concat([
{ title: 'Job Title', className: 'job-name' },
{ title: 'Employee Type', className: 'employee-type'},
{ title: 'Service', className: 'service' },
{ title: `FY${this.fiscal_year} Requested FTE`, className: 'baseline-ftes' },
{ title: `FY${this.fiscal_year} Average Projected Salary/Wage`, className: 'avg-salary', isCost: true },
{ title: 'Total Cost', className: 'total-baseline', isCost: true },
{ title: `FY${this.fiscal_year} Projected Average Salary/Wage`, className: 'avg-salary', isCost: true },
{ title: 'Total Sal/Wag & Ben Request', className: 'total-baseline', isCost: true },
// hidden columns
{ title: 'Fringe Benefits Rate', className: 'fringe', hide: true },
{ title: 'General Increase Rate', className: 'general-increase-rate', hide: true},
Expand Down Expand Up @@ -74,6 +76,7 @@ class PersonnelTable extends ViewTable {
addCustomQuestions(){
// form questions to add a new job
Form.NewField.shortText('Job Title:', 'job-name', true);
Form.NewField.dropdown('Employee Type:', 'employee-type', EMPLOYEE_TYPES, true),
Form.NewField.dropdown('Appropriation:', 'approp-name', FundLookupTable.getApprops(), true);
Form.NewField.dropdown('Cost Center:', 'cc-name', FundLookupTable.getCostCenters(), true);
Form.NewField.dropdown('Service', 'service', Services.list(), true);
Expand Down
Loading

0 comments on commit 2aad965

Please sign in to comment.