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
Expand Up @@ -51,6 +51,6 @@ public ResponseEntity<Void> update(
@PathVariable("sensorId") String sensorId,
@RequestBody SensorUpdateDto dto) {
service.updateSensor(sensorId, dto);
return ResponseEntity.noContent().build();
return ResponseEntity.noContent().build(); // 204 응닡 λ°˜ν™˜
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.factoreal.backend.controller;

import com.factoreal.backend.dto.CreateWorkerRequest;
import com.factoreal.backend.dto.WorkerDto;
import com.factoreal.backend.dto.ZoneManagerResponseDto;
import com.factoreal.backend.service.WorkerService;
Expand All @@ -17,10 +18,18 @@
@RequestMapping("/api/workers")
@RequiredArgsConstructor
@Slf4j
@Tag(name = "μž‘μ—…μž API", description = "μž‘μ—…μž 쑰회 API")
@Tag(name = "μž‘μ—…μž API", description = "μž‘μ—…μž 쑰회 및 생성 API")
public class WorkerController {
private final WorkerService workerService;

@Operation(summary = "μž‘μ—…μž 생성", description = "μƒˆλ‘œμš΄ μž‘μ—…μžλ₯Ό μƒμ„±ν•˜κ³  μ ‘κ·Ό κ°€λŠ₯ν•œ 곡간듀을 μ„ νƒν•©λ‹ˆλ‹€.")
@PostMapping
public ResponseEntity<Void> createWorker(@RequestBody CreateWorkerRequest request) {
log.info("μž‘μ—…μž 생성 μš”μ²­: {}", request);
workerService.createWorker(request);
return ResponseEntity.ok().build(); // μž‘μ—…μž 생성 성곡 μ‹œ 200 응닡
}

@Operation(summary = "전체 μž‘μ—…μž λͺ©λ‘ 쑰회", description = "전체 μž‘μ—…μž λͺ©λ‘μ„ μ‘°νšŒν•©λ‹ˆλ‹€.")
@GetMapping
public ResponseEntity<List<WorkerDto>> getAllWorkers() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.factoreal.backend.controller;

import com.factoreal.backend.dto.WorkerManagerResponse;
import com.factoreal.backend.service.WorkerManagerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Tag(name = "곡간 λ‹΄λ‹Ήμž API", description = "곡간별 λ‹΄λ‹Ήμž 관리 API")
@Slf4j
@RestController
@RequestMapping("/api/zone-managers")
@RequiredArgsConstructor
public class WorkerManagerController {

private final WorkerManagerService workerManagerService;

@Operation(summary = "곡간 λ‹΄λ‹Ήμž 후보 λͺ©λ‘ 쑰회", description = "νŠΉμ • κ³΅κ°„μ˜ λ‹΄λ‹Ήμžλ‘œ μ§€μ • κ°€λŠ₯ν•œ μž‘μ—…μž λͺ©λ‘μ„ μ‘°νšŒν•©λ‹ˆλ‹€.")
@GetMapping("/candidates/{zoneId}")
public ResponseEntity<List<WorkerManagerResponse>> getManagerCandidates(
@Parameter(description = "곡간 ID", required = true)
@PathVariable String zoneId) {
log.info("곡간 ID: {}의 λ‹΄λ‹Ήμž 후보 λͺ©λ‘ 쑰회 μš”μ²­", zoneId);
return ResponseEntity.ok(workerManagerService.getManagerCandidates(zoneId));
}

@Operation(summary = "곡간 λ‹΄λ‹Ήμž μ§€μ •", description = "νŠΉμ • κ³΅κ°„μ˜ λ‹΄λ‹Ήμžλ₯Ό μ§€μ •ν•©λ‹ˆλ‹€.")
@PostMapping("/{zoneId}/assign/{workerId}")
public ResponseEntity<Void> assignManager(
@Parameter(description = "곡간 ID", required = true)
@PathVariable String zoneId,
@Parameter(description = "μž‘μ—…μž ID", required = true)
@PathVariable String workerId) {
log.info("곡간 ID: {}의 λ‹΄λ‹Ήμžλ₯Ό μž‘μ—…μž ID: {}둜 μ§€μ • μš”μ²­", zoneId, workerId);
workerManagerService.assignManager(zoneId, workerId);
return ResponseEntity.ok().build();
}

@Operation(summary = "ν˜„μž¬ 곡간 λ‹΄λ‹Ήμž 쑰회", description = "νŠΉμ • κ³΅κ°„μ˜ ν˜„μž¬ λ‹΄λ‹Ήμž 정보λ₯Ό μ‘°νšŒν•©λ‹ˆλ‹€.")
@GetMapping("/{zoneId}")
public ResponseEntity<WorkerManagerResponse> getCurrentManager(
@Parameter(description = "곡간 ID", required = true)
@PathVariable String zoneId) {
log.info("곡간 ID: {}의 ν˜„μž¬ λ‹΄λ‹Ήμž 쑰회 μš”μ²­", zoneId);
WorkerManagerResponse manager = workerManagerService.getCurrentManager(zoneId);
return manager != null ? ResponseEntity.ok(manager) : ResponseEntity.noContent().build();
// λ‹΄λ‹Ήμžκ°€ 있으면 λ‹΄λ‹Ήμž 정보 λ°˜ν™˜, μ—†μœΌλ©΄ 빈 응닡
}
}
21 changes: 21 additions & 0 deletions src/main/java/com/factoreal/backend/dto/CreateWorkerRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.factoreal.backend.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
// μž‘μ—…μž 생성 μš”μ²­ DTO (FE -> BE)
public class CreateWorkerRequest {
private String workerId; // μž‘μ—…μž ID (사원 번호)
private String name; // μž‘μ—…μž 이름
private String phoneNumber; // μ—°λ½μ²˜
private String email; // 이메일
private List<String> zoneNames; // μΆœμž… κ°€λŠ₯ν•œ 곡간λͺ… 리슀트
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@Getter
@Setter
@ToString
// Wearable μž₯μΉ˜μ—μ„œ λ°›μ•„μ˜€λŠ” 데이터 by 우영. μΆ”ν›„ λ…Όμ˜ μ˜ˆμ •
// Wearable μž₯μΉ˜μ—μ„œ λ°›μ•„μ˜€λŠ” 데이터 by 우영
public class WorkerLocationRequest {
private String workerId;
private String zoneId;
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/factoreal/backend/dto/WorkerManagerResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.factoreal.backend.dto;

import com.factoreal.backend.entity.Worker;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
// 곡간 λ‹΄λ‹Ήμž 후보 λͺ©λ‘ 응닡 DTO (BE -> FE)
public class WorkerManagerResponse {
private String workerId; // 직원 아이디
private String name; // 직원 이름
private Boolean isManager; // κ³΅κ°„λ‹΄λ‹Ήμž μ—¬λΆ€

public static WorkerManagerResponse fromEntity(Worker worker, Boolean isManager) {
return WorkerManagerResponse.builder()
.workerId(worker.getWorkerId())
.name(worker.getName())
.isManager(isManager)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,10 @@ public interface WorkerZoneRepository extends JpaRepository<WorkerZone, WorkerZo

// νŠΉμ • zone_id의 λ‹΄λ‹Ήμž 쑰회 (manageYn = true)
Optional<WorkerZone> findByZoneZoneIdAndManageYnIsTrue(String zoneId);

// νŠΉμ • 곡간을 μ œμ™Έν•œ λ‹€λ₯Έ κ³΅κ°„μ˜ λ‹΄λ‹Ήμž λͺ©λ‘ 쑰회
List<WorkerZone> findByZoneZoneIdNotAndManageYnIsTrue(String zoneId);

// νŠΉμ • μž‘μ—…μžκ°€ λ‹΄λ‹Ήμžλ‘œ μžˆλŠ” 곡간 쑰회
Optional<WorkerZone> findByWorkerWorkerIdAndManageYnIsTrue(String workerId);
}
106 changes: 106 additions & 0 deletions src/main/java/com/factoreal/backend/service/WorkerManagerService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.factoreal.backend.service;

import com.factoreal.backend.dto.WorkerManagerResponse;
import com.factoreal.backend.entity.Worker;
import com.factoreal.backend.entity.WorkerZone;
import com.factoreal.backend.entity.WorkerZoneId;
import com.factoreal.backend.entity.Zone;
import com.factoreal.backend.repository.WorkerRepository;
import com.factoreal.backend.repository.WorkerZoneRepository;
import com.factoreal.backend.repository.ZoneRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
// 곡간 λ‹΄λ‹Ήμž μ§€μ • μ„œλΉ„μŠ€
public class WorkerManagerService {

private final WorkerRepository workerRepository;
private final WorkerZoneRepository workerZoneRepository;
private final ZoneRepository zoneRepository;

/**
* νŠΉμ • κ³΅κ°„μ˜ λ‹΄λ‹Ήμž 후보 λͺ©λ‘ 쑰회
* - 이미 λ‹΄λ‹Ήμžκ°€ μžˆλŠ” 경우: ν˜„μž¬ λ‹΄λ‹Ήμžλ₯Ό μ œμ™Έν•œ ν•΄λ‹Ή 곡간 μ ‘κ·Ό κΆŒν•œμ΄ μžˆλŠ” μž‘μ—…μž λͺ©λ‘
* - λ‹΄λ‹Ήμžκ°€ μ—†λŠ” 경우: ν•΄λ‹Ή 곡간 μ ‘κ·Ό κΆŒν•œμ΄ μžˆλŠ” μž‘μ—…μž λͺ©λ‘
* - λ‹€λ₯Έ κ³΅κ°„μ˜ λ‹΄λ‹ΉμžμΈ μž‘μ—…μžλŠ” 후보 λͺ©λ‘μ—μ„œ μ œμ™Έ
*/
@Transactional(readOnly = true)
public List<WorkerManagerResponse> getManagerCandidates(String zoneId) {
log.info("곡간 ID: {}의 λ‹΄λ‹Ήμž 후보 λͺ©λ‘ 쑰회", zoneId);

// 1. ν˜„μž¬ ν•΄λ‹Ή κ³΅κ°„μ˜ λ‹΄λ‹Ήμž 쑰회
Optional<WorkerZone> currentManager = workerZoneRepository.findByZoneZoneIdAndManageYnIsTrue(zoneId);

// 2. ν˜„μž¬ 곡간을 μ œμ™Έν•œ λ‹€λ₯Έ κ³΅κ°„μ˜ λ‹΄λ‹Ήμž λͺ©λ‘ 쑰회 (workerIdλ₯Ό Set으둜 λ¬Άμ–΄μ„œ 쀑볡 제거)
Set<String> otherManagerIds = workerZoneRepository.findByZoneZoneIdNotAndManageYnIsTrue(zoneId).stream()
.map(wz -> wz.getWorker().getWorkerId())
.collect(Collectors.toSet());

// 3. ν•΄λ‹Ή 곡간에 μ ‘κ·Ό κΆŒν•œμ΄ μžˆλŠ” μž‘μ—…μž λͺ©λ‘ 쑰회
List<WorkerZone> zoneWorkers = workerZoneRepository.findByZoneZoneId(zoneId);

// 4. ν˜„μž¬ λ‹΄λ‹Ήμžμ™€ λ‹€λ₯Έ κ³΅κ°„μ˜ λ‹΄λ‹Ήμžλ₯Ό μ œμ™Έν•œ 후보 λͺ©λ‘ 생성
List<Worker> candidates = currentManager
.map(manager -> zoneWorkers.stream()
.filter(wz -> !wz.getWorker().getWorkerId().equals(manager.getWorker().getWorkerId())) // ν˜„μž¬ λ‹΄λ‹Ήμžλ₯Ό μ œμ™Έ
.filter(wz -> !otherManagerIds.contains(wz.getWorker().getWorkerId())) // λ‹€λ₯Έ κ³΅κ°„μ˜ λ‹΄λ‹ΉμžμΈ μž‘μ—…μžλŠ” 후보 λͺ©λ‘μ—μ„œ μ œμ™Έ
.map(WorkerZone::getWorker) // 후보 λͺ©λ‘μ— ν¬ν•¨λœ μž‘μ—…μž 객체 생성
.collect(Collectors.toList()))
.orElse(zoneWorkers.stream() // λ‹΄λ‹Ήμžκ°€ μ—†λŠ” 경우, ν•΄λ‹Ή 곡간 μ ‘κ·Ό κΆŒν•œμ΄ μžˆλŠ” μž‘μ—…μž λͺ©λ‘
.filter(wz -> !otherManagerIds.contains(wz.getWorker().getWorkerId())) // λ‹€λ₯Έ κ³΅κ°„μ˜ λ‹΄λ‹ΉμžμΈ μž‘μ—…μžλŠ” 후보 λͺ©λ‘μ—μ„œ μ œμ™Έ
.map(WorkerZone::getWorker) // 후보 λͺ©λ‘μ— ν¬ν•¨λœ μž‘μ—…μž 객체 생성
.collect(Collectors.toList()));

// 4. DTO λ³€ν™˜ (후보 λͺ©λ‘μ˜ μž‘μ—…μžλ“€μ€ ν˜„μž¬ 이 κ³΅κ°„μ˜ λ‹΄λ‹Ήμžκ°€ μ•„λ‹ˆλ―€λ‘œ isManager = false)
return candidates.stream()
.map(worker -> WorkerManagerResponse.fromEntity(worker, false))
.collect(Collectors.toList());
}

/**
* νŠΉμ • κ³΅κ°„μ˜ λ‹΄λ‹Ήμž μ§€μ •
*/
@Transactional
public void assignManager(String zoneId, String workerId) {
log.info("곡간 ID: {}의 λ‹΄λ‹Ήμžλ₯Ό μž‘μ—…μž ID: {}둜 μ§€μ •", zoneId, workerId);

// 1. μž‘μ—…μž-곡간 관계 확인
WorkerZoneId workerZoneId = new WorkerZoneId(workerId, zoneId);
WorkerZone workerZone = workerZoneRepository.findById(workerZoneId)
.orElseThrow(() -> new IllegalArgumentException(
String.format("μž‘μ—…μž ID: %sλŠ” 곡간 ID: %s에 λŒ€ν•œ μ ‘κ·Ό κΆŒν•œμ΄ μ—†μŠ΅λ‹ˆλ‹€.", workerId, zoneId)));

// 2. κΈ°μ‘΄ λ‹΄λ‹Ήμžκ°€ μžˆλ‹€λ©΄ λ‹΄λ‹Ήμž ν•΄μ œ
Optional<WorkerZone> currentManager = workerZoneRepository.findByZoneZoneIdAndManageYnIsTrue(zoneId);
currentManager.ifPresent(manager -> {
manager.setManageYn(false);
workerZoneRepository.save(manager);
});

// 3. μƒˆλ‘œμš΄ λ‹΄λ‹Ήμž μ§€μ •
workerZone.setManageYn(true);
workerZoneRepository.save(workerZone);
}

/**
* νŠΉμ • κ³΅κ°„μ˜ ν˜„μž¬ λ‹΄λ‹Ήμž 쑰회
*/
@Transactional(readOnly = true)
public WorkerManagerResponse getCurrentManager(String zoneId) {
log.info("곡간 ID: {}의 ν˜„μž¬ λ‹΄λ‹Ήμž 쑰회", zoneId);

return workerZoneRepository.findByZoneZoneIdAndManageYnIsTrue(zoneId)
.map(workerZone -> WorkerManagerResponse.fromEntity(workerZone.getWorker(), true))
.orElse(null);
}
}
61 changes: 45 additions & 16 deletions src/main/java/com/factoreal/backend/service/WorkerService.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.factoreal.backend.service;

import com.factoreal.backend.dto.CreateWorkerRequest;
import com.factoreal.backend.dto.WorkerDto;
import com.factoreal.backend.dto.ZoneManagerResponseDto;
import com.factoreal.backend.entity.Worker;
import com.factoreal.backend.entity.WorkerZone;
import com.factoreal.backend.entity.WorkerZoneId;
import com.factoreal.backend.entity.Zone;
import com.factoreal.backend.entity.ZoneHist;
import com.factoreal.backend.repository.WorkerRepository;
import com.factoreal.backend.repository.WorkerZoneRepository;
import com.factoreal.backend.repository.ZoneRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -23,13 +26,18 @@ public class WorkerService {
private final WorkerRepository workerRepository;
private final WorkerLocationService workerLocationService;
private final WorkerZoneRepository workerZoneRepository;
private final ZoneRepository zoneRepository;

@Transactional(readOnly = true)
public List<WorkerDto> getAllWorkers() {
log.info("전체 μž‘μ—…μž λͺ©λ‘ 쑰회");
List<Worker> workers = workerRepository.findAll();
return workers.stream()
.map(worker -> WorkerDto.fromEntity(worker, false))
.map(worker -> {
// ν•΄λ‹Ή μž‘μ—…μžκ°€ μ–΄λ–€ κ³΅κ°„μ˜ λ‹΄λ‹ΉμžμΈμ§€ 확인
boolean isManager = workerZoneRepository.findByWorkerWorkerIdAndManageYnIsTrue(worker.getWorkerId()).isPresent();
return WorkerDto.fromEntity(worker, isManager);
})
.collect(Collectors.toList());
}

Expand Down Expand Up @@ -71,19 +79,40 @@ public ZoneManagerResponseDto getZoneManagerWithLocation(String zoneId) {
// 4. DTO λ³€ν™˜ 및 λ°˜ν™˜
return ZoneManagerResponseDto.fromEntity(manager, currentZone);
}
}

// TODO. μˆ˜μ •λ˜μ–΄μ•Ό ν•  둜직. ν˜„μž¬λŠ” WorkerZone ν…Œμ΄λΈ”μ—μ„œ 곡간id둜 필터링 λ˜λŠ” λͺ¨λ“  μž‘μ—…μžλ₯Ό λŒκ³ μ™”λŠ”λ°,
// 사싀 ν˜„μž¬ κ·Έ κ³΅κ°„μ—μ„œ μ‹€μ œλ‘œ μž‘μ—…ν•˜κ³  μžˆλŠ”, 즉 λ“€μ–΄
// public List<WorkerDto> getWorkersByZoneId(String zoneId) {
// log.info("곡간 ID: {}의 μž‘μ—…μž λͺ©λ‘ 쑰회", zoneId);
// List<WorkerZone> workerZones = workerZoneRepository.findByZoneZoneId(zoneId);

// return workerZones.stream()
// .map(workerZone -> {
// Worker worker = workerZone.getWorker();
// Boolean isManager = workerZone.getManageYn();
// return WorkerDto.fromEntity(worker, isManager);
// })
// .collect(Collectors.toList());
// }
/**
* μž‘μ—…μž 생성 및 μΆœμž… κ°€λŠ₯ 곡간 μ„€μ •
*/
@Transactional
public void createWorker(CreateWorkerRequest request) {
log.info("μž‘μ—…μž 생성 μš”μ²­: {}", request);

// 1. μž‘μ—…μž 정보 μ €μž₯
Worker worker = Worker.builder()
.workerId(request.getWorkerId())
.name(request.getName())
.phoneNumber(request.getPhoneNumber())
.email(request.getEmail())
.build();

workerRepository.save(worker); // μž‘μ—…μž 정보 μ €μž₯

// 2. 각 곡간λͺ…μœΌλ‘œ Zone 쑰회 및 WorkerZone 생성
for (String zoneName : request.getZoneNames()) {
Zone zone = zoneRepository.findByZoneName(zoneName)
.orElseThrow(() -> new IllegalArgumentException("μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 곡간λͺ…μž…λ‹ˆλ‹€: " + zoneName));

// WorkerZone 생성 (기본적으둜 κ΄€λ¦¬μž κΆŒν•œμ€ μ—†μŒ)
WorkerZone workerZone = WorkerZone.builder()
.id(new WorkerZoneId(worker.getWorkerId(), zone.getZoneId())) // 볡합킀 생성
.worker(worker)
.zone(zone)
.manageYn(false) // λ‹΄λ‹Ήμž κΆŒν•œμ€ μ—†μŒμ΄ default
.build();

workerZoneRepository.save(workerZone); // WorkerZone μ €μž₯
}

log.info("μž‘μ—…μž 생성 μ™„λ£Œ - workerId: {}", worker.getWorkerId());
}
}
Loading