From f7e68568f842688d1d9e8b5cb5aab65d4b2dcdd8 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Wed, 19 Sep 2018 10:45:01 -0400 Subject: [PATCH 01/14] Modify mock reports data to be near current date, not in the future --- atst/domain/reports.py | 194 +++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 102 deletions(-) diff --git a/atst/domain/reports.py b/atst/domain/reports.py index 7e49e0de..cfeaae7d 100644 --- a/atst/domain/reports.py +++ b/atst/domain/reports.py @@ -4,151 +4,141 @@ from itertools import groupby MONTHLY_SPEND_AARDVARK = { "LC04": { "Integ": { - "10/2018": 284, - "11/2018": 1210, - "12/2018": 1430, - "01/2019": 1366, - "02/2019": 1169, - "03/2019": 991, - "04/2019": 978, - "05/2019": 737, + "02/2018": 284, + "03/2018": 1210, + "04/2018": 1430, + "05/2018": 1366, + "06/2018": 1169, + "07/2018": 991, + "08/2018": 978, + "09/2018": 737, }, "PreProd": { - "10/2018": 812, - "11/2018": 1389, - "12/2018": 1425, - "01/2019": 1306, - "02/2019": 1112, - "03/2019": 936, - "04/2019": 921, - "05/2019": 694, + "02/2018": 812, + "03/2018": 1389, + "04/2018": 1425, + "05/2018": 1306, + "06/2018": 1112, + "07/2018": 936, + "08/2018": 921, + "09/2018": 694, }, "Prod": { - "10/2018": 1742, - "11/2018": 1716, - "12/2018": 1866, - "01/2019": 1809, - "02/2019": 1839, - "03/2019": 1633, - "04/2019": 1654, - "05/2019": 1103, + "02/2018": 1742, + "03/2018": 1716, + "04/2018": 1866, + "05/2018": 1809, + "06/2018": 1839, + "07/2018": 1633, + "08/2018": 1654, + "09/2018": 1103, }, }, "SF18": { "Integ": { - "12/2018": 1498, - "01/2019": 1400, - "02/2019": 1394, - "03/2019": 1171, - "04/2019": 1200, - "05/2019": 963, + "04/2018": 1498, + "05/2018": 1400, + "06/2018": 1394, + "07/2018": 1171, + "08/2018": 1200, + "09/2018": 963, }, "PreProd": { - "12/2018": 1780, - "01/2019": 1667, - "02/2019": 1703, - "03/2019": 1474, - "04/2019": 1441, - "05/2019": 933, + "04/2018": 1780, + "05/2018": 1667, + "06/2018": 1703, + "07/2018": 1474, + "08/2018": 1441, + "09/2018": 933, }, "Prod": { - "12/2018": 1686, - "01/2019": 1779, - "02/2019": 1792, - "03/2019": 1570, - "04/2019": 1539, - "05/2019": 986, + "04/2018": 1686, + "05/2018": 1779, + "06/2018": 1792, + "07/2018": 1570, + "08/2018": 1539, + "09/2018": 986, }, }, "Canton": { "Prod": { - "01/2019": 28699, - "02/2019": 26766, - "03/2019": 22619, - "04/2019": 24090, - "05/2019": 16719, + "05/2018": 28699, + "06/2018": 26766, + "07/2018": 22619, + "08/2018": 24090, + "09/2018": 16719, } }, "BD04": { "Integ": {}, "PreProd": { - "10/2018": 7019, - "11/2018": 3004, - "12/2018": 2691, - "01/2019": 2901, - "02/2019": 3463, - "03/2019": 3314, - "04/2019": 3432, - "05/2019": 723, + "02/2018": 7019, + "03/2018": 3004, + "04/2018": 2691, + "05/2018": 2901, + "06/2018": 3463, + "07/2018": 3314, + "08/2018": 3432, + "09/2018": 723, }, }, "SCV18": {"Dev": {"05/2019": 9797}}, "Crown": { "CR Portal Dev": { - "11/2018": 208, - "12/2018": 457, - "01/2019": 671, - "02/2019": 136, - "03/2019": 1524, - "04/2019": 2077, - "05/2019": 1858, + "03/2018": 208, + "04/2018": 457, + "05/2018": 671, + "06/2018": 136, + "07/2018": 1524, + "08/2018": 2077, + "09/2018": 1858, }, "CR Staging": { - "11/2018": 208, - "12/2018": 457, - "01/2019": 671, - "02/2019": 136, - "03/2019": 1524, - "04/2019": 2077, - "05/2019": 1858, + "03/2018": 208, + "04/2018": 457, + "05/2018": 671, + "06/2018": 136, + "07/2018": 1524, + "08/2018": 2077, + "09/2018": 1858, }, - "CR Portal Test 1": {"03/2019": 806, "04/2019": 1966, "05/2019": 2597}, - "Jewels Prod": {"03/2019": 806, "04/2019": 1966, "05/2019": 2597}, + "CR Portal Test 1": {"07/2018": 806, "08/2018": 1966, "09/2018": 2597}, + "Jewels Prod": {"07/2018": 806, "08/2018": 1966, "09/2018": 2597}, "Jewels Dev": { - "11/2018": 145, - "12/2018": 719, - "01/2019": 1243, - "02/2019": 2214, - "03/2019": 2959, - "04/2019": 4151, - "05/2019": 4260, + "03/2018": 145, + "04/2018": 719, + "05/2018": 1243, + "06/2018": 2214, + "07/2018": 2959, + "08/2018": 4151, + "09/2018": 4260, }, }, } CUMULATIVE_BUDGET_AARDVARK = { - "10/2018": {"spend": 9857, "cumulative": 9857}, - "11/2018": {"spend": 7881, "cumulative": 17738}, - "12/2018": {"spend": 14010, "cumulative": 31748}, - "01/2019": {"spend": 43510, "cumulative": 75259}, - "02/2019": {"spend": 41725, "cumulative": 116984}, - "03/2019": {"spend": 41328, "cumulative": 158312}, - "04/2019": {"spend": 47491, "cumulative": 205803}, - "05/2019": {"spend": 45826, "cumulative": 251629}, - "06/2019": {"projected": 296511}, - "07/2019": {"projected": 341393}, - "08/2019": {"projected": 386274}, - "09/2019": {"projected": 431156}, + "02/2018": {"spend": 9857, "cumulative": 9857}, + "03/2018": {"spend": 7881, "cumulative": 17738}, + "04/2018": {"spend": 14010, "cumulative": 31748}, + "05/2018": {"spend": 43510, "cumulative": 75259}, + "06/2018": {"spend": 41725, "cumulative": 116984}, + "07/2018": {"spend": 41328, "cumulative": 158312}, + "08/2018": {"spend": 47491, "cumulative": 205803}, + "09/2018": {"spend": 45826, "cumulative": 251629}, } MONTHLY_SPEND_BELUGA = { "NP02": { - "Integ": {"02/2019": 284, "03/2019": 1210}, - "PreProd": {"02/2019": 812, "03/2019": 1389}, - "Prod": {"02/2019": 3742, "03/2019": 4716}, + "Integ": {"08/2018": 284, "09/2018": 1210}, + "PreProd": {"08/2018": 812, "09/2018": 1389}, + "Prod": {"08/2018": 3742, "09/2018": 4716}, }, - "FM": {"Integ": {"03/2019": 1498}, "Prod": {"03/2019": 5686}}, + "FM": {"Integ": {"08/2018": 1498}, "Prod": {"09/2018": 5686}}, } CUMULATIVE_BUDGET_BELUGA = { - "02/2019": {"spend": 4838, "cumulative": 4838}, - "03/2019": {"spend": 14500, "cumulative": 19338}, - "04/2019": {"projected": 29007}, - "05/2019": {"projected": 38676}, - "06/2019": {"projected": 48345}, - "07/2019": {"projected": 58014}, - "08/2019": {"projected": 67683}, - "09/2019": {"projected": 77352}, + "08/2018": {"spend": 4838, "cumulative": 4838}, + "09/2018": {"spend": 14500, "cumulative": 19338}, } From 7f6cebbc5f4a101656be41dcf52277ddfe59c6f6 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Wed, 19 Sep 2018 10:45:54 -0400 Subject: [PATCH 02/14] mock expiration date in workspace/reports route --- atst/routes/workspaces.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/atst/routes/workspaces.py b/atst/routes/workspaces.py index 673719a5..33eb2c57 100644 --- a/atst/routes/workspaces.py +++ b/atst/routes/workspaces.py @@ -106,6 +106,11 @@ def workspace_reports(workspace_id): prev_month = current_month - timedelta(days=28) two_months_ago = prev_month - timedelta(days=28) + # lets just say it expires on Christmas... ho ho ho + expiration_date = date(2018, 12, 25) + remaining_difference = expiration_date - current_month + remaining_days = remaining_difference.days + return render_template( "workspaces/reports/index.html", cumulative_budget=Reports.cumulative_budget(alternate_reports), @@ -114,6 +119,8 @@ def workspace_reports(workspace_id): current_month=current_month, prev_month=prev_month, two_months_ago=two_months_ago, + expiration_date=expiration_date, + remaining_days=remaining_days ) From 5242ab2e2ae445f379d94cc8096a6a82cea54888 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Wed, 19 Sep 2018 10:46:09 -0400 Subject: [PATCH 03/14] expiration styles for budget chart --- styles/components/_budget_chart.scss | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/styles/components/_budget_chart.scss b/styles/components/_budget_chart.scss index 92c22c39..0c37695e 100644 --- a/styles/components/_budget_chart.scss +++ b/styles/components/_budget_chart.scss @@ -67,6 +67,10 @@ fill: $color-aqua-lightest; } + &--is-expiration { + border-left: 2px dotted $color-gray; + } + &:hover { fill: $color-aqua-lightest; } @@ -96,6 +100,12 @@ } } + .budget-chart__expiration-line { + stroke-width: 2px; + stroke: $color-gray-light; + stroke-dasharray: 4px; + } + .budget-chart__cumulative__dot { fill: $color-gold; } From 9cc8ad75d289df7cec9573f9ebd9f0359d221868 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Wed, 19 Sep 2018 10:52:22 -0400 Subject: [PATCH 04/14] update budget chart component to add rolling average projections and expiration date --- js/components/charts/budget_chart.js | 86 +++++++++++++++++++++------- 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/js/components/charts/budget_chart.js b/js/components/charts/budget_chart.js index 68f071fe..1c84af0c 100644 --- a/js/components/charts/budget_chart.js +++ b/js/components/charts/budget_chart.js @@ -1,14 +1,15 @@ -import { format } from 'date-fns' +import { format, isWithinRange, addMonths, isSameMonth, getMonth } from 'date-fns' import { abbreviateDollars, formatDollars } from '../../lib/dollars' const TOP_OFFSET = 20 -const BOTTOM_OFFSET = 60 +const BOTTOM_OFFSET = 70 const CHART_HEIGHT = 360 export default { name: 'budget-chart', props: { currentMonth: String, + expirationDate: String, months: Object, budget: String }, @@ -46,18 +47,17 @@ export default { let lastSpendPoint = '' for (let i = 0; i < this.numMonths; i++) { - const { metrics, budget } = this.displayedMonths[i] + + console.log(this.displayedMonths[i]) + const { metrics, budget, rollingAverage, cumulativeTotal } = this.displayedMonths[i] const blockWidth = (this.width / this.numMonths) const blockX = blockWidth * i - const spend = budget - ? budget.spend || lastSpend - : 0 - const cumulative = budget - ? budget.cumulative || budget.projected - : 0 + const spend = budget && budget.spend + ? budget.spend + : rollingAverage const barHeight = spend / this.heightScale lastSpend = spend - const cumulativeY = this.height - (cumulative / this.heightScale) - BOTTOM_OFFSET + const cumulativeY = this.height - (cumulativeTotal / this.heightScale) - BOTTOM_OFFSET const cumulativeX = blockX + blockWidth/2 const cumulativePoint = `${cumulativeX} ${cumulativeY}` @@ -77,9 +77,7 @@ export default { this.spendPath += this.spendPath === '' ? 'M' : ' L' this.spendPath += cumulativePoint lastSpendPoint = cumulativePoint - } - - if (budget && budget.projected) { + } else { this.projectedPath += this.projectedPath === '' ? `M${lastSpendPoint} L` : ' L' this.projectedPath += cumulativePoint } @@ -88,32 +86,76 @@ export default { _setDisplayedMonths: function () { const [month, year] = this.currentMonth.split('/') + const [expYear, expMonth, expDate] = this.expirationDate.split('-') // assumes format 'YYYY-MM-DD' const monthsRange = [] - const monthsBack = this.focusedMonthPosition + const monthsBack = this.focusedMonthPosition + 1 const monthsForward = this.numMonths - this.focusedMonthPosition - 1 - const start = new Date(year, month - 1 - monthsBack) - let previousAmount = 0 + // currently focused date + const current = new Date(year, month) + + // starting date of the chart + const start = addMonths(current, -monthsBack) + + // ending date of the chart + const end = addMonths(start, this.numMonths + 1) + + // expiration date + const expires = new Date(expYear, expMonth-1, expDate) + + // is the expiration date within the displayed date range? + const expirationWithinRange = isWithinRange(expires, start, end) + + let rollingAverage = 0 + let cumulativeTotal = 0 for (let i = 0; i < this.numMonths; i++) { - const date = new Date(start.getFullYear(), start.getMonth() + i) + const date = addMonths(start, i) + const dateMinusOne = addMonths(date, -1) + const dateMinusTwo = addMonths(date, -2) + const dateMinusThree = addMonths(date, -3) + const index = format(date, 'MM/YYYY') + const indexMinusOne = format(dateMinusOne, 'MM/YYYY') + const indexMinusTwo = format(dateMinusTwo, 'MM/YYYY') + const indexMinusThree = format(dateMinusThree, 'MM/YYYY') + const budget = this.months[index] || null - const spendAmount = budget ? budget.spend || previousAmount : 0 - const cumulativeAmount = budget ? budget.cumulative || budget.projected : 0 - previousAmount = spendAmount + const spendAmount = budget ? budget.spend : rollingAverage + const spendMinusOne = this.months[indexMinusOne] ? this.months[indexMinusOne].spend : rollingAverage + const spendMinusTwo = this.months[indexMinusTwo] ? this.months[indexMinusTwo].spend : rollingAverage + const spendMinusThree = this.months[indexMinusThree] ? this.months[indexMinusThree].spend : rollingAverage + + const isExpirationMonth = isSameMonth(date, expires) + + if (budget && budget.cumulative) { + cumulativeTotal = budget.cumulative + } else { + cumulativeTotal += spendAmount + } + + rollingAverage = ( + spendAmount + + spendMinusOne + + spendMinusTwo + + spendMinusThree + ) / 4 monthsRange.push({ budget, + rollingAverage, + cumulativeTotal, + isExpirationMonth, spendAmount: formatDollars(spendAmount), abbreviatedSpend: abbreviateDollars(spendAmount), - cumulativeAmount: formatDollars(cumulativeAmount), - abbreviatedCumulative: abbreviateDollars(cumulativeAmount), + cumulativeAmount: formatDollars(cumulativeTotal), + abbreviatedCumulative: abbreviateDollars(cumulativeTotal), date: { monthIndex: format(date, 'M'), month: format(date, 'MMM'), year: format(date,'YYYY') }, + showYear: isExpirationMonth || (i === 0) || getMonth(date) === 0, isHighlighted: this.currentMonth === index, metrics: { blockWidth: 0, From 05d0028b3b9e19d336fdace3f13bb7292c43a0e2 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Wed, 19 Sep 2018 10:54:09 -0400 Subject: [PATCH 05/14] Add expiration date and remaining days to reports template --- templates/workspaces/reports/index.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/templates/workspaces/reports/index.html b/templates/workspaces/reports/index.html index 0f763890..ddbf02c3 100644 --- a/templates/workspaces/reports/index.html +++ b/templates/workspaces/reports/index.html @@ -63,12 +63,17 @@
Expires
-
November 1, 2019
+
+ + +
Remaining
-
200 days
+
{{ remaining_days }} days
From 715f27dcc3ade1020183cad6459908e7fc017578 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Wed, 19 Sep 2018 10:56:59 -0400 Subject: [PATCH 06/14] Add expiration month to budget chart --- templates/workspaces/reports/index.html | 43 +++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/templates/workspaces/reports/index.html b/templates/workspaces/reports/index.html index ddbf02c3..903ed4be 100644 --- a/templates/workspaces/reports/index.html +++ b/templates/workspaces/reports/index.html @@ -102,7 +102,12 @@ {% set two_months_ago_index = two_months_ago.strftime('%m/%Y') %} {% set reports_url = url_for("workspaces.workspace_reports", workspace_id=workspace.id) %} - +

Cumulative Budget

@@ -153,7 +158,7 @@ {# container block #} @@ -168,6 +173,31 @@ v-bind:x='month.metrics.barX' v-bind:y='month.metrics.barY'> + {# projected budget bar #} + + + {# task order expiration line #} + + + {# task order expiration label #} + T.O. Expires + {# cumulative dot #} + + {# year label #} + From 84cbbd2b176f02cc09c140c475b4769c793bb353 Mon Sep 17 00:00:00 2001 From: Andrew Croce Date: Wed, 19 Sep 2018 11:49:20 -0400 Subject: [PATCH 07/14] Add a filter to put background color on chart labels --- templates/workspaces/reports/index.html | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/templates/workspaces/reports/index.html b/templates/workspaces/reports/index.html index 903ed4be..05e33d2f 100644 --- a/templates/workspaces/reports/index.html +++ b/templates/workspaces/reports/index.html @@ -137,9 +137,45 @@
+ + + + + + + + + {# spend/projected budget path lines #} + + + + {# max budget line #} + + + {# make this clickable to focus on that month #} + + + + + + + +  |