import { Body,Controller,Get,Param,Post,Req,UseGuards } from '@nestjs/common';
import { AuthGuard } from '../../../common/auth/auth.guard';
import { OrganizationContextGuard } from '../../../common/auth/organization-context.guard';
import { LocationContextGuard,type LocationScopedRequest } from '../../../common/auth/location-context.guard';
import { PermissionGuard } from '../../../common/auth/permission.guard';
import { RequirePermissions } from '../../../common/auth/permissions.decorator';
import { ExternalProviderRegistry } from '../providers/external-provider.registry';
import { ExternalIntegrationService } from '../application/external-integration.service';
import { ExternalMappingService } from '../application/external-mapping.service';
import { ExternalConflictService } from '../application/external-conflict.service';
import { ZodValidationPipe } from '../../../common/validation/zod-validation.pipe';
import { externalIntegrationCreateSchema,externalMappingSchema,externalPollSchema,pmsFolioChargeSchema,externalPosBatchSchema,supplierCatalogPreviewSchema,integrationConflictResolveSchema } from '../../../common/validation/critical-write.schemas';
import { ExternalPollWorker } from '../workers/external-poll.worker';
import { PmsChargeService } from '../application/pms-charge.service';
import { ExternalPosImportService } from '../application/external-pos-import.service';
import { SupplierCatalogService } from '../application/supplier-catalog.service';
import { ExternalIntegrationReadModelService } from '../application/external-integration-read-model.service';
import { HotelFnbOverviewService } from '../read-models/hotel-fnb-overview.service';
import { HotelOutletNetworkService } from '../read-models/hotel-outlet-network.service';
import { ExternalInboxWorker } from '../workers/external-inbox.worker';
import { ExternalDomainEventRouterWorker } from '../workers/external-domain-event-router.worker';
import { ExternalOutboundWorker } from '../workers/external-outbound.worker';
import { SupplierGoodsReceiptService } from '../application/supplier-goods-receipt.service';
import type { z } from 'zod';
@Controller('/external-integrations')
@UseGuards(AuthGuard,OrganizationContextGuard,LocationContextGuard,PermissionGuard)
export class ExternalIntegrationsController {
constructor(
private readonly providers:ExternalProviderRegistry,
private readonly integrations:ExternalIntegrationService,
private readonly mappings:ExternalMappingService,
private readonly conflicts:ExternalConflictService,
private readonly poller:ExternalPollWorker,
private readonly pms:PmsChargeService,
private readonly pos:ExternalPosImportService,
private readonly supplier:SupplierCatalogService,
private readonly read:ExternalIntegrationReadModelService,
private readonly hotelFnb:HotelFnbOverviewService,
private readonly hotelOutlets:HotelOutletNetworkService,
private readonly inbox:ExternalInboxWorker,
private readonly router:ExternalDomainEventRouterWorker,
private readonly outbound:ExternalOutboundWorker,
private readonly goodsReceipts:SupplierGoodsReceiptService,
) {}
@Get('/providers')
@RequirePermissions('integrations.external.read')
providersList(){return this.providers.list();}
@Get('/overview')
@RequirePermissions('integrations.external.read')
overview(@Req() req:LocationScopedRequest){
return this.read.overview({organizationId:req.organizationId!,locationId:req.locationId!});
}
@Get('/hotel-fnb-overview')
@RequirePermissions('integrations.external.read')
hotelFnbOverview(@Req() req:LocationScopedRequest){
return this.hotelFnb.overview({organizationId:req.organizationId!,locationId:req.locationId!});
}
@Get('/hotel-outlet-network')
@RequirePermissions('organizations.read')
hotelOutletNetwork(@Req() req:LocationScopedRequest){
return this.hotelOutlets.overview({organizationId:req.organizationId!});
}
@Post()
@RequirePermissions('integrations.external.manage')
create(@Req() req:LocationScopedRequest,@Body(new ZodValidationPipe(externalIntegrationCreateSchema)) body:z.infer<typeof externalIntegrationCreateSchema>){
return this.integrations.create({
organizationId:req.organizationId!,locationId:req.locationId!,
userId:req.auth?.userId,...body,
});
}
@Post('/:id/test')
@RequirePermissions('integrations.external.manage')
test(@Req() req:LocationScopedRequest,@Param('id') id:string){
return this.integrations.test({organizationId:req.organizationId!,locationId:req.locationId!,connectionId:id});
}
@Post('/:id/mappings')
@RequirePermissions('integrations.external.manage')
mapping(@Req() req:LocationScopedRequest,@Param('id') id:string,@Body(new ZodValidationPipe(externalMappingSchema)) body:z.infer<typeof externalMappingSchema>){
return this.mappings.upsert({
organizationId:req.organizationId!,locationId:req.locationId!,
connectionId:id,...body,
});
}
@Post('/:id/poll')
@RequirePermissions('integrations.external.sync')
poll(@Req() req:LocationScopedRequest,@Param('id') id:string,@Body(new ZodValidationPipe(externalPollSchema)) body:z.infer<typeof externalPollSchema>){
return this.poller.pollConnection({
organizationId:req.organizationId!,locationId:req.locationId!,connectionId:id,streamKey:body.streamKey,
});
}
@Post('/:id/pms/folio-charge')
@RequirePermissions('integrations.pms.charge')
folio(@Req() req:LocationScopedRequest,@Param('id') id:string,@Body(new ZodValidationPipe(pmsFolioChargeSchema)) body:z.infer<typeof pmsFolioChargeSchema>){
return this.pms.post({
organizationId:req.organizationId!,locationId:req.locationId!,
connectionId:id,...body,
});
}
@Post('/:id/external-pos/import-batch')
@RequirePermissions('integrations.external.sync')
posBatch(@Req() req:LocationScopedRequest,@Param('id') id:string,@Body(new ZodValidationPipe(externalPosBatchSchema)) body:z.infer<typeof externalPosBatchSchema>){
return this.pos.importBatch({
organizationId:req.organizationId!,locationId:req.locationId!,
connectionId:id,...body,
});
}
@Post('/:id/supplier/catalog/preview')
@RequirePermissions('integrations.external.sync')
catalog(@Req() req:LocationScopedRequest,@Param('id') id:string,@Body(new ZodValidationPipe(supplierCatalogPreviewSchema)) body:z.infer<typeof supplierCatalogPreviewSchema>){
return this.supplier.preview({
organizationId:req.organizationId!,locationId:req.locationId!,connectionId:id,...body,
});
}
@Post('/supplier/catalog/:importId/commit')
@RequirePermissions('integrations.external.sync')
catalogCommit(@Req() req:LocationScopedRequest,@Param('importId') importId:string){
return this.supplier.commit({organizationId:req.organizationId!,locationId:req.locationId!,importId});
}
@Post('/conflicts/:id/resolve')
@RequirePermissions('integrations.external.conflicts')
resolve(@Req() req:LocationScopedRequest,@Param('id') id:string,@Body(new ZodValidationPipe(integrationConflictResolveSchema)) body:z.infer<typeof integrationConflictResolveSchema>){
return this.conflicts.resolve({
organizationId:req.organizationId!,locationId:req.locationId!,conflictId:id,action:body.action,
userId:req.auth?.userId,note:body.note,result:body.result,
});
}
@Post('/workers/inbox')
@RequirePermissions('integrations.external.sync')
runInbox(){return this.inbox.runBatch();}
@Post('/workers/route-events')
@RequirePermissions('integrations.external.sync')
routeEvents(){return this.router.runBatch();}
@Post('/workers/outbound')
@RequirePermissions('integrations.external.sync')
runOutbound(){return this.outbound.runBatch();}
@Post('/supplier/goods-receipts/:importId/commit')
@RequirePermissions('integrations.external.sync')
goodsReceiptCommit(
@Req() req:LocationScopedRequest,
@Param('importId') importId:string,
){
return this.goodsReceipts.commit({
organizationId:req.organizationId!,locationId:req.locationId!,importId,
});
}
}
