feat: add contract extension request functionality

- Implemented  method in  to allow customers to request an extension for expired contracts.
- Added  component in  for users to initiate extension requests.
- Updated  to include logic for handling extension requests for expired contracts.
- Enhanced  to display extension request options and status.
- Created migration to add  and  columns to the contracts table.
- Added unit tests for contract extension request and handling in .
- Defined DTOs for request and extension in .
- Updated types in  to include new fields related to contract extensions.
This commit is contained in:
marshal
2026-09-06 12:33:40 +00:00
parent f225721e89
commit 75b75e3d4e
32 changed files with 1582 additions and 179 deletions

View File

@@ -78,6 +78,10 @@ import {
import { SignContractDto } from './dto/sign-contract.dto';
import { ReviewClearanceDocumentDto } from './dto/review-clearance-document.dto';
import { RenewContractDto } from './dto/renew-contract.dto';
import {
ExtendContractDto,
RequestContractExtensionDto,
} from './dto/extend-contract.dto';
import {
CompleteConsolidatedPairDto,
CreateBookingUnderContractDto,
@@ -528,6 +532,52 @@ export class ContractsController {
);
}
@Post(':id/extension-request')
@PortalCustomer()
@ApiOperation({
summary: 'Customer asks EDR to extend the validity of their expired contract',
})
async requestExtension(
@Param('id', ParseUUIDPipe) id: string,
@Body() dto: RequestContractExtensionDto,
@CurrentUser() user: TCurrentUser,
) {
// Same ownership rule as cancel/renew: staff with bookings.view/contracts.view
// pass through, everyone else must own the contract's company.
const contract = await this.contractsService.findById(id);
if (
!hasFreightPermission(user, FREIGHT_PERMS.bookings.view) &&
!hasFreightPermission(user, FREIGHT_PERMS.contracts.view)
) {
await this.contractsService.assertCustomerCanAccessContract(user?.id, contract);
}
return this.transitionService.requestExtension(
id,
dto.note,
resolveAuthUserId(user),
);
}
@Post(':id/extend')
@BookingStaff(FREIGHT_PERMS.contracts.extend)
@ApiOperation({
summary:
'Staff extend an expired contract the customer asked to extend — it returns to its pre-expiry status',
})
extend(
@Param('id', ParseUUIDPipe) id: string,
@Body() dto: ExtendContractDto,
@CurrentUser() user: TCurrentUser,
) {
return this.transitionService.extend(
id,
dto.days,
dto.note,
resolveAuthUserId(user),
user,
);
}
@Post(':id/cancel')
@PortalCustomer()
@ApiOperation({