This commit is contained in:
Flatlogic Bot 2026-05-01 13:50:27 +00:00
parent f4182557a8
commit 1fd0a1b094
6 changed files with 164 additions and 10 deletions

View File

@ -407,7 +407,13 @@ module.exports = class UsersDBApi {
output.employee_pay_types_employee = await users.getEmployee_pay_types_employee({ output.employee_pay_types_employee = await users.getEmployee_pay_types_employee({
transaction transaction,
include: [
{
model: db.pay_types,
as: 'pay_type',
},
],
}); });
@ -501,6 +507,21 @@ module.exports = class UsersDBApi {
as: 'avatar', as: 'avatar',
}, },
{
model: db.employee_pay_types,
as: 'employee_pay_types_employee',
required: false,
where: {
active: true,
},
include: [
{
model: db.pay_types,
as: 'pay_type',
},
],
},
]; ];
if (filter) { if (filter) {

View File

@ -13,6 +13,63 @@ const EmailSender = require('./email');
const AuthService = require('./auth'); const AuthService = require('./auth');
module.exports = class UsersService { module.exports = class UsersService {
static normalizePayTypeIds(payTypes = []) {
return [...new Set((payTypes || [])
.map((payType) => {
if (typeof payType === 'string') {
return payType;
}
return payType?.id || payType?.value || null;
})
.filter(Boolean))];
}
static async syncEmployeePayTypes(employeeId, payTypes, currentUser, transaction) {
const payTypeIds = UsersService.normalizePayTypeIds(payTypes);
const selectedPayTypeIds = new Set(payTypeIds);
const existingAssignments = await db.employee_pay_types.findAll({
where: { employeeId },
transaction,
});
const existingPayTypeIds = new Set();
for (const assignment of existingAssignments) {
existingPayTypeIds.add(assignment.pay_typeId);
const shouldBeActive = selectedPayTypeIds.has(assignment.pay_typeId);
if (assignment.active !== shouldBeActive) {
await assignment.update(
{
active: shouldBeActive,
updatedById: currentUser.id,
},
{ transaction },
);
}
}
for (const payTypeId of payTypeIds) {
if (existingPayTypeIds.has(payTypeId)) {
continue;
}
await db.employee_pay_types.create(
{
employeeId,
pay_typeId: payTypeId,
active: true,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
}
}
static async create(data, currentUser, sendInvitationEmails = true, host) { static async create(data, currentUser, sendInvitationEmails = true, host) {
let transaction = await db.sequelize.transaction(); let transaction = await db.sequelize.transaction();
@ -26,7 +83,7 @@ module.exports = class UsersService {
'iam.errors.userAlreadyExists', 'iam.errors.userAlreadyExists',
); );
} else { } else {
await UsersDBApi.create( const createdUser = await UsersDBApi.create(
{data}, {data},
{ {
@ -34,6 +91,15 @@ module.exports = class UsersService {
transaction, transaction,
}, },
); );
if (data.pay_types !== undefined) {
await UsersService.syncEmployeePayTypes(
createdUser.id,
data.pay_types,
currentUser,
transaction,
);
}
emailsToInvite.push(email); emailsToInvite.push(email);
} }
} else { } else {
@ -127,6 +193,15 @@ module.exports = class UsersService {
}, },
); );
if (data.pay_types !== undefined) {
await UsersService.syncEmployeePayTypes(
id,
data.pay_types,
currentUser,
transaction,
);
}
await transaction.commit(); await transaction.commit();
return updatedUser; return updatedUser;

View File

@ -17,6 +17,15 @@ import {hasPermission} from "../../helpers/userPermissions";
type Params = (id: string) => void; type Params = (id: string) => void;
const formatAssignedPayTypes = (assignments = []) => {
const uniquePayTypeNames = [...new Set((assignments || [])
.filter((assignment) => assignment?.active !== false)
.map((assignment) => assignment?.pay_type?.name)
.filter(Boolean))];
return uniquePayTypeNames.length ? uniquePayTypeNames.join(', ') : '—';
};
export const loadColumns = async ( export const loadColumns = async (
onDelete: Params, onDelete: Params,
entityName: string, entityName: string,
@ -180,6 +189,27 @@ export const loadColumns = async (
}, },
{
field: 'employee_pay_types_employee',
headerName: 'Pay Types',
flex: 1,
minWidth: 180,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: false,
sortable: false,
valueGetter: (params: GridValueGetterParams) =>
formatAssignedPayTypes(params?.row?.employee_pay_types_employee),
renderCell: (params: GridValueGetterParams) => (
<span className='whitespace-normal leading-5 py-2'>
{formatAssignedPayTypes(params?.row?.employee_pay_types_employee)}
</span>
),
},
{ {
field: 'actions', field: 'actions',
type: 'actions', type: 'actions',

View File

@ -261,6 +261,7 @@ const EditUsersPage = () => {
custom_permissions: [], custom_permissions: [],
pay_types: [],
@ -278,16 +279,17 @@ const EditUsersPage = () => {
dispatch(fetch({ id: id })) dispatch(fetch({ id: id }))
}, [id]) }, [id])
useEffect(() => {
if (typeof users === 'object') {
setInitialValues(users)
}
}, [users])
useEffect(() => { useEffect(() => {
if (typeof users === 'object') { if (typeof users === 'object') {
const newInitialVal = {...initVals}; const newInitialVal = {...initVals};
Object.keys(initVals).forEach(el => newInitialVal[el] = (users)[el]) Object.keys(initVals).forEach((el) => {
newInitialVal[el] = users[el]
})
newInitialVal.pay_types = Array.isArray(users.employee_pay_types_employee)
? users.employee_pay_types_employee
.filter((item) => item?.active && item?.pay_type)
.map((item) => item.pay_type)
: []
setInitialValues(newInitialVal); setInitialValues(newInitialVal);
} }
}, [users]) }, [users])
@ -676,6 +678,18 @@ const EditUsersPage = () => {
<FormField label='Pay Types' labelFor='pay_types'>
<Field
name='pay_types'
id='pay_types'
component={SelectFieldMany}
options={initialValues.pay_types}
itemRef={'pay_types'}
showField={'name'}
></Field>
</FormField>
<FormField <FormField
label="Password" label="Password"
> >

View File

@ -155,6 +155,7 @@ const initialValues = {
custom_permissions: [], custom_permissions: [],
pay_types: [],
} }
@ -469,7 +470,16 @@ const UsersNew = () => {
</Field> </Field>
</FormField> </FormField>
<FormField label='Pay Types' labelFor='pay_types'>
<Field
name='pay_types'
id='pay_types'
itemRef={'pay_types'}
options={[]}
component={SelectFieldMany}
showField={'name'}>
</Field>
</FormField>

View File

@ -433,6 +433,7 @@ const UsersView = () => {
<th>Pay Type</th>
<th>Active</th> <th>Active</th>
@ -456,6 +457,9 @@ const UsersView = () => {
<td data-label="pay_type">
{item?.pay_type?.name ?? 'No data'}
</td>
<td data-label="active"> <td data-label="active">
{ dataFormatter.booleanFormatter(item.active) } { dataFormatter.booleanFormatter(item.active) }
</td> </td>