Skip to content

Commit b0a4fb0

Browse files
feat(TargetUnit): Add DepTech hours calculation and Redmine custom field IDs (#71)
- Add constants for Redmine custom field IDs to weeklyFinancialReport config - Refactor TargetUnit query to support DepTech hours calculation - Improve SQL structure for group and project time aggregation These changes enhance the flexibility and accuracy of the weekly financial report generation process.
1 parent b9b27b8 commit b0a4fb0

File tree

2 files changed

+94
-39
lines changed

2 files changed

+94
-39
lines changed

workers/main/src/configs/weeklyFinancialReport.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@ export enum GroupNameEnum {
55

66
export const HIGH_MARGINALITY_THRESHOLD = 55;
77
export const MEDIUM_MARGINALITY_THRESHOLD = 45;
8+
9+
// ID of the custom field in Redmine used for report filtering
10+
export const REPORT_FILTER_FIELD_ID = 253;
11+
12+
// ID of the custom field in Redmine used to link issue to Billable project
13+
export const RELATED_PROJECT_FIELD_ID = 20;
Lines changed: 88 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,99 @@
1-
export const TARGET_UNITS_QUERY = `SELECT
1+
import {
2+
GroupNameEnum,
3+
RELATED_PROJECT_FIELD_ID,
4+
REPORT_FILTER_FIELD_ID,
5+
} from '../../configs/weeklyFinancialReport';
6+
7+
const groupNamesList = Object.values(GroupNameEnum)
8+
.map((name) => `'${name.replace(/'/g, "''")}'`)
9+
.join(', ');
10+
11+
const COMMON_SELECT = `
12+
SELECT
13+
g.id AS group_id,
14+
g.lastname AS group_name,
15+
p.id AS project_id,
16+
p.name AS project_name,
17+
te.user_id AS user_id,
18+
CONCAT(u.firstname, ' ', u.lastname) AS username,
19+
te.spent_on AS spent_on,
20+
cv.value AS filter_name,
21+
`;
22+
23+
const COMMON_FROM = `
24+
FROM users AS g
25+
JOIN custom_values as cv ON cv.customized_id = g.id
26+
JOIN members AS m ON m.user_id = g.id
27+
JOIN projects AS p ON p.id = m.project_id
28+
`;
29+
30+
const COMMON_WHERE = `
31+
WHERE g.type = 'Group'
32+
AND cv.customized_type = 'Principal'
33+
AND cv.custom_field_id = ${REPORT_FILTER_FIELD_ID}
34+
AND cv.value IN (${groupNamesList})
35+
AND te.spent_on BETWEEN DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) + 7 DAY)
36+
AND DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) + 1 DAY)
37+
`;
38+
39+
function buildDirectGroupTimeEntries() {
40+
return `
41+
${COMMON_SELECT}
42+
te.hours AS project_hours,
43+
0 as deptech_hours
44+
${COMMON_FROM}
45+
JOIN time_entries te ON te.project_id = p.id
46+
JOIN users AS u ON u.id = te.user_id
47+
${COMMON_WHERE}
48+
`;
49+
}
50+
51+
function buildRelatedProjectTimeEntries() {
52+
return `
53+
${COMMON_SELECT}
54+
0 as project_hours,
55+
te.hours AS deptech_hours
56+
${COMMON_FROM}
57+
JOIN custom_values icv ON icv.value = CAST(p.id AS CHAR)
58+
AND icv.customized_type = 'Issue'
59+
AND icv.custom_field_id = ${RELATED_PROJECT_FIELD_ID}
60+
AND icv.value <> ""
61+
JOIN time_entries te ON te.issue_id = icv.customized_id
62+
JOIN users AS u ON u.id = te.user_id
63+
${COMMON_WHERE}
64+
`;
65+
}
66+
67+
export const TARGET_UNITS_QUERY = `
68+
SELECT
269
group_id,
370
group_name,
471
project_id,
572
project_name,
673
user_id,
774
username,
875
DATE_FORMAT(spent_on, '%Y-%m-%d') AS spent_on,
9-
SUM(total_hours) AS total_hours
76+
SUM(project_hours) AS project_hours,
77+
SUM(deptech_hours) AS deptech_hours,
78+
SUM(project_hours) + SUM(deptech_hours) AS total_hours,
79+
filter_name
1080
FROM (
11-
SELECT
12-
g.id AS group_id,
13-
g.lastname AS group_name,
14-
p.id AS project_id,
15-
p.name AS project_name,
16-
te.user_id AS user_id,
17-
CONCAT(u.firstname, ' ', u.lastname) AS username,
18-
te.spent_on AS spent_on,
19-
te.hours AS total_hours
20-
FROM users AS g
21-
JOIN custom_values as cv ON cv.customized_id = g.id
22-
JOIN members AS m ON m.user_id = g.id
23-
JOIN projects AS p ON p.id = m.project_id
24-
JOIN time_entries te ON te.project_id = p.id
25-
JOIN users AS u ON u.id = te.user_id
26-
WHERE g.type = 'Group'
27-
AND cv.customized_type = 'Principal' and cv.value = ?
28-
AND te.spent_on BETWEEN
29-
DATE_FORMAT(
30-
DATE_SUB(
31-
DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) + 1 DAY),
32-
INTERVAL (MONTH(DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) + 1 DAY))-1)%3 MONTH
33-
),
34-
'%Y-%m-01'
35-
)
36-
AND DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) + 1 DAY)
81+
${buildDirectGroupTimeEntries()}
82+
UNION ALL
83+
${buildRelatedProjectTimeEntries()}
3784
) t
3885
GROUP BY
39-
group_id,
40-
group_name,
41-
project_id,
42-
project_name,
43-
user_id,
44-
username,
45-
spent_on
86+
t.group_id,
87+
t.group_name,
88+
t.project_id,
89+
t.project_name,
90+
t.user_id,
91+
t.username,
92+
t.spent_on,
93+
t.filter_name
4694
ORDER BY
47-
group_name ASC,
48-
project_name ASC,
49-
username ASC,
50-
spent_on ASC`;
95+
t.group_name ASC,
96+
t.project_name ASC,
97+
t.username ASC,
98+
t.spent_on ASC
99+
`;

0 commit comments

Comments
 (0)