This commit is contained in:
Marshal
2026-07-07 18:40:32 +00:00
parent b57840c907
commit 8addfdf3e2
7 changed files with 529 additions and 74 deletions

View File

@@ -9,6 +9,7 @@ import { BillingService } from '../billing/billing.service';
import { Booking } from '../bookings/entities/booking.entity';
import { BookingContainer } from '../bookings/entities/booking-container.entity';
import { BookingContainerUnit } from '../bookings/entities/booking-container-unit.entity';
import { Contract } from '../contracts/entities/contract.entity';
import {
BookingBatchOffer,
OfferedLine,
@@ -30,10 +31,11 @@ export interface SizedOffer {
* pays, which is the act of accepting the split (applySplit). No payment →
* offer expires and the booking stays whole.
*
* Only GENERAL-contract commercial bookings are offered partials: the remainder
* GENERAL and ONE_TIME commercial bookings are offered partials: the remainder
* returns to the contract's quantity cap (derived live from booking_container
* rows, so reducing the lines releases it automatically) and can be rebooked in
* any later window within contract validity.
* any later window within contract validity. A ONE_TIME contract is promoted to
* GENERAL on split (see applySplit) so its remainder is actually rebookable.
*/
@Injectable()
export class BookingSplitService {
@@ -245,6 +247,25 @@ export class BookingSplitService {
pricingBreakdown: offer.offeredPricingBreakdown,
} as never);
// A ONE_TIME contract permits a single active booking, which would block the
// split remainder from ever being rebooked. Promote the parent contract (and
// the booking's denormalized copy) to GENERAL so the leftover quantity draws
// down against the cap like any general contract, within the same validity.
const booking = await manager.getRepository(Booking).findOne({
where: { id: bookingId },
select: { id: true, contractId: true, contractKind: true },
});
if (booking?.contractKind === 'ONE_TIME') {
await manager
.getRepository(Booking)
.update(bookingId, { contractKind: 'GENERAL' } as never);
if (booking.contractId) {
await manager
.getRepository(Contract)
.update(booking.contractId, { contractKind: 'GENERAL' } as never);
}
}
await manager
.getRepository(BookingBatchOffer)
.update(offer.id, { status: 'APPLIED' });