Updated via schema editor on 2025-06-19 01:34

This commit is contained in:
Flatlogic Bot 2025-06-19 01:35:28 +00:00
parent da7c3a9bf4
commit a4c8cac57d
28 changed files with 446 additions and 12 deletions

File diff suppressed because one or more lines are too long

View File

@ -19,6 +19,7 @@ module.exports = class UnitsDBApi {
balance: data.balance || null, balance: data.balance || null,
unit_factor: data.unit_factor || null, unit_factor: data.unit_factor || null,
cond_fee: data.cond_fee || null, cond_fee: data.cond_fee || null,
parking_stall: data.parking_stall || null,
importHash: data.importHash || null, importHash: data.importHash || null,
createdById: currentUser.id, createdById: currentUser.id,
updatedById: currentUser.id, updatedById: currentUser.id,
@ -45,6 +46,7 @@ module.exports = class UnitsDBApi {
balance: item.balance || null, balance: item.balance || null,
unit_factor: item.unit_factor || null, unit_factor: item.unit_factor || null,
cond_fee: item.cond_fee || null, cond_fee: item.cond_fee || null,
parking_stall: item.parking_stall || null,
importHash: item.importHash || null, importHash: item.importHash || null,
createdById: currentUser.id, createdById: currentUser.id,
updatedById: currentUser.id, updatedById: currentUser.id,
@ -77,6 +79,9 @@ module.exports = class UnitsDBApi {
if (data.cond_fee !== undefined) updatePayload.cond_fee = data.cond_fee; if (data.cond_fee !== undefined) updatePayload.cond_fee = data.cond_fee;
if (data.parking_stall !== undefined)
updatePayload.parking_stall = data.parking_stall;
updatePayload.updatedById = currentUser.id; updatePayload.updatedById = currentUser.id;
await units.update(updatePayload, { transaction }); await units.update(updatePayload, { transaction });
@ -150,6 +155,10 @@ module.exports = class UnitsDBApi {
const output = units.get({ plain: true }); const output = units.get({ plain: true });
output.users_unit = await units.getUsers_unit({
transaction,
});
output.maintenance_requests_unit = await units.getMaintenance_requests_unit( output.maintenance_requests_unit = await units.getMaintenance_requests_unit(
{ {
transaction, transaction,
@ -290,6 +299,30 @@ module.exports = class UnitsDBApi {
} }
} }
if (filter.parking_stallRange) {
const [start, end] = filter.parking_stallRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
parking_stall: {
...where.parking_stall,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
parking_stall: {
...where.parking_stall,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) { if (filter.active !== undefined) {
where = { where = {
...where, ...where,

View File

@ -56,6 +56,10 @@ module.exports = class UsersDBApi {
}); });
} }
await users.setUnit(data.data.unit || null, {
transaction,
});
await users.setCustom_permissions(data.data.custom_permissions || [], { await users.setCustom_permissions(data.data.custom_permissions || [], {
transaction, transaction,
}); });
@ -190,6 +194,14 @@ module.exports = class UsersDBApi {
); );
} }
if (data.unit !== undefined) {
await users.setUnit(
data.unit,
{ transaction },
);
}
if (data.custom_permissions !== undefined) { if (data.custom_permissions !== undefined) {
await users.setCustom_permissions(data.custom_permissions, { await users.setCustom_permissions(data.custom_permissions, {
transaction, transaction,
@ -289,6 +301,10 @@ module.exports = class UsersDBApi {
transaction, transaction,
}); });
output.unit = await users.getUnit({
transaction,
});
return output; return output;
} }
@ -331,6 +347,32 @@ module.exports = class UsersDBApi {
: {}, : {},
}, },
{
model: db.units,
as: 'unit',
where: filter.unit
? {
[Op.or]: [
{
id: {
[Op.in]: filter.unit
.split('|')
.map((term) => Utils.uuid(term)),
},
},
{
unit_number: {
[Op.or]: filter.unit
.split('|')
.map((term) => ({ [Op.iLike]: `%${term}%` })),
},
},
],
}
: {},
},
{ {
model: db.permissions, model: db.permissions,
as: 'custom_permissions', as: 'custom_permissions',

View File

@ -0,0 +1,65 @@
module.exports = {
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async up(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.addColumn(
'users',
'unitId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'units',
key: 'id',
},
},
{ transaction },
);
await queryInterface.addColumn(
'units',
'parking_stall',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async down(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.removeColumn('units', 'parking_stall', {
transaction,
});
await queryInterface.removeColumn('users', 'unitId', { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};

View File

@ -30,6 +30,10 @@ module.exports = function (sequelize, DataTypes) {
type: DataTypes.DECIMAL, type: DataTypes.DECIMAL,
}, },
parking_stall: {
type: DataTypes.INTEGER,
},
importHash: { importHash: {
type: DataTypes.STRING(255), type: DataTypes.STRING(255),
allowNull: true, allowNull: true,
@ -46,6 +50,14 @@ module.exports = function (sequelize, DataTypes) {
units.associate = (db) => { units.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity /// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
db.units.hasMany(db.users, {
as: 'users_unit',
foreignKey: {
name: 'unitId',
},
constraints: false,
});
db.units.hasMany(db.maintenance_requests, { db.units.hasMany(db.maintenance_requests, {
as: 'maintenance_requests_unit', as: 'maintenance_requests_unit',
foreignKey: { foreignKey: {

View File

@ -120,6 +120,14 @@ module.exports = function (sequelize, DataTypes) {
constraints: false, constraints: false,
}); });
db.users.belongsTo(db.units, {
as: 'unit',
foreignKey: {
name: 'unitId',
},
constraints: false,
});
db.users.hasMany(db.file, { db.users.hasMany(db.file, {
as: 'avatar', as: 'avatar',
foreignKey: 'belongsToId', foreignKey: 'belongsToId',

View File

@ -85,7 +85,7 @@ const MaintenanceRequestsData = [
description: 'Leaking faucet in kitchen', description: 'Leaking faucet in kitchen',
status: 'completed', status: 'pending',
request_date: new Date('2023-10-01T10:00:00Z'), request_date: new Date('2023-10-01T10:00:00Z'),
}, },
@ -105,7 +105,7 @@ const MaintenanceRequestsData = [
description: 'Heating not working', description: 'Heating not working',
status: 'pending', status: 'completed',
request_date: new Date('2023-09-20T09:00:00Z'), request_date: new Date('2023-09-20T09:00:00Z'),
}, },
@ -115,7 +115,7 @@ const MaintenanceRequestsData = [
description: 'Elevator malfunction', description: 'Elevator malfunction',
status: 'in_progress', status: 'completed',
request_date: new Date('2023-10-02T11:15:00Z'), request_date: new Date('2023-10-02T11:15:00Z'),
}, },
@ -171,9 +171,11 @@ const UnitsData = [
balance: 250, balance: 250,
unit_factor: 3, unit_factor: 6,
cond_fee: 53.45, cond_fee: 58.08,
parking_stall: 6,
}, },
{ {
@ -185,7 +187,9 @@ const UnitsData = [
unit_factor: 4, unit_factor: 4,
cond_fee: 82.56, cond_fee: 59.96,
parking_stall: 5,
}, },
{ {
@ -195,9 +199,11 @@ const UnitsData = [
balance: 150, balance: 150,
unit_factor: 3, unit_factor: 4,
cond_fee: 49.53, cond_fee: 96.18,
parking_stall: 7,
}, },
{ {
@ -207,14 +213,62 @@ const UnitsData = [
balance: 0, balance: 0,
unit_factor: 5, unit_factor: 3,
cond_fee: 95.34, cond_fee: 34.91,
parking_stall: 6,
}, },
]; ];
// Similar logic for "relation_many" // Similar logic for "relation_many"
async function associateUserWithUnit() {
const relatedUnit0 = await Units.findOne({
offset: Math.floor(Math.random() * (await Units.count())),
});
const User0 = await Users.findOne({
order: [['id', 'ASC']],
offset: 0,
});
if (User0?.setUnit) {
await User0.setUnit(relatedUnit0);
}
const relatedUnit1 = await Units.findOne({
offset: Math.floor(Math.random() * (await Units.count())),
});
const User1 = await Users.findOne({
order: [['id', 'ASC']],
offset: 1,
});
if (User1?.setUnit) {
await User1.setUnit(relatedUnit1);
}
const relatedUnit2 = await Units.findOne({
offset: Math.floor(Math.random() * (await Units.count())),
});
const User2 = await Users.findOne({
order: [['id', 'ASC']],
offset: 2,
});
if (User2?.setUnit) {
await User2.setUnit(relatedUnit2);
}
const relatedUnit3 = await Units.findOne({
offset: Math.floor(Math.random() * (await Units.count())),
});
const User3 = await Users.findOne({
order: [['id', 'ASC']],
offset: 3,
});
if (User3?.setUnit) {
await User3.setUnit(relatedUnit3);
}
}
// Similar logic for "relation_many" // Similar logic for "relation_many"
async function associateMaintenanceRequestWithUnit() { async function associateMaintenanceRequestWithUnit() {
@ -326,6 +380,8 @@ module.exports = {
await Promise.all([ await Promise.all([
// Similar logic for "relation_many" // Similar logic for "relation_many"
await associateUserWithUnit(),
// Similar logic for "relation_many" // Similar logic for "relation_many"
await associateMaintenanceRequestWithUnit(), await associateMaintenanceRequestWithUnit(),

View File

@ -27,6 +27,9 @@ router.use(checkCrudPermissions('units'));
* unit_factor: * unit_factor:
* type: integer * type: integer
* format: int64 * format: int64
* parking_stall:
* type: integer
* format: int64
* balance: * balance:
* type: integer * type: integer
@ -314,6 +317,7 @@ router.get(
'id', 'id',
'unit_number', 'unit_number',
'unit_factor', 'unit_factor',
'parking_stall',
'balance', 'balance',
'cond_fee', 'cond_fee',
]; ];

View File

@ -54,7 +54,7 @@ module.exports = class SearchService {
const columnsInt = { const columnsInt = {
budgets: ['year', 'total_budget', 'expenses'], budgets: ['year', 'total_budget', 'expenses'],
units: ['balance', 'unit_factor', 'cond_fee'], units: ['balance', 'unit_factor', 'cond_fee', 'parking_stall'],
}; };
let allFoundRecords = []; let allFoundRecords = [];

View File

@ -0,0 +1 @@
{}

View File

@ -128,6 +128,17 @@ const CardUnits = ({
</div> </div>
</dd> </dd>
</div> </div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>
Parking Stall
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.parking_stall}
</div>
</dd>
</div>
</dl> </dl>
</li> </li>
))} ))}

View File

@ -77,6 +77,13 @@ const ListUnits = ({
<p className={'text-xs text-gray-500 '}>Cond Fee</p> <p className={'text-xs text-gray-500 '}>Cond Fee</p>
<p className={'line-clamp-2'}>{item.cond_fee}</p> <p className={'line-clamp-2'}>{item.cond_fee}</p>
</div> </div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>
Parking Stall
</p>
<p className={'line-clamp-2'}>{item.parking_stall}</p>
</div>
</Link> </Link>
<ListActionsPopover <ListActionsPopover
onDelete={onDelete} onDelete={onDelete}

View File

@ -112,6 +112,20 @@ export const loadColumns = async (
type: 'number', type: 'number',
}, },
{
field: 'parking_stall',
headerName: 'Parking Stall',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{ {
field: 'actions', field: 'actions',
type: 'actions', type: 'actions',

View File

@ -173,6 +173,15 @@ const CardUsers = ({
</div> </div>
</dd> </dd>
</div> </div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Unit</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{dataFormatter.unitsOneListFormatter(item.unit)}
</div>
</dd>
</div>
</dl> </dl>
</li> </li>
))} ))}

View File

@ -113,6 +113,13 @@ const ListUsers = ({
.join(', ')} .join(', ')}
</p> </p>
</div> </div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Unit</p>
<p className={'line-clamp-2'}>
{dataFormatter.unitsOneListFormatter(item.unit)}
</p>
</div>
</Link> </Link>
<ListActionsPopover <ListActionsPopover
onDelete={onDelete} onDelete={onDelete}

View File

@ -159,6 +159,26 @@ export const loadColumns = async (
), ),
}, },
{
field: 'unit',
headerName: 'Unit',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
sortable: false,
type: 'singleSelect',
getOptionValue: (value: any) => value?.id,
getOptionLabel: (value: any) => value?.label,
valueOptions: await callOptionsApi('units'),
valueGetter: (params: GridValueGetterParams) =>
params?.value?.id ?? params?.value,
},
{ {
field: 'actions', field: 'actions',
type: 'actions', type: 'actions',

View File

@ -45,6 +45,8 @@ const EditUnits = () => {
unit_factor: '', unit_factor: '',
cond_fee: '', cond_fee: '',
parking_stall: '',
}; };
const [initialValues, setInitialValues] = useState(initVals); const [initialValues, setInitialValues] = useState(initVals);
@ -128,6 +130,14 @@ const EditUnits = () => {
<Field type='number' name='cond_fee' placeholder='Cond Fee' /> <Field type='number' name='cond_fee' placeholder='Cond Fee' />
</FormField> </FormField>
<FormField label='Parking Stall'>
<Field
type='number'
name='parking_stall'
placeholder='Parking Stall'
/>
</FormField>
<BaseDivider /> <BaseDivider />
<BaseButtons> <BaseButtons>
<BaseButton type='submit' color='info' label='Submit' /> <BaseButton type='submit' color='info' label='Submit' />

View File

@ -45,6 +45,8 @@ const EditUnitsPage = () => {
unit_factor: '', unit_factor: '',
cond_fee: '', cond_fee: '',
parking_stall: '',
}; };
const [initialValues, setInitialValues] = useState(initVals); const [initialValues, setInitialValues] = useState(initVals);
@ -126,6 +128,14 @@ const EditUnitsPage = () => {
<Field type='number' name='cond_fee' placeholder='Cond Fee' /> <Field type='number' name='cond_fee' placeholder='Cond Fee' />
</FormField> </FormField>
<FormField label='Parking Stall'>
<Field
type='number'
name='parking_stall'
placeholder='Parking Stall'
/>
</FormField>
<BaseDivider /> <BaseDivider />
<BaseButtons> <BaseButtons>
<BaseButton type='submit' color='info' label='Submit' /> <BaseButton type='submit' color='info' label='Submit' />

View File

@ -31,6 +31,7 @@ const UnitsTablesPage = () => {
const [filters] = useState([ const [filters] = useState([
{ label: 'UnitNumber', title: 'unit_number' }, { label: 'UnitNumber', title: 'unit_number' },
{ label: 'Unit Factor', title: 'unit_factor', number: 'true' }, { label: 'Unit Factor', title: 'unit_factor', number: 'true' },
{ label: 'Parking Stall', title: 'parking_stall', number: 'true' },
{ label: 'Balance', title: 'balance', number: 'true' }, { label: 'Balance', title: 'balance', number: 'true' },
{ label: 'Cond Fee', title: 'cond_fee', number: 'true' }, { label: 'Cond Fee', title: 'cond_fee', number: 'true' },

View File

@ -42,6 +42,8 @@ const initialValues = {
unit_factor: '', unit_factor: '',
cond_fee: '', cond_fee: '',
parking_stall: '',
}; };
const UnitsNew = () => { const UnitsNew = () => {
@ -101,6 +103,14 @@ const UnitsNew = () => {
<Field type='number' name='cond_fee' placeholder='Cond Fee' /> <Field type='number' name='cond_fee' placeholder='Cond Fee' />
</FormField> </FormField>
<FormField label='Parking Stall'>
<Field
type='number'
name='parking_stall'
placeholder='Parking Stall'
/>
</FormField>
<BaseDivider /> <BaseDivider />
<BaseButtons> <BaseButtons>
<BaseButton type='submit' color='info' label='Submit' /> <BaseButton type='submit' color='info' label='Submit' />

View File

@ -31,6 +31,7 @@ const UnitsTablesPage = () => {
const [filters] = useState([ const [filters] = useState([
{ label: 'UnitNumber', title: 'unit_number' }, { label: 'UnitNumber', title: 'unit_number' },
{ label: 'Unit Factor', title: 'unit_factor', number: 'true' }, { label: 'Unit Factor', title: 'unit_factor', number: 'true' },
{ label: 'Parking Stall', title: 'parking_stall', number: 'true' },
{ label: 'Balance', title: 'balance', number: 'true' }, { label: 'Balance', title: 'balance', number: 'true' },
{ label: 'Cond Fee', title: 'cond_fee', number: 'true' }, { label: 'Cond Fee', title: 'cond_fee', number: 'true' },

View File

@ -80,6 +80,64 @@ const UnitsView = () => {
<p>{units?.cond_fee || 'No data'}</p> <p>{units?.cond_fee || 'No data'}</p>
</div> </div>
<div className={'mb-4'}>
<p className={'block font-bold mb-2'}>Parking Stall</p>
<p>{units?.parking_stall || 'No data'}</p>
</div>
<>
<p className={'block font-bold mb-2'}>Users Unit</p>
<CardBox
className='mb-6 border border-gray-300 rounded overflow-hidden'
hasTable
>
<div className='overflow-x-auto'>
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Phone Number</th>
<th>E-Mail</th>
<th>Disabled</th>
</tr>
</thead>
<tbody>
{units.users_unit &&
Array.isArray(units.users_unit) &&
units.users_unit.map((item: any) => (
<tr
key={item.id}
onClick={() =>
router.push(`/users/users-view/?id=${item.id}`)
}
>
<td data-label='firstName'>{item.firstName}</td>
<td data-label='lastName'>{item.lastName}</td>
<td data-label='phoneNumber'>{item.phoneNumber}</td>
<td data-label='email'>{item.email}</td>
<td data-label='disabled'>
{dataFormatter.booleanFormatter(item.disabled)}
</td>
</tr>
))}
</tbody>
</table>
</div>
{!units?.users_unit?.length && (
<div className={'text-center py-4'}>No data</div>
)}
</CardBox>
</>
<> <>
<p className={'block font-bold mb-2'}>Maintenance_requests Unit</p> <p className={'block font-bold mb-2'}>Maintenance_requests Unit</p>
<CardBox <CardBox

View File

@ -52,6 +52,8 @@ const EditUsers = () => {
custom_permissions: [], custom_permissions: [],
unit: null,
password: '', password: '',
}; };
const [initialValues, setInitialValues] = useState(initVals); const [initialValues, setInitialValues] = useState(initVals);
@ -170,6 +172,17 @@ const EditUsers = () => {
></Field> ></Field>
</FormField> </FormField>
<FormField label='Unit' labelFor='unit'>
<Field
name='unit'
id='unit'
component={SelectField}
options={initialValues.unit}
itemRef={'units'}
showField={'unit_number'}
></Field>
</FormField>
<FormField label='Password'> <FormField label='Password'>
<Field name='password' placeholder='password' /> <Field name='password' placeholder='password' />
</FormField> </FormField>

View File

@ -52,6 +52,8 @@ const EditUsersPage = () => {
custom_permissions: [], custom_permissions: [],
unit: null,
password: '', password: '',
}; };
const [initialValues, setInitialValues] = useState(initVals); const [initialValues, setInitialValues] = useState(initVals);
@ -168,6 +170,17 @@ const EditUsersPage = () => {
></Field> ></Field>
</FormField> </FormField>
<FormField label='Unit' labelFor='unit'>
<Field
name='unit'
id='unit'
component={SelectField}
options={initialValues.unit}
itemRef={'units'}
showField={'unit_number'}
></Field>
</FormField>
<FormField label='Password'> <FormField label='Password'>
<Field name='password' placeholder='password' /> <Field name='password' placeholder='password' />
</FormField> </FormField>

View File

@ -36,6 +36,8 @@ const UsersTablesPage = () => {
{ label: 'App Role', title: 'app_role' }, { label: 'App Role', title: 'app_role' },
{ label: 'Unit', title: 'unit' },
{ label: 'Custom Permissions', title: 'custom_permissions' }, { label: 'Custom Permissions', title: 'custom_permissions' },
]); ]);

View File

@ -48,6 +48,8 @@ const initialValues = {
app_role: '', app_role: '',
custom_permissions: [], custom_permissions: [],
unit: '',
}; };
const UsersNew = () => { const UsersNew = () => {
@ -140,6 +142,16 @@ const UsersNew = () => {
></Field> ></Field>
</FormField> </FormField>
<FormField label='Unit' labelFor='unit'>
<Field
name='unit'
id='unit'
component={SelectField}
options={[]}
itemRef={'units'}
></Field>
</FormField>
<BaseDivider /> <BaseDivider />
<BaseButtons> <BaseButtons>
<BaseButton type='submit' color='info' label='Submit' /> <BaseButton type='submit' color='info' label='Submit' />

View File

@ -36,6 +36,8 @@ const UsersTablesPage = () => {
{ label: 'App Role', title: 'app_role' }, { label: 'App Role', title: 'app_role' },
{ label: 'Unit', title: 'unit' },
{ label: 'Custom Permissions', title: 'custom_permissions' }, { label: 'Custom Permissions', title: 'custom_permissions' },
]); ]);

View File

@ -138,6 +138,12 @@ const UsersView = () => {
</CardBox> </CardBox>
</> </>
<div className={'mb-4'}>
<p className={'block font-bold mb-2'}>Unit</p>
<p>{users?.unit?.unit_number ?? 'No data'}</p>
</div>
<> <>
<p className={'block font-bold mb-2'}>Units Owner</p> <p className={'block font-bold mb-2'}>Units Owner</p>
<CardBox <CardBox
@ -155,6 +161,8 @@ const UsersView = () => {
<th>Unit Factor</th> <th>Unit Factor</th>
<th>Cond Fee</th> <th>Cond Fee</th>
<th>Parking Stall</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -174,6 +182,10 @@ const UsersView = () => {
<td data-label='unit_factor'>{item.unit_factor}</td> <td data-label='unit_factor'>{item.unit_factor}</td>
<td data-label='cond_fee'>{item.cond_fee}</td> <td data-label='cond_fee'>{item.cond_fee}</td>
<td data-label='parking_stall'>
{item.parking_stall}
</td>
</tr> </tr>
))} ))}
</tbody> </tbody>