Skip to content

Commit

Permalink
Feature/hourly pay quartile text (#172)
Browse files Browse the repository at this point in the history
Co-authored-by: Sukanya Rath <[email protected]>
  • Loading branch information
banders and sukanya-rath authored Jan 23, 2024
1 parent 5e1ba0a commit b08eff3
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 24 deletions.
32 changes: 30 additions & 2 deletions backend/src/v1/services/report-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,16 +369,44 @@ describe('getHoursGapTextSummary', () => {
expect(text).toContain('overtime hours');
expect(text).toContain(
Math.abs(mockCalcs[CALCULATION_CODES.MEDIAN_OT_HOURS_DIFF_W].value) +
' less',
' less',
);
expect(text).toContain(
Math.abs(mockCalcs[CALCULATION_CODES.MEDIAN_OT_HOURS_DIFF_X].value) +
' more',
' more',
);
});
});
});

describe('getHourlyPayQuartilesTextSummary', () => {
describe('given the ref gender category and hourly pay Q1 and Q4 data', () => {
it('returns a text summary of the upper and lower quartiles', () => {
const referenceGenderCode = GENDERS.MALE.code;
const mockHourlyPayQuartile4 = [
{ genderChartInfo: GENDERS.MALE, value: 45 },
{ genderChartInfo: GENDERS.FEMALE, value: 45 },
{ genderChartInfo: GENDERS.NON_BINARY, value: 1 },
{ genderChartInfo: GENDERS.UNKNOWN, value: 9 },
];
const mockHourlyPayQuartile1 = [
{ genderChartInfo: GENDERS.MALE, value: 55 },
{ genderChartInfo: GENDERS.FEMALE, value: 35 },
{ genderChartInfo: GENDERS.UNKNOWN, value: 10 },
];
const text: string = reportServicePrivate.getHourlyPayQuartilesTextSummary(
referenceGenderCode,
mockHourlyPayQuartile4,
mockHourlyPayQuartile1
);
console.log(text);
expect(text.toLowerCase()).toContain(`${GENDERS.FEMALE.extendedLabel} occupy 45% of the highest paid jobs and 35% of the lowest`.toLowerCase());
expect(text.toLowerCase()).toContain(`${GENDERS.NON_BINARY.extendedLabel} occupy 1% of the highest paid jobs.`.toLowerCase());

});
});
});

