Skip to main content

Returns Service

Overview​

The Returns Service handles return request creation, approval, rejection processing, and refund coordination. Upon return approval, it integrates with the Payment Service to process refunds.

ItemDetails
LanguageJava 17
FrameworkSpring Boot 3.2
DatabaseAurora PostgreSQL (Global Database)
Namespacemall-returns
Port8080
Health Check/actuator/health

Architecture​

API Endpoints​

MethodPathDescription
POST/api/v1/returnsCreate return request
GET/api/v1/returns/{id}Get return request
GET/api/v1/returns?userId={userId}Get returns by user
PUT/api/v1/returns/{id}/approveApprove return
PUT/api/v1/returns/{id}/rejectReject return

Create Return Request​

POST /api/v1/returns

Request:

{
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user-123",
"reason": "Product defect",
"items": [
{
"productId": "prod-001",
"sku": "SKU-ELECTRONICS-001",
"quantity": 1,
"reason": "Screen defect"
}
]
}

Response (201 Created):

{
"id": "770e8400-e29b-41d4-a716-446655440000",
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user-123",
"reason": "Product defect",
"status": "PENDING",
"items": [
{
"id": "880e8400-e29b-41d4-a716-446655440000",
"productId": "prod-001",
"sku": "SKU-ELECTRONICS-001",
"quantity": 1,
"reason": "Screen defect"
}
],
"createdAt": "2024-01-20T10:00:00",
"updatedAt": "2024-01-20T10:00:00"
}

Get Return Request​

GET /api/v1/returns/{id}

Response (200 OK):

{
"id": "770e8400-e29b-41d4-a716-446655440000",
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user-123",
"reason": "Product defect",
"status": "PENDING",
"items": [
{
"id": "880e8400-e29b-41d4-a716-446655440000",
"productId": "prod-001",
"sku": "SKU-ELECTRONICS-001",
"quantity": 1,
"reason": "Screen defect"
}
],
"createdAt": "2024-01-20T10:00:00",
"updatedAt": "2024-01-20T10:00:00"
}

Get Returns by User​

GET /api/v1/returns?userId=user-123

Response (200 OK):

[
{
"id": "770e8400-e29b-41d4-a716-446655440000",
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user-123",
"reason": "Product defect",
"status": "APPROVED",
"items": [...],
"createdAt": "2024-01-20T10:00:00",
"updatedAt": "2024-01-21T14:00:00"
}
]

Approve Return​

PUT /api/v1/returns/{id}/approve

Response (200 OK):

{
"id": "770e8400-e29b-41d4-a716-446655440000",
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user-123",
"reason": "Product defect",
"status": "APPROVED",
"items": [...],
"createdAt": "2024-01-20T10:00:00",
"updatedAt": "2024-01-21T14:00:00"
}

Reject Return​

PUT /api/v1/returns/{id}/reject

Response (200 OK):

{
"id": "770e8400-e29b-41d4-a716-446655440000",
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user-123",
"reason": "Product defect",
"status": "REJECTED",
"items": [...],
"createdAt": "2024-01-20T10:00:00",
"updatedAt": "2024-01-21T14:00:00"
}

Data Models​

ReturnRequest Entity​

@Entity
@Table(name = "return_requests")
public class ReturnRequest {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

@Column(name = "order_id", nullable = false)
private UUID orderId;

@Column(name = "user_id", nullable = false)
private String userId;

@Column(columnDefinition = "TEXT")
private String reason;

@Enumerated(EnumType.STRING)
@Column(length = 50)
private ReturnStatus status = ReturnStatus.PENDING;

@OneToMany(mappedBy = "returnRequest", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ReturnItem> items = new ArrayList<>();

@Column(name = "created_at")
private LocalDateTime createdAt;

@Column(name = "updated_at")
private LocalDateTime updatedAt;
}

ReturnItem Entity​

@Entity
@Table(name = "return_items")
public class ReturnItem {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

@ManyToOne
@JoinColumn(name = "return_id")
private ReturnRequest returnRequest;

@Column(name = "product_id", nullable = false)
private String productId;

@Column(nullable = false)
private String sku;

@Column(nullable = false)
private Integer quantity;

@Column(columnDefinition = "TEXT")
private String reason;
}

ReturnStatus Enum​

public enum ReturnStatus {
PENDING, // Pending
APPROVED, // Approved
REJECTED, // Rejected
REFUNDED // Refunded
}

Database Schema​

CREATE TABLE return_requests (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
order_id UUID NOT NULL,
user_id VARCHAR(255) NOT NULL,
reason TEXT,
status VARCHAR(50) DEFAULT 'PENDING',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE return_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
return_id UUID REFERENCES return_requests(id),
product_id VARCHAR(255) NOT NULL,
sku VARCHAR(255) NOT NULL,
quantity INTEGER NOT NULL,
reason TEXT
);

CREATE INDEX idx_return_requests_order_id ON return_requests(order_id);
CREATE INDEX idx_return_requests_user_id ON return_requests(user_id);
CREATE INDEX idx_return_requests_status ON return_requests(status);
CREATE INDEX idx_return_items_return_id ON return_items(return_id);

Events (Kafka)​

Published Topics​

Topic NameEventDescription
returns.createdreturn.createdPublished when return request is created
returns.approvedreturn.approvedPublished when return is approved
returns.rejectedreturn.rejectedPublished when return is rejected

returns.created Payload​

{
"return_id": "770e8400-e29b-41d4-a716-446655440000",
"order_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "user-123",
"status": "PENDING",
"reason": "Product defect",
"item_count": 1
}

returns.approved Payload​

{
"return_id": "770e8400-e29b-41d4-a716-446655440000",
"order_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "user-123",
"status": "APPROVED",
"reason": "Product defect",
"item_count": 1
}

returns.rejected Payload​

{
"return_id": "770e8400-e29b-41d4-a716-446655440000",
"order_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "user-123",
"status": "REJECTED",
"reason": "Product defect",
"item_count": 1
}

Environment Variables​

VariableDescriptionDefault
SPRING_DATASOURCE_URLAurora PostgreSQL connection URL-
SPRING_DATASOURCE_USERNAMEDB username-
SPRING_DATASOURCE_PASSWORDDB password-
SPRING_KAFKA_BOOTSTRAP_SERVERSKafka broker address-
SERVER_PORTService port8080

Service Dependencies​

Return Processing Flow​

Return Status Flow​

Error Handling​

HTTP Status CodeErrorDescription
404ReturnNotFoundExceptionReturn request not found
400IllegalStateExceptionInvalid state transition (e.g., already processed return)
400InvalidReturnRequestExceptionInvalid return request (return period exceeded, etc.)