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 @@ -6,8 +6,11 @@
import com.mobility.api.domain.office.dto.request.UpdateDispatchReq;
import com.mobility.api.domain.office.dto.response.GetAllDispatchRes;
import com.mobility.api.domain.office.service.OfficeService;
import com.mobility.api.domain.transporter.dto.request.TransporterCreateReq;
import com.mobility.api.domain.transporter.dto.response.TransporterRes;
import com.mobility.api.global.annotation.SwaggerPageable;
import com.mobility.api.global.response.CommonResponse;
import com.mobility.api.global.security.PrincipalDetails;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
Expand All @@ -17,8 +20,11 @@
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Tag(name = "사무실 관련 요청(/api/v1/office/...)")
@RestController
@RequiredArgsConstructor
Expand Down Expand Up @@ -108,4 +114,26 @@ public CommonResponse<String> getStatistics() {
return CommonResponse.success("프론트 개발 후 작업 예정입니다.");
}

@RequestMapping(path = "/transporter", method = RequestMethod.POST)
public CommonResponse<String> createTransporter(
@RequestBody TransporterCreateReq req,
@AuthenticationPrincipal PrincipalDetails user // 👈 토큰에서 사용자 정보 추출
) {

// userDetails.getUsername()에는 토큰에 넣었던 subject(loginId)가 들어있습니다.
officeService.createTransporter(req, user.getManager());

return CommonResponse.success("기사 등록 성공");
}

@RequestMapping(path = "/transporter", method = RequestMethod.GET)
public CommonResponse<List<TransporterRes>> getMyTransporters(
@AuthenticationPrincipal PrincipalDetails user
) {
// userDetails.getUsername() -> 로그인한 관리자의 ID
List<TransporterRes> result = officeService.getMyTransporters(user.getManager());

return CommonResponse.success(result);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
import com.mobility.api.domain.office.dto.request.DispatchSearchDto;
import com.mobility.api.domain.office.dto.request.UpdateDispatchReq;
import com.mobility.api.domain.office.dto.response.GetAllDispatchRes;
import com.mobility.api.domain.office.entity.Manager;
import com.mobility.api.domain.office.entity.Office;
import com.mobility.api.domain.transporter.dto.request.TransporterCreateReq;
import com.mobility.api.domain.transporter.dto.response.TransporterRes;
import com.mobility.api.domain.transporter.entity.Transporter;
import com.mobility.api.domain.transporter.repository.TransporterRepository;
import com.mobility.api.global.enums.ApiResponseCode;
import com.mobility.api.global.exception.BusinessException;
import com.mobility.api.global.exception.GlobalException;
Expand All @@ -30,6 +36,7 @@
public class OfficeService {

private final DispatchRepository dispatchRepository;
private final TransporterRepository transporterRepository;
private final AutoDispatchService autoDispatchService;

public Page<GetAllDispatchRes> findAllDispatch(DispatchSearchDto searchDto, Pageable pageable) {
Expand Down Expand Up @@ -117,4 +124,57 @@ public void cancelDispatch(Long dispatchId) { // <- 메서드 이름도 delete -
// @Transactional이 변경 감지(Dirty Checking)로 UPDATE
}

/**
* 기사 등록 (사장님이 호출)
* @param req 기사 정보
* @param manager 로그인한 직원 (토큰에서 추출)
*/
@Transactional
public void createTransporter(TransporterCreateReq req, Manager manager) {

// 1. 현재 로그인한 사장님 조회

// 2. 사장님의 소속 사무실 가져오기
Office office = manager.getOffice();

// 3. 기사 전화번호 중복 검사
if (transporterRepository.existsByPhone(req.phone())) {
throw new GlobalException(ResultCode.FIXME_FAIL); // 이미 등록된 기사
}

// 4. 기사 저장 (사무실 정보 자동 주입)
Transporter transporter = Transporter.builder()
.name(req.name())
.phone(req.phone())
.isAutoDispatch(req.isAutoDispatch())
.office(office) // 직원의 사무실을 자동으로 넣어줌
.build();

transporterRepository.save(transporter);
}

/**
* 내 사무실 기사 목록 조회
* @param manager 로그인한 직원
*/
@Transactional(readOnly = true) // 조회 전용이므로 readOnly 권장 (성능 향상)
public List<TransporterRes> getMyTransporters(Manager manager) {

// 1. 관리자(사장님) 찾기

// 2. 소속 사무실 확인
Office office = manager.getOffice();
if (office == null) {
throw new GlobalException(ResultCode.FIXME_FAIL);
}

// 3. 해당 사무실의 기사 리스트 조회
List<Transporter> transporters = transporterRepository.findAllByOffice(office);

// 4. Entity List -> DTO List 변환하여 반환
return transporters.stream()
.map(TransporterRes::from)
.toList();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.mobility.api.domain.transporter.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;

public record TransporterCreateReq(
@Schema(description = "기사 이름", example = "김기사")
String name,

@Schema(description = "기사 전화번호", example = "010-1234-1234")
String phone,

@Schema(description = "자동배차 여부", example = "false")
Boolean isAutoDispatch
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.mobility.api.domain.transporter.dto.response;

import com.mobility.api.domain.transporter.entity.Transporter;
import lombok.Builder;

import java.time.LocalDateTime;

@Builder
public record TransporterRes(
Long transporterId,
String name,
String phoneNumber,
Boolean isAutoDispatch,
LocalDateTime createdAt
) {
// Entity -> DTO 변환 메서드
public static TransporterRes from(Transporter transporter) {
return TransporterRes.builder()
.transporterId(transporter.getId())
.name(transporter.getName())
.phoneNumber(transporter.getPhone())
.isAutoDispatch(transporter.isAutoDispatch())
.createdAt(transporter.getCreatedAt())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mobility.api.domain.transporter.entity;

import com.mobility.api.domain.office.entity.Office;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
Expand Down Expand Up @@ -35,6 +36,10 @@ public class Transporter {
@Column(name = "is_auto_dispatch")
private boolean isAutoDispatch;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "office_id") // DB 컬럼명: office_id
private Office office;

@CreationTimestamp
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mobility.api.domain.transporter.repository;

import com.mobility.api.domain.office.entity.Office;
import com.mobility.api.domain.transporter.dto.TransporterDistanceProjection;
import com.mobility.api.domain.transporter.entity.Transporter;
import org.springframework.data.jpa.repository.JpaRepository;
Expand Down Expand Up @@ -64,4 +65,7 @@ List<TransporterDistanceProjection> findEligibleDriversForAutoDispatch(
// 로그인 시 기사 조회용 (기사 id는 전화번호이므로 username을 받아서 phone을 조회함)
Optional<Transporter> findByPhone(String username);

// 특정 사무실에 소속된 기사 목록 조회
List<Transporter> findAllByOffice(Office office);

}
Loading