Add field management module with database schema and validation
- Introduced `FieldModule` to manage cycles and plans, including read and write controllers. - Created database migrations for `company_settings`, `cycles`, `cycle_weekdays`, `cycle_destinations`, `plans`, `plan_destinations`, `plan_invoices`, and `plan_packing_slips` tables, including constraints and unique indexes. - Developed service and repository layers for handling cycle and plan data operations. - Added unit tests for the cycles and plans services, repositories, and controllers to ensure functionality and correctness. - Updated application module to include the new `FieldModule` for better organization.
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
HttpCode,
|
||||
Param,
|
||||
ParseUUIDPipe,
|
||||
Patch,
|
||||
Post,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
ApiCreatedResponse,
|
||||
ApiForbiddenResponse,
|
||||
ApiNoContentResponse,
|
||||
ApiNotFoundResponse,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
ApiTags,
|
||||
ApiUnauthorizedResponse,
|
||||
} from '@nestjs/swagger';
|
||||
import type { AuthUser } from '../../../common/auth/auth-user';
|
||||
import { CurrentUser } from '../../../common/decorators/current-user.decorator';
|
||||
import { BEARER_AUTH_NAME } from '../../../common/swagger/setup-swagger';
|
||||
import { RequireFieldPrivilege } from '../shared/field-privilege.decorator';
|
||||
import { FieldPrivilegeGuard } from '../shared/field-privilege.guard';
|
||||
import {
|
||||
AddPlanDestinationDto,
|
||||
BulkIdsDto,
|
||||
BulkStatusDto,
|
||||
CreatePlanDto,
|
||||
GeneratePlansDto,
|
||||
PlanDto,
|
||||
UpdatePlanDto,
|
||||
UpdatePlanStatusDto,
|
||||
} from './dto/plan.dto';
|
||||
import { PlansService } from './plans.service';
|
||||
|
||||
@ApiTags('plans')
|
||||
@ApiBearerAuth(BEARER_AUTH_NAME)
|
||||
@UseGuards(FieldPrivilegeGuard)
|
||||
@Controller('plans')
|
||||
export class PlansWriteController {
|
||||
constructor(private readonly plansService: PlansService) {}
|
||||
|
||||
@Post('generate')
|
||||
@RequireFieldPrivilege('plan', 'create')
|
||||
@ApiOperation({ summary: 'Generate plans from cycles for a date range' })
|
||||
@ApiOkResponse({
|
||||
schema: {
|
||||
properties: {
|
||||
created: { type: 'number' },
|
||||
skipped: { type: 'number' },
|
||||
},
|
||||
},
|
||||
})
|
||||
@ApiUnauthorizedResponse()
|
||||
@ApiForbiddenResponse()
|
||||
generate(
|
||||
@Body() dto: GeneratePlansDto,
|
||||
@CurrentUser('id') userId: string,
|
||||
): Promise<{ created: number; skipped: number }> {
|
||||
return this.plansService.generate({ ...dto, userId });
|
||||
}
|
||||
|
||||
@Post('bulk-delete')
|
||||
@HttpCode(200)
|
||||
@RequireFieldPrivilege('plan', 'delete')
|
||||
@ApiOperation({ summary: 'Bulk archive plans' })
|
||||
@ApiOkResponse({ schema: { properties: { deleted: { type: 'number' } } } })
|
||||
bulkDelete(
|
||||
@Body() dto: BulkIdsDto,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<{ deleted: number }> {
|
||||
return this.plansService.bulkDelete(dto.ids, user);
|
||||
}
|
||||
|
||||
@Post('bulk-status')
|
||||
@HttpCode(200)
|
||||
@RequireFieldPrivilege('plan', 'update')
|
||||
@ApiOperation({ summary: 'Bulk update plan status' })
|
||||
@ApiOkResponse({ schema: { properties: { updated: { type: 'number' } } } })
|
||||
bulkStatus(
|
||||
@Body() dto: BulkStatusDto,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<{ updated: number }> {
|
||||
return this.plansService.bulkUpdateStatus(
|
||||
dto.ids,
|
||||
dto.status,
|
||||
user.id,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@RequireFieldPrivilege('plan', 'create')
|
||||
@ApiOperation({ summary: 'Create plan' })
|
||||
@ApiCreatedResponse({ type: PlanDto })
|
||||
create(
|
||||
@Body() dto: CreatePlanDto,
|
||||
@CurrentUser('id') userId: string,
|
||||
): Promise<PlanDto> {
|
||||
return this.plansService.create({ ...dto, userId });
|
||||
}
|
||||
|
||||
@Post(':id/destinations')
|
||||
@RequireFieldPrivilege('plan', 'update')
|
||||
@ApiOperation({ summary: 'Add a destination to a plan' })
|
||||
@ApiOkResponse({ type: PlanDto })
|
||||
addDestination(
|
||||
@Param('id', ParseUUIDPipe) id: string,
|
||||
@Body() dto: AddPlanDestinationDto,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<PlanDto> {
|
||||
return this.plansService.addDestination(
|
||||
id,
|
||||
dto.customerId,
|
||||
dto.afterDestinationId,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
@Delete(':id/destinations/:destinationId')
|
||||
@RequireFieldPrivilege('plan', 'update')
|
||||
@ApiOperation({ summary: 'Remove a destination from a plan' })
|
||||
@ApiOkResponse({ type: PlanDto })
|
||||
removeDestination(
|
||||
@Param('id', ParseUUIDPipe) id: string,
|
||||
@Param('destinationId', ParseUUIDPipe) destinationId: string,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<PlanDto> {
|
||||
return this.plansService.removeDestination(id, destinationId, user);
|
||||
}
|
||||
|
||||
@Patch(':id/status')
|
||||
@RequireFieldPrivilege('plan', 'update')
|
||||
@ApiOperation({ summary: 'Update plan status' })
|
||||
@ApiOkResponse({ type: PlanDto })
|
||||
updateStatus(
|
||||
@Param('id', ParseUUIDPipe) id: string,
|
||||
@Body() dto: UpdatePlanStatusDto,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<PlanDto> {
|
||||
return this.plansService.updateStatus(id, dto.status, user.id, user);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@RequireFieldPrivilege('plan', 'update')
|
||||
@ApiOperation({ summary: 'Update plan (not status)' })
|
||||
@ApiOkResponse({ type: PlanDto })
|
||||
@ApiNotFoundResponse()
|
||||
update(
|
||||
@Param('id', ParseUUIDPipe) id: string,
|
||||
@Body() dto: UpdatePlanDto,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<PlanDto> {
|
||||
return this.plansService.update(id, { ...dto, userId: user.id }, user);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@HttpCode(204)
|
||||
@RequireFieldPrivilege('plan', 'delete')
|
||||
@ApiOperation({ summary: 'Archive plan' })
|
||||
@ApiNoContentResponse()
|
||||
@ApiUnauthorizedResponse()
|
||||
@ApiForbiddenResponse()
|
||||
async delete(
|
||||
@Param('id', ParseUUIDPipe) id: string,
|
||||
@CurrentUser() user: AuthUser,
|
||||
): Promise<void> {
|
||||
await this.plansService.delete(id, user);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user