Skip to content

Commit e76d5e7

Browse files
committed
fixed error
1 parent 7b0e3ce commit e76d5e7

68 files changed

Lines changed: 1163 additions & 217 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/src/abdulrcrtw.spec.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,34 @@ import { TransfersService } from './transfers/transfers.service';
55
describe('abdulrcrtw Modules (BE-92, BE-91, BE-90, BE-89)', () => {
66
it('NotesDocsController adds and lists asset notes and documents', () => {
77
const controller = new NotesDocsController();
8-
const note = controller.addNote('ast-1', 'Need battery replacement', { user: { id: 'u-1' } } as any);
8+
const note = controller.addNote('ast-1', 'Need battery replacement', {
9+
user: { id: 'u-1' },
10+
} as any);
911
expect(note.content).toBe('Need battery replacement');
1012
expect(controller.getNotes('ast-1').length).toBe(1);
1113

12-
const doc = controller.addDocument('ast-1', { title: 'Warranty.pdf', fileUrl: 'http://example.com/w.pdf' }, { user: { id: 'u-1' } } as any);
14+
const doc = controller.addDocument(
15+
'ast-1',
16+
{ title: 'Warranty.pdf', fileUrl: 'http://example.com/w.pdf' },
17+
{ user: { id: 'u-1' } } as any,
18+
);
1319
expect(doc.title).toBe('Warranty.pdf');
1420
expect(controller.getDocuments('ast-1').length).toBe(1);
1521
});
1622

1723
it('MaintenanceService creates maintenance records', async () => {
1824
const mockRepo = {
1925
create: jest.fn().mockImplementation((dto) => dto),
20-
save: jest.fn().mockImplementation((dto) => Promise.resolve({ id: 'm-1', ...dto })),
26+
save: jest
27+
.fn()
28+
.mockImplementation((dto) => Promise.resolve({ id: 'm-1', ...dto })),
2129
};
2230
const service = new MaintenanceService(mockRepo as any);
23-
const rec = await service.create({ assetId: 'ast-1', title: 'Screen repair', cost: 15000 });
31+
const rec = await service.create({
32+
assetId: 'ast-1',
33+
title: 'Screen repair',
34+
cost: 15000,
35+
});
2436
expect(rec.cost).toBe(15000);
2537
});
2638

backend/src/app.controller.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
import { Controller, Get } from '@nestjs/common';
2+
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
23
import { AppService } from './app.service';
34

5+
@ApiTags('app')
46
@Controller()
57
export class AppController {
68
constructor(private readonly appService: AppService) {}
79

810
@Get()
11+
@ApiOperation({ summary: 'Health check / welcome message' })
12+
@ApiResponse({ status: 200, description: 'Server is running' })
913
getHello(): string {
1014
return this.appService.getHello();
1115
}
12-
13-
@Get()
14-
getHealth() {
15-
return {
16-
status: 'OK',
17-
message: 'Server is running',
18-
Timestamp: Date.now(),
19-
};
20-
}
2116
}

backend/src/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { PurchaseOrdersModule } from './purchase-orders/purchase-orders.module';
2323
import { LicensesModule } from './licenses/licenses.module';
2424
import { NotificationsModule } from './notifications/notifications.module';
2525
import { GatewayModule } from './gateway/gateway.module';
26+
import { AuditLogsModule } from './audit-logs/audit-logs.module';
2627

2728
@Module({
2829
imports: [
@@ -46,6 +47,7 @@ import { GatewayModule } from './gateway/gateway.module';
4647
LicensesModule,
4748
NotificationsModule,
4849
GatewayModule,
50+
AuditLogsModule,
4951
TypeOrmModule.forRootAsync({
5052
imports: [ConfigModule],
5153
useFactory: (configService: ConfigService) => ({

backend/src/assets/asset-lifecycle.service.ts

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,37 @@ export enum AssetStatus {
1111
}
1212

1313
const ALLOWED_TRANSITIONS: Record<AssetStatus, AssetStatus[]> = {
14-
[AssetStatus.AVAILABLE]: [AssetStatus.ASSIGNED, AssetStatus.IN_MAINTENANCE, AssetStatus.IN_TRANSIT, AssetStatus.RETIRED, AssetStatus.LOST],
15-
[AssetStatus.ASSIGNED]: [AssetStatus.AVAILABLE, AssetStatus.IN_MAINTENANCE, AssetStatus.IN_TRANSIT, AssetStatus.RETIRED, AssetStatus.LOST],
16-
[AssetStatus.IN_MAINTENANCE]: [AssetStatus.AVAILABLE, AssetStatus.ASSIGNED, AssetStatus.RETIRED],
17-
[AssetStatus.IN_TRANSIT]: [AssetStatus.AVAILABLE, AssetStatus.ASSIGNED, AssetStatus.LOST],
14+
[AssetStatus.AVAILABLE]: [
15+
AssetStatus.ASSIGNED,
16+
AssetStatus.IN_MAINTENANCE,
17+
AssetStatus.IN_TRANSIT,
18+
AssetStatus.RETIRED,
19+
AssetStatus.LOST,
20+
],
21+
[AssetStatus.ASSIGNED]: [
22+
AssetStatus.AVAILABLE,
23+
AssetStatus.IN_MAINTENANCE,
24+
AssetStatus.IN_TRANSIT,
25+
AssetStatus.RETIRED,
26+
AssetStatus.LOST,
27+
],
28+
[AssetStatus.IN_MAINTENANCE]: [
29+
AssetStatus.AVAILABLE,
30+
AssetStatus.ASSIGNED,
31+
AssetStatus.RETIRED,
32+
],
33+
[AssetStatus.IN_TRANSIT]: [
34+
AssetStatus.AVAILABLE,
35+
AssetStatus.ASSIGNED,
36+
AssetStatus.LOST,
37+
],
1838
[AssetStatus.RETIRED]: [AssetStatus.DISPOSED],
1939
[AssetStatus.DISPOSED]: [],
20-
[AssetStatus.LOST]: [AssetStatus.AVAILABLE, AssetStatus.RETIRED, AssetStatus.DISPOSED],
40+
[AssetStatus.LOST]: [
41+
AssetStatus.AVAILABLE,
42+
AssetStatus.RETIRED,
43+
AssetStatus.DISPOSED,
44+
],
2145
};
2246

2347
@Injectable()
@@ -28,12 +52,22 @@ export class AssetLifecycleService {
2852
if (fromStatus === toStatus) return true;
2953
const allowed = ALLOWED_TRANSITIONS[fromStatus] || [];
3054
if (!allowed.includes(toStatus)) {
31-
throw new BadRequestException(`Cannot transition asset status from ${fromStatus} to ${toStatus}`);
55+
throw new BadRequestException(
56+
`Cannot transition asset status from ${fromStatus} to ${toStatus}`,
57+
);
3258
}
3359
return true;
3460
}
3561

36-
recordHistory(assetId: string, event: { eventType: string; actorUserId: string; note?: string; fieldChanges?: any }) {
62+
recordHistory(
63+
assetId: string,
64+
event: {
65+
eventType: string;
66+
actorUserId: string;
67+
note?: string;
68+
fieldChanges?: any;
69+
},
70+
) {
3771
const list = this.history.get(assetId) || [];
3872
const entry = {
3973
id: `h_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,

backend/src/assets/asset-status.controller.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,47 @@
11
import { Controller, Get, Patch, Param, Body, Req } from '@nestjs/common';
2-
import { ApiTags, ApiOperation } from '@nestjs/swagger';
2+
import {
3+
ApiTags,
4+
ApiOperation,
5+
ApiBearerAuth,
6+
ApiResponse,
7+
} from '@nestjs/swagger';
38
import { AssetLifecycleService, AssetStatus } from './asset-lifecycle.service';
49

510
@ApiTags('assets')
11+
@ApiBearerAuth('JWT-auth')
612
@Controller('assets')
713
export class AssetStatusController {
814
constructor(private readonly lifecycleService: AssetLifecycleService) {}
915

1016
@Patch(':id/status')
1117
@ApiOperation({ summary: 'Update asset status' })
18+
@ApiResponse({ status: 200, description: 'Status updated' })
19+
@ApiResponse({ status: 400, description: 'Invalid status transition' })
1220
updateStatus(
1321
@Param('id') id: string,
14-
@Body() body: { currentStatus: AssetStatus; newStatus: AssetStatus; note?: string },
22+
@Body()
23+
body: { currentStatus: AssetStatus; newStatus: AssetStatus; note?: string },
1524
@Req() req: any,
1625
) {
17-
this.lifecycleService.validateTransition(body.currentStatus, body.newStatus);
26+
this.lifecycleService.validateTransition(
27+
body.currentStatus,
28+
body.newStatus,
29+
);
1830
const actorId = req.user?.id || 'usr-1';
1931
const entry = this.lifecycleService.recordHistory(id, {
2032
eventType: 'STATUS_CHANGED',
2133
actorUserId: actorId,
2234
note: body.note,
23-
fieldChanges: { status: { from: body.currentStatus, to: body.newStatus } },
35+
fieldChanges: {
36+
status: { from: body.currentStatus, to: body.newStatus },
37+
},
2438
});
2539
return { assetId: id, status: body.newStatus, historyEntry: entry };
2640
}
2741

2842
@Get(':id/history')
2943
@ApiOperation({ summary: 'Get asset history and audit trail' })
44+
@ApiResponse({ status: 200, description: 'Asset history' })
3045
getHistory(@Param('id') id: string) {
3146
return this.lifecycleService.getHistory(id);
3247
}

backend/src/assets/assets.controller.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ import {
99
Query,
1010
UseGuards,
1111
} from '@nestjs/common';
12-
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
12+
import {
13+
ApiTags,
14+
ApiOperation,
15+
ApiBearerAuth,
16+
ApiResponse,
17+
} from '@nestjs/swagger';
1318
import { AssetsService } from './assets.service';
1419
import { BulkStatusDto } from './dto/bulk-status.dto';
1520
import { BulkAssignDto } from './dto/bulk-assign.dto';
@@ -21,12 +26,14 @@ import { GetUser } from '../auth/decorators/get-user.decorator';
2126
import { User } from '../users/entities/user.entity';
2227

2328
@ApiTags('assets')
29+
@ApiBearerAuth('JWT-auth')
2430
@Controller('assets')
2531
export class AssetsController {
2632
constructor(private readonly assetsService: AssetsService) {}
2733

2834
@Get()
2935
@ApiOperation({ summary: 'List all assets (paginated, filterable)' })
36+
@ApiResponse({ status: 200, description: 'Paginated list of assets' })
3037
findAll(
3138
@Query('search') search?: string,
3239
@Query('categoryId') categoryId?: string,
@@ -36,54 +43,68 @@ export class AssetsController {
3643
@Query('page') page?: number,
3744
@Query('limit') limit?: number,
3845
) {
39-
return this.assetsService.findAll({ search, categoryId, departmentId, locationId, status, page, limit });
46+
return this.assetsService.findAll({
47+
search,
48+
categoryId,
49+
departmentId,
50+
locationId,
51+
status,
52+
page,
53+
limit,
54+
});
4055
}
4156

4257
@Post()
4358
@ApiOperation({ summary: 'Create an asset' })
59+
@ApiResponse({ status: 201, description: 'Asset created' })
4460
create(@Body() dto: any) {
4561
return this.assetsService.create(dto);
4662
}
4763

4864
@Get(':id')
4965
@ApiOperation({ summary: 'Get asset details' })
66+
@ApiResponse({ status: 200, description: 'Asset details' })
67+
@ApiResponse({ status: 404, description: 'Asset not found' })
5068
findOne(@Param('id') id: string) {
5169
return this.assetsService.findById(id);
5270
}
5371

5472
@Patch(':id')
5573
@ApiOperation({ summary: 'Update an asset' })
74+
@ApiResponse({ status: 200, description: 'Asset updated' })
5675
update(@Param('id') id: string, @Body() dto: any) {
5776
return this.assetsService.update(id, dto);
5877
}
5978

6079
@Delete(':id')
6180
@ApiOperation({ summary: 'Soft delete an asset' })
81+
@ApiResponse({ status: 200, description: 'Asset deleted' })
6282
delete(@Param('id') id: string) {
6383
return this.assetsService.delete(id);
6484
}
6585

6686
@Patch('bulk/status')
6787
@UseGuards(JwtAuthGuard)
68-
@ApiBearerAuth()
6988
@ApiOperation({ summary: 'Bulk update asset status' })
89+
@ApiResponse({ status: 200, description: 'Bulk status update result' })
7090
bulkStatus(@Body() dto: BulkStatusDto, @GetUser() user: User) {
7191
return this.assetsService.bulkStatus(dto, user.id);
7292
}
7393

7494
@Patch('bulk/assign')
7595
@UseGuards(JwtAuthGuard)
76-
@ApiBearerAuth()
7796
@ApiOperation({ summary: 'Bulk assign assets to user or department' })
97+
@ApiResponse({ status: 200, description: 'Bulk assignment result' })
7898
bulkAssign(@Body() dto: BulkAssignDto, @GetUser() user: User) {
7999
return this.assetsService.bulkAssign(dto, user.id);
80100
}
81101

82102
@Delete('bulk')
83103
@UseGuards(JwtAuthGuard, RolesGuard)
84104
@Roles('ADMIN')
85-
@ApiBearerAuth()
86105
@ApiOperation({ summary: 'Bulk soft delete assets (ADMIN only)' })
106+
@ApiResponse({ status: 200, description: 'Bulk delete result' })
107+
@ApiResponse({ status: 403, description: 'Forbidden — requires ADMIN role' })
87108
bulkDelete(@Body() dto: BulkDeleteDto, @GetUser() user: User) {
88109
return this.assetsService.bulkDelete(dto, user.id);
89110
}

backend/src/assets/assets.service.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ describe('AssetsService', () => {
6666
jest.spyOn(repository, 'findOne').mockResolvedValue(mockAsset as any);
6767
jest.spyOn(repository, 'save').mockResolvedValue(updatedAsset as any);
6868

69-
const result = await service.update('ast-1', { name: 'MacBook Pro M3' } as any);
69+
const result = await service.update('ast-1', {
70+
name: 'MacBook Pro M3',
71+
} as any);
7072

7173
expect(result.name).toBe('MacBook Pro M3');
7274
});

0 commit comments

Comments
 (0)