mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 15:18:11 +00:00
Seats report, supplementary change for bookings added
This commit is contained in:
@@ -39,12 +39,34 @@ import {
|
||||
import { PassengerStaff } from "../../common/passenger-guards";
|
||||
import { PASSENGER_PERMS } from "../../seed/passenger-permissions.registry";
|
||||
import { resolveAllowedOrigin } from "../../common/utils/redirect-origin.util";
|
||||
import { SupplementaryChargesService } from "./supplementary-charges.service";
|
||||
import { IsString, IsInt, IsOptional, Min, IsEnum, IsIn } from "class-validator";
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
|
||||
class CreateSupplementaryChargeDto {
|
||||
@ApiProperty({ example: 'EDR-20240001', description: 'Booking reference number' }) @IsString() bookingRef: string;
|
||||
@ApiProperty({ description: 'Amount owed in minor units (e.g. 5000 = 50 ETB)' }) @IsInt() @Min(1) amountMinor: number;
|
||||
@ApiProperty({ example: 'UNDERPAYMENT' }) @IsString() reason: string;
|
||||
@ApiPropertyOptional() @IsOptional() @IsString() notes?: string;
|
||||
}
|
||||
|
||||
class WaiveSupplementaryChargeDto {
|
||||
@ApiPropertyOptional() @IsOptional() @IsString() notes?: string;
|
||||
}
|
||||
|
||||
class PaySupplementaryChargeDto {
|
||||
@ApiProperty({ enum: PaymentMethodTypeEnum, example: 'TELEBIRR' }) @IsEnum(PaymentMethodTypeEnum) method: PaymentMethodTypeEnum;
|
||||
@ApiPropertyOptional({ enum: ['web', 'mobile'], default: 'web' }) @IsOptional() @IsIn(['web', 'mobile']) platform?: 'web' | 'mobile';
|
||||
}
|
||||
|
||||
@ApiTags("Payment")
|
||||
@Controller("payments")
|
||||
// @Throttle({ strict: { limit: 20, ttl: 60_000 } })
|
||||
export class PaymentsController {
|
||||
constructor(private service: PaymentsService) {}
|
||||
constructor(
|
||||
private service: PaymentsService,
|
||||
private supplementaryService: SupplementaryChargesService,
|
||||
) {}
|
||||
|
||||
@Delete(":id")
|
||||
@PassengerStaff([PASSENGER_PERMS.admin])
|
||||
@@ -315,6 +337,92 @@ export class PaymentsController {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Supplementary Charges ──────────────────────────────────────────────────
|
||||
|
||||
@Post('supplementary')
|
||||
@PassengerStaff([PASSENGER_PERMS.payments.manage, PASSENGER_PERMS.admin])
|
||||
@ApiBearerAuth('IAM-auth')
|
||||
@ApiOperation({ summary: 'Raise a supplementary charge for an underpayment (staff only)' })
|
||||
createSupplementaryCharge(
|
||||
@Body() dto: CreateSupplementaryChargeDto,
|
||||
@Headers('x-iam-user-id') iamUserId?: string,
|
||||
) {
|
||||
return this.supplementaryService.create({
|
||||
...dto,
|
||||
createdBy: iamUserId ?? 'staff',
|
||||
});
|
||||
}
|
||||
|
||||
@Get('supplementary')
|
||||
@PassengerStaff([PASSENGER_PERMS.payments.view, PASSENGER_PERMS.payments.viewAll, PASSENGER_PERMS.admin])
|
||||
@ApiBearerAuth('IAM-auth')
|
||||
@ApiOperation({ summary: 'List supplementary charges (staff only)' })
|
||||
@ApiQuery({ name: 'bookingRef', required: false })
|
||||
@ApiQuery({ name: 'status', required: false })
|
||||
@ApiQuery({ name: 'page', required: false })
|
||||
@ApiQuery({ name: 'pageSize', required: false })
|
||||
listSupplementaryCharges(
|
||||
@Query('bookingRef') bookingRef?: string,
|
||||
@Query('status') status?: string,
|
||||
@Query('page') page?: string,
|
||||
@Query('pageSize') pageSize?: string,
|
||||
) {
|
||||
return this.supplementaryService.getAll({
|
||||
bookingRef,
|
||||
status,
|
||||
page: page ? parseInt(page) : 1,
|
||||
pageSize: pageSize ? parseInt(pageSize) : 20,
|
||||
});
|
||||
}
|
||||
|
||||
@Get('supplementary/by-token/:token')
|
||||
@SetMetadata('isPublic', true)
|
||||
@ApiOperation({ summary: 'Get supplementary charge by payment token (public — for self-pay page)' })
|
||||
getSupplementaryByToken(@Param('token') token: string) {
|
||||
return this.supplementaryService.getByToken(token);
|
||||
}
|
||||
|
||||
@Post('supplementary/by-token/:token/pay')
|
||||
@SetMetadata('isPublic', true)
|
||||
@ApiOperation({ summary: 'Initiate payment for a supplementary charge (public — self-pay)' })
|
||||
paySupplementaryCharge(
|
||||
@Param('token') token: string,
|
||||
@Body() dto: PaySupplementaryChargeDto,
|
||||
) {
|
||||
return this.supplementaryService.pay(token, dto.method, dto.platform);
|
||||
}
|
||||
|
||||
@Post('supplementary/:id/mark-paid')
|
||||
@PassengerStaff([PASSENGER_PERMS.payments.manage, PASSENGER_PERMS.admin])
|
||||
@ApiBearerAuth('IAM-auth')
|
||||
@ApiOperation({ summary: 'Manually mark a supplementary charge as paid (staff only)' })
|
||||
markSupplementaryPaid(
|
||||
@Param('id') id: string,
|
||||
@Body() body: { providerTxnId?: string },
|
||||
) {
|
||||
return this.supplementaryService.markPaid(id, body.providerTxnId);
|
||||
}
|
||||
|
||||
@Post('supplementary/:id/waive')
|
||||
@PassengerStaff([PASSENGER_PERMS.payments.manage, PASSENGER_PERMS.admin])
|
||||
@ApiBearerAuth('IAM-auth')
|
||||
@ApiOperation({ summary: 'Waive a supplementary charge (staff only)' })
|
||||
waiveSupplementaryCharge(
|
||||
@Param('id') id: string,
|
||||
@Body() dto: WaiveSupplementaryChargeDto,
|
||||
@Headers('x-iam-user-id') iamUserId?: string,
|
||||
) {
|
||||
return this.supplementaryService.waive(id, dto.notes ?? '', iamUserId ?? 'staff');
|
||||
}
|
||||
|
||||
@Post('supplementary/:id/resend')
|
||||
@PassengerStaff([PASSENGER_PERMS.payments.manage, PASSENGER_PERMS.admin])
|
||||
@ApiBearerAuth('IAM-auth')
|
||||
@ApiOperation({ summary: 'Resend payment link for a supplementary charge (staff only)' })
|
||||
resendSupplementaryLink(@Param('id') id: string) {
|
||||
return this.supplementaryService.resendLink(id);
|
||||
}
|
||||
|
||||
private buildRedirectHtml(url: string): string {
|
||||
const escaped = url.replace(/\"/g, """);
|
||||
return `<!DOCTYPE html>
|
||||
|
||||
Reference in New Issue
Block a user