describe('dollarsToText', () => {
describe('when a value less than 1 is specified', () => {
it('returns a value in cents', () => {
Expand Down
49 changes: 49 additions & 0 deletions backend/src/v1/services/report-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,50 @@ const reportServicePrivate = {
return result;
},

/*
Creates a text summary of the 4th and 1st hourly pay quartiles
in a form similar to:
"In this organization, women occupy 30% of the highest paid
jobs and 56% of the lowest paid jobs. Non-binary people occupy
1% of the highest paid jobs and 2% of the lowest paid jobs."
*/
getHourlyPayQuartilesTextSummary(
referenceGenderCode: string,
hourlyPayQuartile4: ChartDataRecord[],
hourlyPayQuartile1: ChartDataRecord[]): string {
const genderCodesToSkip = [referenceGenderCode, GENDERS.UNKNOWN.code];
const genderCodesToSummarize = Object.values(GENDERS).filter(d => genderCodesToSkip.indexOf(d.code) == -1);

const genderSummaries = [];
genderCodesToSummarize.forEach((g, i) => {
const genderLabel = i == 0 ? g.extendedLabel.toLocaleLowerCase() : g.extendedLabel;
const q4 = hourlyPayQuartile4.filter(c => c.genderChartInfo.code == g.code);
const q1 = hourlyPayQuartile1.filter(c => c.genderChartInfo.code == g.code);
const quartileSummaries = [];
if (q4.length) {
const q4Percent = Math.round(q4[0].value);
quartileSummaries.push(`${q4Percent}% of the highest paid jobs`);
}
if (q1.length) {
const q1Percent = Math.round(q1[0].value);
quartileSummaries.push(`${q1Percent}% of the lowest paid jobs`);
}
if (quartileSummaries.length) {
genderSummaries.push(`${genderLabel} occupy ${quartileSummaries.join(' and ')}`);
}
});

let text = null;
if (genderSummaries.length) {
text = `In this organization, ${genderSummaries[0]}.`;
}
for (let i = 1; i < genderSummaries.length; i++) {
text += ` ${genderSummaries[i]}.`
}

return text;
},

/*
converts a number representing an amount in dollars (such as 1.20 or 0.95)
into a string according to the following rules:
Expand Down Expand Up @@ -771,6 +815,11 @@ const reportService = {
'median',
'overtime hours',
),
hourlyPayQuartiles: reportServicePrivate.getHourlyPayQuartilesTextSummary(
referenceGenderCode,
chartData.hourlyPayQuartile4,
chartData.hourlyPayQuartile1,
),
};

const referenceGenderChartInfo =
Expand Down
66 changes: 44 additions & 22 deletions doc-gen-service/src/templates/report.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -521,38 +521,59 @@ <h2>Percentage of each gender in each pay quartile</h2><sup>
</div>
</div>

<table role="presentation">
<table role="presentation" class="mb-2">
<tr>
<td class="pe-2" style="width: 80%">
<div>
<td class="pe-2" style="width:600px">
<div id=" hourly-pay-quartiles">
<div id="hourly-pay-quartile-4">
<div class="text-normal">Upper hourly pay quartile (highest paid)</div>
<% if (chartData.hourlyPayQuartile4.length) { %>
<div id="hourly-pay-quartile-4-chart"></div>
<% } %>
<% var q4HasSuppressed=chartData.hourlyPayQuartile4.length < 4; %>
<div class="text-normal">Upper hourly pay quartile (highest paid)<% if (q4HasSuppressed) { %>*<% } %>
</div>
<% if (chartData.hourlyPayQuartile4.length) { %>
<div id="hourly-pay-quartile-4-chart"></div>
<% } %>
</div>
<div id="hourly-pay-quartile-3">
<div class="text-normal">Upper middle hourly pay quartile</div>
<% if (chartData.hourlyPayQuartile3.length) { %>
<div id="hourly-pay-quartile-3-chart"></div>
<% } %>
<% var q3HasSuppressed=chartData.hourlyPayQuartile3.length < 4; %>
<div class="text-normal">Upper middle hourly pay quartile<% if (q3HasSuppressed) { %>*<% } %>
</div>
<% if (chartData.hourlyPayQuartile3.length) { %>
<div id="hourly-pay-quartile-3-chart"></div>
<% } %>
</div>
<div id="hourly-pay-quartile-2">
<div class="text-normal">Lower middle hourly pay quartile</div>
<% if (chartData.hourlyPayQuartile2.length) { %>
<div id="hourly-pay-quartile-2-chart"></div>
<% } %>
<% var q2HasSuppressed=chartData.hourlyPayQuartile2.length < 4; %>
<div class="text-normal">Lower middle hourly pay quartile<% if (q2HasSuppressed) { %>*<% } %>
</div>
<% if (chartData.hourlyPayQuartile2.length) { %>
<div id="hourly-pay-quartile-2-chart"></div>
<% } %>
</div>
<div id="hourly-pay-quartile-1">
<div class="text-normal">Lowest hourly pay quartile (lowest paid)</div>
<% if (chartData.hourlyPayQuartile1.length) { %>
<div id="hourly-pay-quartile-1-chart"></div>
<% } %>
<% var q1HasSuppressed=chartData.hourlyPayQuartile1.length < 4; %>
<div class="text-normal">Lowest hourly pay quartile (lowest paid)<% if (q1HasSuppressed) { %>*<% } %>
</div>
<% if (chartData.hourlyPayQuartile1.length) { %>
<div id="hourly-pay-quartile-1-chart"></div>
<% } %>
</div>
</div>
</td>
<td class="pe-2" style="width: 20%">
<div id="hourly-pay-quartiles-legend"></div>
<td class="pe-2">
<div id="hourly-pay-quartiles-legend" class="ml-6"></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="text-normal mt-2 mb-2">
<p>
<%= chartSummaryText.hourlyPayQuartiles %>
</p>
<% if (q1HasSuppressed || q2HasSuppressed || q3HasSuppressed || q4HasSuppressed) { %>
<p>* This pay quartile was reduced to suppress gender categories consisting of less than ten (10)
employees.</p>
<% } %>
</div>
</td>
</tr>
</table>
Expand All @@ -563,7 +584,8 @@ <h4>Explanatory notes</h4>
<div class="footnote-number">
<%= explanatoryNotes.payQuartiles.num %>.
</div>
<div></div>
<div>&quot;Pay quartile&quot; refers to the percentage of each gender within four equal sized groups based on
their hourly pay.</div>
</div>
</div>

Expand Down

0 comments on commit b08eff3

Please sign in to comment.