Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.mulmi.backend.domain.equipment.controller;

import com.mulmi.backend.domain.equipment.dto.request.EquipmentModelCreateRequestDTO;
import com.mulmi.backend.domain.equipment.dto.response.EquipmentModelCreateResponseDTO;
import com.mulmi.backend.domain.equipment.exception.code.EquipmentModelSuccessCode;
import com.mulmi.backend.domain.equipment.service.EquipmentModelService;
import com.mulmi.backend.global.apiPayload.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/admin/equipment-models")
@Tag(name = "모델 관리", description = "조교용 모델 관리 API")
public class AdminEquipmentModelController {

private final EquipmentModelService equipmentModelService;

// 모델 등록
@Operation(summary = "모델 등록")
@PostMapping
@PreAuthorize("hasRole('ASSISTANT')")
public ApiResponse<EquipmentModelCreateResponseDTO> createEquipmentModel(
@RequestBody @Valid EquipmentModelCreateRequestDTO dto
) {
return ApiResponse.onSuccess(
EquipmentModelSuccessCode.MODEL_CREATED,
equipmentModelService.createEquipmentModel(dto)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

import com.mulmi.backend.domain.equipment.dto.response.CategoryResponseDTO;
import com.mulmi.backend.domain.equipment.entity.Category;
import com.mulmi.backend.domain.equipment.enums.LoanPeriodType;

public class CategoryConverter {

// 이름 -> Category
public static Category toCategory(String name) {
return Category.builder()
.name(name)
.regularRentalEnabled(false)
.loanPeriodType(LoanPeriodType.FIXED_DAYS)
.loanDurationDays(1)
.pickupPhotoRequired(false)
.pledgeRequired(false)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.mulmi.backend.domain.equipment.converter;

import com.mulmi.backend.domain.equipment.dto.request.EquipmentModelCreateRequestDTO;
import com.mulmi.backend.domain.equipment.dto.response.EquipmentModelCreateResponseDTO;
import com.mulmi.backend.domain.equipment.entity.Category;
import com.mulmi.backend.domain.equipment.entity.EquipmentItem;
import com.mulmi.backend.domain.equipment.entity.EquipmentModel;
import com.mulmi.backend.domain.equipment.entity.LabelPrefix;
import com.mulmi.backend.domain.equipment.enums.EquipmentItemStatus;

public class EquipmentModelConverter {

// 요청 DTO + 조회해 온 카테고리,접두사 -> EquipmentModel
public static EquipmentModel toEquipmentModel(
EquipmentModelCreateRequestDTO dto, Category category, LabelPrefix labelPrefix) {
return EquipmentModel.builder()
.category(category)
.labelPrefix(labelPrefix)
.name(dto.modelName().trim())
.components(dto.components())
.specification(dto.specification())
.description(dto.description())
.rentalStatus(dto.rentalStatus())
.disposalDate(dto.disposalDate())
.build();
}

// 모델 + 발급 번호 -> EquipmentItem 한 대
public static EquipmentItem toEquipmentItem(EquipmentModel model, int labelNumber) {
String labelCode = String.format("%s-%03d", model.getLabelPrefix().getCode(), labelNumber);
return EquipmentItem.builder()
.equipmentModel(model)
.labelNumber(labelNumber)
.labelCode(labelCode)
.status(EquipmentItemStatus.AVAILABLE)
.build();
}

// 저장된 모델 + 생성된 아이템 목록 -> 응답 DTO
public static EquipmentModelCreateResponseDTO toEquipmentModelCreateResponseDTO(
EquipmentModel model) {
return new EquipmentModelCreateResponseDTO(
model.getId()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.mulmi.backend.domain.equipment.dto.request;

import com.mulmi.backend.domain.equipment.enums.EquipmentModelStatus;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import java.time.LocalDate;

public record EquipmentModelCreateRequestDTO(
@NotNull(message = "카테고리는 필수입니다.")
Long categoryId,

@Size(max = 10)
String prefixCode,

@Size(max = 100, message = "모델명은 100자를 넘을 수 없습니다.")
@NotBlank(message = "모델명은 필수입니다.")
String modelName,

@NotBlank(message = "구성품은 필수입니다.")
String components,

String description,
String specification,

@NotNull(message = "상태는 필수입니다.")
EquipmentModelStatus rentalStatus,

@NotNull(message = "폐기일은 필수입니다.")
LocalDate disposalDate
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.mulmi.backend.domain.equipment.dto.response;

public record EquipmentModelCreateResponseDTO(
Long modelId
) {
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.mulmi.backend.domain.equipment.entity;

import com.mulmi.backend.domain.equipment.enums.LoanPeriodType;
import com.mulmi.backend.global.common.BaseEntity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;

@Entity
@Getter
Expand All @@ -19,6 +22,31 @@ public class Category extends BaseEntity {
@Column(name= "category_name", nullable = false, unique = true, length = 50)
private String name;

@Column(name = "label_required", nullable = false)
private boolean labelRequired;

// 정기대여 가능 여부
@Column(name = "regular_rental_enabled", nullable = false)
private boolean regularRentalEnabled;

// 기간 유형
@JdbcTypeCode(SqlTypes.VARCHAR)
@Column(name = "loan_period_type", nullable = false, length = 30)
@Enumerated(EnumType.STRING)
private LoanPeriodType loanPeriodType;

// 대여 일수 (SEMESTER_END면 null)
@Column(name = "loan_duration_days", nullable = true)
private Integer loanDurationDays;

// 수령 사진 필수 여부
@Column(name = "pickup_photo_required", nullable = false)
private boolean pickupPhotoRequired;

// 서약서 필수 여부
@Column(name = "pledge_required", nullable = false)
private boolean pledgeRequired;

public void updateCategoryName(String name) {
this.name = name;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.mulmi.backend.domain.equipment.entity;

import com.mulmi.backend.domain.equipment.enums.EquipmentItemStatus;
import com.mulmi.backend.global.common.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;

@Entity
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Table(name = "equipment_item")
public class EquipmentItem extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "model_id", nullable = false)
private EquipmentModel equipmentModel;

@Column(name="label_number")
private Integer labelNumber;

@Column(name="label_code", length = 30, unique = true)
private String labelCode;

@JdbcTypeCode(SqlTypes.VARCHAR)
@Enumerated(EnumType.STRING)
@Column(name="status", length = 30, nullable = false)
private EquipmentItemStatus status;

@Column(name = "memo", nullable = true, columnDefinition = "TEXT")
private String memo;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.mulmi.backend.domain.equipment.entity;

import com.mulmi.backend.domain.equipment.enums.ApplicationPolicy;
import com.mulmi.backend.domain.equipment.enums.EquipmentModelStatus;
import com.mulmi.backend.domain.equipment.enums.LoanPeriodType;
import com.mulmi.backend.global.common.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand All @@ -21,6 +19,10 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;

import java.time.LocalDate;

@Entity
@Getter
Expand All @@ -39,13 +41,13 @@ public class EquipmentModel extends BaseEntity {
private Category category;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "prefix_id", nullable = false)
@JoinColumn(name = "prefix_id")
private LabelPrefix labelPrefix;

@Column(name = "model_name", nullable = false, length = 100)
private String name;

@Column(nullable = true, columnDefinition = "TEXT")
@Column(nullable = false, columnDefinition = "TEXT")
private String components;

@Column(nullable = true, columnDefinition = "TEXT")
Expand All @@ -57,23 +59,11 @@ public class EquipmentModel extends BaseEntity {
@Column(name = "model_image_url", nullable = true, length = 1000)
private String modelImageUrl;

@Column(name = "application_policy", nullable = false, length = 30)
@Enumerated(EnumType.STRING)
private ApplicationPolicy applicationPolicy;

@Column(name = "loan_period_type", nullable = false, length = 30)
@Enumerated(EnumType.STRING)
private LoanPeriodType loanPeriodType;

@Column(name = "loan_duration_days", nullable = true)
private Integer loanDurationDays;

@Column(name = "pledge_required", nullable = false)
private boolean pledgeRequired;

@JdbcTypeCode(SqlTypes.VARCHAR)
@Column(name = "rental_status", nullable = false, length = 30)
@Enumerated(EnumType.STRING)
private EquipmentModelStatus rentalStatus;


@Column(name = "disposal_date", nullable = false)
private LocalDate disposalDate;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.mulmi.backend.domain.equipment.enums;

public enum ApplicationPolicy {
REGULAR_AND_ON_DEMAND,
ON_DEMAND_ONLY
REGULAR,
ON_DEMAND
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mulmi.backend.domain.equipment.enums;

public enum EquipmentItemStatus {
AVAILABLE,
RENTED,
BROKEN,
REPAIRING,
DISPOSAL_PENDING,
DISPOSED
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@ public enum EquipmentModelStatus {
// 모델 대여 '가능여부'의 상태
// 대여신청에 나올 rental status와 헷갈리지 말 것
AVAILABLE,
UNAVAILABLE,
DISCONTINUED
UNAVAILABLE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mulmi.backend.domain.equipment.exception;

import com.mulmi.backend.global.apiPayload.code.BaseErrorCode;
import com.mulmi.backend.global.apiPayload.exception.GeneralException;

public class EquipmentModelException extends GeneralException {
public EquipmentModelException(BaseErrorCode code) {
super(code);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mulmi.backend.domain.equipment.exception;

import com.mulmi.backend.global.apiPayload.code.BaseErrorCode;
import com.mulmi.backend.global.apiPayload.exception.GeneralException;

public class LabelPrefixException extends GeneralException {
public LabelPrefixException(BaseErrorCode code) {
super(code);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.mulmi.backend.domain.equipment.exception.code;

import com.mulmi.backend.global.apiPayload.code.BaseErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum EquipmentModelErrorCode implements BaseErrorCode {

LABEL_PREFIX_REQUIRED(
HttpStatus.BAD_REQUEST,
"EQUIPMENTMODEL400_2",
"라벨을 쓰는 카테고리는 접두사가 필요합니다."
),

LABEL_PREFIX_NOT_ALLOWED(
HttpStatus.BAD_REQUEST,
"EQUIPMENTMODEL400_3",
"라벨을 쓰지 않는 카테고리에는 접두사를 입력할 수 없습니다."
),

DUPLICATE_MODEL(
HttpStatus.CONFLICT,
"EQUIPMENTMODEL409_1",
"같은 카테고리에 동일 이름의 모델이 이미 있습니다."
);

private final HttpStatus status;
private final String code;
private final String message;
}
Loading
Loading