Refactor OrderFulfillmentController for improved readability and consistency

- Consolidated import statements for better clarity.
- Streamlined API operation and parameter definitions for enhanced readability.
- Cleaned up response schemas and error handling for consistency across API responses.
- Improved logging messages for better context during order fulfillment requests.
This commit is contained in:
T. Narantuya 2025-09-02 16:09:54 +09:00
parent 98f998db51
commit bb6593c9a3

View File

@ -1,13 +1,4 @@
import {
Controller,
Post,
Param,
Body,
Headers,
HttpCode,
HttpStatus,
UseGuards,
} from "@nestjs/common";
import { Controller, Post, Param, Body, Headers, HttpCode, HttpStatus, UseGuards } from "@nestjs/common";
import { ApiTags, ApiOperation, ApiParam, ApiResponse, ApiHeader } from "@nestjs/swagger";
import { ThrottlerGuard } from "@nestjs/throttler";
import { Logger } from "nestjs-pino";
@ -30,38 +21,37 @@ export class OrderFulfillmentController {
@UseGuards(ThrottlerGuard, EnhancedWebhookSignatureGuard)
@ApiOperation({
summary: "Fulfill order from Salesforce",
description:
"Secure endpoint called by Salesforce Quick Action to fulfill orders in WHMCS. Handles complete flow: SF Order → WHMCS AddOrder/AcceptOrder → SF Status Update",
description: "Secure endpoint called by Salesforce Quick Action to fulfill orders in WHMCS. Handles complete flow: SF Order → WHMCS AddOrder/AcceptOrder → SF Status Update"
})
@ApiParam({
name: "sfOrderId",
type: String,
description: "Salesforce Order ID to provision",
example: "8014x000000ABCDXYZ",
example: "8014x000000ABCDXYZ"
})
@ApiHeader({
name: "X-SF-Signature",
description: "HMAC-SHA256 signature of request body using shared secret",
required: true,
example: "a1b2c3d4e5f6...",
example: "a1b2c3d4e5f6..."
})
@ApiHeader({
name: "X-SF-Timestamp",
description: "ISO timestamp of request (max 5 minutes old)",
required: true,
example: "2024-01-15T10:30:00Z",
example: "2024-01-15T10:30:00Z"
})
@ApiHeader({
name: "X-SF-Nonce",
description: "Unique nonce to prevent replay attacks",
required: true,
example: "abc123def456",
example: "abc123def456"
})
@ApiHeader({
name: "Idempotency-Key",
description: "Unique key for safe retries",
required: true,
example: "provision_8014x000000ABCDXYZ_1705312200000",
example: "provision_8014x000000ABCDXYZ_1705312200000"
})
@ApiResponse({
status: 200,
@ -70,16 +60,12 @@ export class OrderFulfillmentController {
type: "object",
properties: {
success: { type: "boolean", example: true },
status: {
type: "string",
enum: ["Provisioned", "Already Provisioned"],
example: "Provisioned",
},
status: { type: "string", enum: ["Provisioned", "Already Provisioned"], example: "Provisioned" },
whmcsOrderId: { type: "string", example: "12345" },
whmcsServiceIds: { type: "array", items: { type: "number" }, example: [67890, 67891] },
message: { type: "string", example: "Order provisioned successfully in WHMCS" },
},
},
message: { type: "string", example: "Order provisioned successfully in WHMCS" }
}
}
})
@ApiResponse({
status: 400,
@ -90,13 +76,13 @@ export class OrderFulfillmentController {
success: { type: "boolean", example: false },
status: { type: "string", example: "Failed" },
message: { type: "string", example: "Salesforce order not found" },
errorCode: { type: "string", example: "ORDER_NOT_FOUND" },
},
},
errorCode: { type: "string", example: "ORDER_NOT_FOUND" }
}
}
})
@ApiResponse({
status: 401,
description: "Invalid signature or authentication",
description: "Invalid signature or authentication"
})
@ApiResponse({
status: 409,
@ -106,20 +92,17 @@ export class OrderFulfillmentController {
properties: {
success: { type: "boolean", example: false },
status: { type: "string", example: "Failed" },
message: {
type: "string",
example: "Payment method missing - client must add payment method before provisioning",
},
errorCode: { type: "string", example: "PAYMENT_METHOD_MISSING" },
},
},
message: { type: "string", example: "Payment method missing - client must add payment method before provisioning" },
errorCode: { type: "string", example: "PAYMENT_METHOD_MISSING" }
}
}
})
async fulfillOrder(
@Param("sfOrderId") sfOrderId: string,
@Body() payload: OrderFulfillmentRequest,
@Headers("idempotency-key") idempotencyKey: string
) {
this.logger.log("Salesforce fulfillment request received", {
this.logger.log("Salesforce order fulfillment request received", {
sfOrderId,
idempotencyKey,
timestamp: payload.timestamp,
@ -150,6 +133,7 @@ export class OrderFulfillmentController {
...(result.errorCode && { errorCode: result.errorCode }),
timestamp: new Date().toISOString(),
};
} catch (error) {
this.logger.error("Salesforce provisioning failed", {
error: error instanceof Error ? error.message : String(error),