fix
All checks were successful
Build And Deploy Main / build-and-deploy (push) Successful in 34s

This commit is contained in:
2026-03-16 15:46:37 -04:00
parent 397043807b
commit 08756fc941
3 changed files with 60 additions and 73 deletions

View File

@@ -326,19 +326,23 @@ exports.getExternalEmployeesList = async (req, res) => {
timeout: 15000,
httpsAgent: HR_INSECURE_HTTPS_AGENT
};
const currentSite = splitSite.findSiteNumber(req);
const requestBodies = [
const requestedSite = Number(req.query?.site || req.body?.site);
const hasRequestedSite = Number.isInteger(requestedSite) && requestedSite > 0;
const requestBodies = hasRequestedSite
? [
{
username: HR_INTEGRATION_USERNAME,
password: HR_INTEGRATION_PASSWORD,
site: currentSite,
site: requestedSite,
status: "active"
},
{
username: HR_INTEGRATION_USERNAME,
password: HR_INTEGRATION_PASSWORD,
site: currentSite
},
site: requestedSite
}
]
: [
{
username: HR_INTEGRATION_USERNAME,
password: HR_INTEGRATION_PASSWORD,
@@ -351,6 +355,20 @@ exports.getExternalEmployeesList = async (req, res) => {
];
const normalizeEmployeesList = (raw) => {
if (Array.isArray(raw)) return raw;
if (typeof raw === "string") {
const trimmed = raw.trim();
if (!trimmed) return [];
try {
const parsed = JSON.parse(trimmed);
if (Array.isArray(parsed)) return parsed;
if (Array.isArray(parsed?.data)) return parsed.data;
if (Array.isArray(parsed?.employees)) return parsed.employees;
if (Array.isArray(parsed?.result)) return parsed.result;
if (Array.isArray(parsed?.results)) return parsed.results;
} catch (_err) {
return [];
}
}
if (Array.isArray(raw?.data)) return raw.data;
if (Array.isArray(raw?.employees)) return raw.employees;
if (Array.isArray(raw?.result)) return raw.result;
@@ -362,35 +380,19 @@ exports.getExternalEmployeesList = async (req, res) => {
let bestResponseData = null;
for (const requestBody of requestBodies) {
try {
console.log("[HR Integration] Requesting employee list from:", HR_EMPLOYEE_LIST_ENDPOINT, "payload:", requestBody);
const response = await axios.post(HR_EMPLOYEE_LIST_ENDPOINT, requestBody, requestOptions);
const list = normalizeEmployeesList(response?.data);
console.log(
"[HR Integration] employee list response meta:",
{ endpoint: HR_EMPLOYEE_LIST_ENDPOINT, count: list.length, responseType: typeof response?.data }
);
console.log("[HR Integration] raw employee list response:", response?.data);
bestResponseData = response?.data;
if (list.length > 0) {
return res.send(list);
}
} catch (attemptError) {
console.log("[HR Integration] employee list attempt failed:", {
endpoint: HR_EMPLOYEE_LIST_ENDPOINT,
payload: requestBody,
status: attemptError?.response?.status,
data: attemptError?.response?.data,
message: attemptError?.message
});
} catch (_attemptError) {
// Try next payload variant.
}
}
const emptyList = normalizeEmployeesList(bestResponseData);
console.log("[HR Integration] all attempts completed; returning list length:", emptyList.length);
return res.send(emptyList);
} catch (err) {
console.log("[HR Integration] /employees/list error status:", err?.response?.status);
console.log("[HR Integration] /employees/list error data:", err?.response?.data);
console.log("[HR Integration] /employees/list error message:", err?.message);
res.status(500).send({
message: err?.response?.data?.message || err.message || "Failed to fetch employees from HR system."
});

View File

@@ -8,6 +8,7 @@ const SYSTEM_ACCESS_PERMISSION = "System Access";
const EmployeeList = () => {
const navigate = useNavigate();
const currentSite = EventsService.site || 3;
const [employees, setEmployees] = useState([]);
const [keyword, setKeyword] = useState('');
const [showInactive, setShowInactive] = useState(false);
@@ -15,7 +16,6 @@ const EmployeeList = () => {
const [isHrLoading, setIsHrLoading] = useState(false);
const [isSavingHrPermission, setIsSavingHrPermission] = useState(false);
const [hrKeyword, setHrKeyword] = useState('');
const [hrSiteFilter, setHrSiteFilter] = useState(EventsService.site || 3);
const [hrPermissionMap, setHrPermissionMap] = useState({});
const [editingHrUser, setEditingHrUser] = useState(undefined);
const [showHrPermissionModal, setShowHrPermissionModal] = useState(false);
@@ -31,25 +31,16 @@ const EmployeeList = () => {
setEmployees(data.data)
);
loadHrUsers();
loadHrPermissionsBySite(currentSite);
}, []);
useEffect(() => {
loadHrPermissionsBySite(hrSiteFilter);
}, [hrSiteFilter]);
const loadHrUsers = () => {
setIsHrLoading(true);
EmployeeService.getExternalEmployeesList()
.then((response) => {
console.log('[HR Debug][EmployeeList] backend /employees/external/list response:', response?.data);
setHrUsers(Array.isArray(response?.data) ? response.data : []);
})
.catch((error) => {
console.log('[HR Debug][EmployeeList] /employees/external/list error:', {
status: error?.response?.status,
data: error?.response?.data,
message: error?.message
});
window.alert(error?.response?.data?.message || 'Failed to load HR users.');
})
.finally(() => {
@@ -95,9 +86,12 @@ const EmployeeList = () => {
}
const filteredHrUsers = useMemo(() => {
const site = Number(hrSiteFilter);
return (hrUsers || [])
.filter((item) => Number(item?.site) === site)
.filter((item) => Number(item?.site) === Number(currentSite))
.filter((item) => {
const configuredPermissions = hrPermissionMap?.[item?.employee_id] || [];
return configuredPermissions.length > 0;
})
.filter((item) => {
if (!hrKeyword) return true;
const key = hrKeyword.toLowerCase();
@@ -107,7 +101,7 @@ const EmployeeList = () => {
(item?.title || '').toLowerCase().includes(key)
);
});
}, [hrUsers, hrKeyword, hrSiteFilter]);
}, [hrUsers, hrKeyword, hrPermissionMap, currentSite]);
const openHrPermissionModal = (hrUser) => {
setEditingHrUser(hrUser);
@@ -141,7 +135,7 @@ const EmployeeList = () => {
username: editingHrUser.username || '',
name: editingHrUser.name || '',
email: editingHrUser.email || '',
allow_site: Number(hrSiteFilter),
allow_site: Number(currentSite),
permissions: selectedHrPermissions
})
.then(() => {
@@ -161,10 +155,10 @@ const EmployeeList = () => {
const revokeHrPermissions = (hrUser) => {
if (!hrUser?.employee_id) return;
if (!window.confirm(`Revoke all permissions for ${hrUser?.username || 'this HR user'} on Site ${hrSiteFilter}?`)) {
if (!window.confirm(`Revoke all permissions for ${hrUser?.username || 'this HR user'} on Site ${currentSite}?`)) {
return;
}
EmployeeService.revokeExternalUserPermission(hrUser.employee_id, Number(hrSiteFilter))
EmployeeService.revokeExternalUserPermission(hrUser.employee_id, Number(currentSite))
.then(() => {
setHrPermissionMap((prev) => {
const next = { ...prev };
@@ -202,18 +196,13 @@ const EmployeeList = () => {
<h6 className="text-primary">HR System Users</h6>
<div className="mb-3 d-flex align-items-center" style={{ gap: '12px', flexWrap: 'wrap' }}>
<label>
Site:
<select className="ms-2" value={hrSiteFilter} onChange={(e) => setHrSiteFilter(Number(e.currentTarget.value))}>
<option value={1}>Site 1</option>
<option value={2}>Site 2</option>
<option value={3}>Site 3</option>
</select>
Site: <strong className="ms-2">{currentSite}</strong>
</label>
<label>
Filter:
<input className="ms-2" type="text" value={hrKeyword} onChange={(e) => setHrKeyword(e.currentTarget.value)} />
</label>
<button className="btn btn-primary btn-sm" onClick={() => {loadHrUsers(); loadHrPermissionsBySite(hrSiteFilter);}} disabled={isHrLoading}>
<button className="btn btn-primary btn-sm" onClick={() => {loadHrUsers(); loadHrPermissionsBySite(currentSite);}} disabled={isHrLoading}>
{isHrLoading ? 'Loading...' : 'Refresh HR Users'}
</button>
</div>
@@ -299,7 +288,7 @@ const EmployeeList = () => {
</Modal.Header>
<Modal.Body>
<div className="mb-3">
<strong>Allow Site:</strong> {hrSiteFilter}
<strong>Allow Site:</strong> {currentSite}
</div>
{Object.entries(EMPLOYEE_PERMISSION_GROUPS).map(([groupName, permissionItems]) => (
<div key={groupName} className="mb-3">

View File

@@ -11,7 +11,7 @@ const ExternalEmployeesImport = () => {
const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false);
const [employees, setEmployees] = useState([]);
const [siteFilter, setSiteFilter] = useState('all');
const [siteFilter, setSiteFilter] = useState(EventsService.site || 3);
const [keyword, setKeyword] = useState("");
const [showPermissionModal, setShowPermissionModal] = useState(false);
const [selectedEmployee, setSelectedEmployee] = useState(undefined);
@@ -32,15 +32,9 @@ const ExternalEmployeesImport = () => {
setLoading(true);
EmployeeService.getExternalEmployeesList()
.then((response) => {
console.log("[HR Debug][ExternalEmployeesImport] backend /employees/external/list response:", response?.data);
setEmployees(Array.isArray(response?.data) ? response.data : []);
})
.catch((error) => {
console.log("[HR Debug][ExternalEmployeesImport] /employees/external/list error:", {
status: error?.response?.status,
data: error?.response?.data,
message: error?.message
});
window.alert(error?.response?.data?.message || "Failed to load employees from HR system.");
})
.finally(() => {
@@ -146,6 +140,8 @@ const ExternalEmployeesImport = () => {
<option value={1}>Site 1</option>
<option value={2}>Site 2</option>
<option value={3}>Site 3</option>
<option value={4}>Site 4</option>
<option value={5}>Site 5</option>
</select>
</label>
<label>