MIS driver id, region 적용. audit 적용.

This commit is contained in:
Hyojin Ahn 2026-06-08 09:27:08 -04:00
parent 98865cb055
commit 2493f1ce66
12 changed files with 227 additions and 73 deletions

View File

@ -35,6 +35,9 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
String jwt = null; String jwt = null;
/**
* 1. Cookie 우선
*/
if (request.getCookies() != null) { if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) { for (Cookie cookie : request.getCookies()) {
@ -45,6 +48,21 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
} }
} }
/**
* 2. Cookie 없으면 Authorization Header fallback
*/
if (jwt == null || jwt.isBlank()) {
final String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
jwt = authHeader.substring(7);
}
}
/**
* 3. 없으면 통과
*/
if (jwt == null || jwt.isBlank()) { if (jwt == null || jwt.isBlank()) {
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
return; return;

View File

@ -14,7 +14,8 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import jakarta.servlet.DispatcherType;
@Configuration @Configuration
@EnableMethodSecurity // @PreAuthorize 사용 가능 @EnableMethodSecurity // @PreAuthorize 사용 가능
@ -26,14 +27,19 @@ public class SecurityConfig {
@Bean @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http http
.csrf(csrf -> csrf.disable()) // CSRF 비활성화 (API 서버라면 stateless) .csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 세션 사용 안함 .cors(cors -> cors.configurationSource(corsConfigurationSource()))
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(auth -> auth .authorizeHttpRequests(auth -> auth
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
) // 요청 권한 설정 )
.addFilterBefore(new CorsFilter(corsConfigurationSource()), UsernamePasswordAuthenticationFilter.class) // JWT 필터 전에 CorsFilter 등록 .addFilterBefore(jwtAuthFilter,
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); // JWT 필터 UsernamePasswordAuthenticationFilter.class);
return http.build(); return http.build();
} }

View File

@ -186,7 +186,8 @@ public class CustomerController {
@GetMapping("/no/{cusNo}/daily-orders/{orderDate}") @GetMapping("/no/{cusNo}/daily-orders/{orderDate}")
public ResponseEntity<CustomerDailyOrderResponseDto> getDailyOrderByCustomerNo( public ResponseEntity<CustomerDailyOrderResponseDto> getDailyOrderByCustomerNo(
@PathVariable String cusNo, @PathVariable String cusNo,
@PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate,
@PathVariable String jobType
) { ) {
PermissionAuthenticationToken auth = PermissionAuthenticationToken auth =
@ -202,7 +203,7 @@ public class CustomerController {
} }
return ResponseEntity.ok( return ResponseEntity.ok(
dailyOrderService.getDailyOrderByCustomerNo(cusNo, orderDate) dailyOrderService.getDailyOrderByCustomerNo(cusNo, orderDate, jobType)
); );
} }
} }

View File

@ -100,9 +100,10 @@ public class CustomerDailyOrderController {
// READ BY CUSTOMER + DATE // READ BY CUSTOMER + DATE
@GetMapping("/customer/{customerNo}/{orderDate}") @GetMapping("/customer/{customerNo}/{jobType}/{orderDate}")
public ResponseEntity<CustomerDailyOrderResponseDto> getDailyOrderByCustomerNo( public ResponseEntity<CustomerDailyOrderResponseDto> getDailyOrderByCustomerNo(
@PathVariable String customerNo, @PathVariable String customerNo,
@PathVariable String jobType,
@PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate
) )
{ {
@ -112,13 +113,14 @@ public class CustomerDailyOrderController {
throw new AccessDeniedException("You do not have permission to read daily order"); throw new AccessDeniedException("You do not have permission to read daily order");
} }
return ResponseEntity.ok(dailyOrderService.getDailyOrderByCustomerNo(customerNo, orderDate)); return ResponseEntity.ok(dailyOrderService.getDailyOrderByCustomerNo(customerNo, orderDate, jobType));
} }
// UPDATE BY CUSTOMER + DATE // UPDATE BY CUSTOMER + DATE
@PatchMapping("/customer/{customerNo}/{orderDate}") @PatchMapping("/customer/{customerNo}/{jobType}/{orderDate}")
public ResponseEntity<CustomerDailyOrderResponseDto> updateDailyOrderByCustomerNo( public ResponseEntity<CustomerDailyOrderResponseDto> updateDailyOrderByCustomerNo(
@PathVariable String customerNo, @PathVariable String customerNo,
@PathVariable String jobType,
@PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate, @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate,
@RequestBody CustomerDailyOrderRequestDto dto @RequestBody CustomerDailyOrderRequestDto dto
) { ) {
@ -129,7 +131,7 @@ public class CustomerDailyOrderController {
} }
return ResponseEntity.ok( return ResponseEntity.ok(
dailyOrderService.updateDailyOrderByCustomerNoAndOrderDate(customerNo, orderDate, dto) dailyOrderService.updateDailyOrderByCustomerNoAndOrderDate(customerNo, orderDate, jobType, dto)
); );
} }

View File

@ -18,6 +18,7 @@ public class CustomerDailyOrderRequestDto {
private String cdoRequestNote; // 주문 요청 메모 private String cdoRequestNote; // 주문 요청 메모
private String cdoExternalDriverId; // MIS 에서 driverId 호출해서 employee_external_map 참조해야함 private String cdoExternalDriverId; // MIS 에서 driverId 호출해서 employee_external_map 참조해야함
private String cdoExternalCreatedBy; // MIS 에서 memberId 호출해서 employee_external_map 참조해야함 private String cdoExternalCreatedBy; // MIS 에서 memberId 호출해서 employee_external_map 참조해야함
private String cdoExternalUpdatedBy; // MIS 에서 memberId 호출해서 employee_external_map 참조해야함
private Long cdoRegionId; // 배정 지역 private Long cdoRegionId; // 배정 지역
private Long cdoDriverId; // 배정된 driver id private Long cdoDriverId; // 배정된 driver id
private UUID cdoDriverUuid; // ERP 에서는 uuid 호출 private UUID cdoDriverUuid; // ERP 에서는 uuid 호출

View File

@ -3,8 +3,8 @@ package com.goi.erp.dto;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@ -28,16 +28,12 @@ public class CustomerRequestDto {
private LocalDate cusContractDate; // c_contractdate private LocalDate cusContractDate; // c_contractdate
private String cusContractedBy; // c_contractby private String cusContractedBy; // c_contractby
private LocalDate cusInstallDate; // c_installdate private LocalDate cusInstallDate; // c_installdate
private BigDecimal cusFullCycle; // c_fullcycle
private Boolean cusFullCycleFlag; // c_fullcycleflag
private BigDecimal cusFullCycleForced; // c_fullcycleforced
private LocalDate cusFullCycleForcedDate; // c_forceddate
private String cusSchedule; // c_schedule private String cusSchedule; // c_schedule
private String cusScheduledays; // c_scheduleday private String cusScheduledays; // c_scheduleday
private LocalDate cusLastPaidDate; // c_lastpaiddate private LocalDate cusLastPaidDate; // c_lastpaiddate
private Double cusRate; // c_rate private Double cusRate; // c_rate
private String cusPayMethod; // c_paymenttype private String cusPayMethod; // c_paymenttype
private String cusAccountNo; // c_accountno private String cusBankAccountNo; //
private LocalDate cusIsccDate; // c_form_eu private LocalDate cusIsccDate; // c_form_eu
private LocalDate cusCorsiaDate; // c_form_corsia private LocalDate cusCorsiaDate; // c_form_corsia
private String cusHstNo; // c_hstno private String cusHstNo; // c_hstno
@ -46,6 +42,7 @@ public class CustomerRequestDto {
private String cusInstallLocation; private String cusInstallLocation;
private LocalDate cusLastPickupDate; private LocalDate cusLastPickupDate;
private Integer cusLastPickupQty; private Integer cusLastPickupQty;
private Integer cusLastSludge;
private Double cusLastPickupLat; private Double cusLastPickupLat;
private Double cusLastPickupLon; private Double cusLastPickupLon;
private String cusOpenTime; private String cusOpenTime;
@ -53,5 +50,10 @@ public class CustomerRequestDto {
private String cusContactComment; // c_comment_ci private String cusContactComment; // c_comment_ci
private Integer cusLastPickupMin; private Integer cusLastPickupMin;
private String cusLoginUser; private String cusLoginUser;
private String cusExternalCreatedBy;
private String cusExternalUpdatedBy;
private String cusSourceType;
private LocalDateTime cusCreatedAt;
private LocalDateTime cusUpdatedAt;
} }

View File

@ -7,6 +7,7 @@ import lombok.NoArgsConstructor;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
@Data @Data
@ -34,18 +35,15 @@ public class CustomerResponseDto {
private String cusInstallLocation; private String cusInstallLocation;
private LocalDate cusLastPickupDate; private LocalDate cusLastPickupDate;
private Integer cusLastPickupQty; private Integer cusLastPickupQty;
private Integer cusLastSludge;
private BigDecimal cusLastPickupLat; private BigDecimal cusLastPickupLat;
private BigDecimal cusLastPickupLon; private BigDecimal cusLastPickupLon;
private BigDecimal cusFullCycle;
private Boolean cusFullCycleFlag;
private BigDecimal cusFullCycleForced;
private LocalDate cusFullCycleForcedDate;
private String cusSchedule; private String cusSchedule;
private String cusScheduledays; private String cusScheduledays;
private LocalDate cusLastPaidDate; private LocalDate cusLastPaidDate;
private BigDecimal cusRate; private BigDecimal cusRate;
private String cusPayMethod; private String cusPayMethod;
private String cusAccountNo; private String cusBankAccountNo;
private LocalDate cusIsccDate; private LocalDate cusIsccDate;
private LocalDate cusCorsiaDate; private LocalDate cusCorsiaDate;
private String cusHstNo; private String cusHstNo;
@ -55,4 +53,6 @@ public class CustomerResponseDto {
private String cusOpenTime; private String cusOpenTime;
private String cusComment; private String cusComment;
private String cusContactComment; private String cusContactComment;
private LocalDateTime cusCreatedAt;
private LocalDateTime cusUpdatedAt;
} }

View File

@ -15,10 +15,9 @@ import lombok.NoArgsConstructor;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.jpa.domain.support.AuditingEntityListener; import org.springframework.data.jpa.domain.support.AuditingEntityListener;
@Entity @Entity
@ -67,28 +66,23 @@ public class Customer {
private String cusInstallLocation; private String cusInstallLocation;
private LocalDate cusLastPickupDate; private LocalDate cusLastPickupDate;
private Integer cusLastPickupQty; private Integer cusLastPickupQty;
private Integer cusLastSludge;
private BigDecimal cusLastPickupLat; private BigDecimal cusLastPickupLat;
private BigDecimal cusLastPickupLon; private BigDecimal cusLastPickupLon;
private BigDecimal cusFullCycle;
private Boolean cusFullCycleFlag;
private BigDecimal cusFullCycleForced;
private LocalDate cusFullCycleForcedDate;
private String cusSchedule; private String cusSchedule;
private String cusScheduledays; private String cusScheduledays;
private LocalDate cusLastPaidDate; private LocalDate cusLastPaidDate;
private BigDecimal cusRate; private BigDecimal cusRate;
private String cusPayMethod; private String cusPayMethod;
private String cusAccountNo; private String cusBankAccountNo;
private LocalDate cusIsccDate; private LocalDate cusIsccDate;
private LocalDate cusCorsiaDate; private LocalDate cusCorsiaDate;
private String cusHstNo; private String cusHstNo;
private LocalDate cusTerminatedDate; private LocalDate cusTerminatedDate;
private String cusTerminationReason; private String cusTerminationReason;
private Integer cusLastPickupMin; private Integer cusLastPickupMin;
@CreatedBy
private String cusCreatedBy; private String cusCreatedBy;
@LastModifiedBy
private String cusUpdatedBy; private String cusUpdatedBy;
private LocalDateTime cusCreatedAt;
private LocalDateTime cusUpdatedAt;
} }

View File

@ -11,8 +11,6 @@ import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.jpa.domain.support.AuditingEntityListener; import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import jakarta.persistence.Column; import jakarta.persistence.Column;
@ -63,13 +61,11 @@ public class CustomerDailyOrder {
private LocalDateTime cdoCreatedAt; private LocalDateTime cdoCreatedAt;
@CreatedBy
@Column(name = "cdo_created_by") @Column(name = "cdo_created_by")
private String cdoCreatedBy; private String cdoCreatedBy;
private LocalDateTime cdoUpdatedAt; private LocalDateTime cdoUpdatedAt;
@LastModifiedBy
@Column(name = "cdo_updated_by") @Column(name = "cdo_updated_by")
private String cdoUpdatedBy; private String cdoUpdatedBy;

View File

@ -22,7 +22,7 @@ public interface CustomerDailyOrderRepository extends JpaRepository<CustomerDail
Optional<CustomerDailyOrder> findByCdoUuid(UUID cdoUuid); Optional<CustomerDailyOrder> findByCdoUuid(UUID cdoUuid);
// 특정 고객의 특정 날짜 주문 조회 // 특정 고객의 특정 날짜 주문 조회
Optional<CustomerDailyOrder> findByCdoCustomerNoAndCdoOrderDate(String cdoCustomerNo, LocalDate cdoOrderDate); Optional<CustomerDailyOrder> findByCdoCustomerNoAndCdoOrderDateAndCdoJobType(String cdoCustomerNo, LocalDate cdoOrderDate, String jobType);
// 특정 고객의 모든 주문 리스트 // 특정 고객의 모든 주문 리스트
List<CustomerDailyOrder> findByCdoCustomerNo(String cdoCustomerNo); List<CustomerDailyOrder> findByCdoCustomerNo(String cdoCustomerNo);

View File

@ -31,7 +31,6 @@ public class CustomerDailyOrderService {
* CREATE * CREATE
*/ */
public CustomerDailyOrderResponseDto createDailyOrder(CustomerDailyOrderRequestDto dto) { public CustomerDailyOrderResponseDto createDailyOrder(CustomerDailyOrderRequestDto dto) {
// customer id // customer id
Long customerId = resolveCustomerId(dto); Long customerId = resolveCustomerId(dto);
@ -41,6 +40,26 @@ public class CustomerDailyOrderService {
// created by (employee no) // created by (employee no)
String createdBy = resolveCreatedBy(dto); String createdBy = resolveCreatedBy(dto);
// created by (employee no)
String updatedBy = resolveUpdatedBy(dto);
// UPSERT CHECK
CustomerDailyOrder existing = findByBusinessKey(
dto.getCdoCustomerNo(),
dto.getCdoOrderDate(),
dto.getCdoJobType()
);
// UPDATE
if (existing != null) {
updateInternal(existing, dto);
existing.setCdoUpdatedAt(LocalDateTime.now());
existing.setCdoUpdatedBy(updatedBy);
existing = dailyOrderRepository.save(existing);
return mapToDto(existing);
}
// CREATE
CustomerDailyOrder order = CustomerDailyOrder.builder() CustomerDailyOrder order = CustomerDailyOrder.builder()
.cdoUuid(UUID.randomUUID()) .cdoUuid(UUID.randomUUID())
.cdoOrderDate(dto.getCdoOrderDate()) .cdoOrderDate(dto.getCdoOrderDate())
@ -99,9 +118,9 @@ public class CustomerDailyOrderService {
/** /**
* GET BY CUSTOMER + DATE * GET BY CUSTOMER + DATE
*/ */
public CustomerDailyOrderResponseDto getDailyOrderByCustomerNo(String cusNo, LocalDate orderDate) { public CustomerDailyOrderResponseDto getDailyOrderByCustomerNo(String cusNo, LocalDate orderDate, String jobType) {
CustomerDailyOrder order = dailyOrderRepository CustomerDailyOrder order = dailyOrderRepository
.findByCdoCustomerNoAndCdoOrderDate(cusNo, orderDate) .findByCdoCustomerNoAndCdoOrderDateAndCdoJobType(cusNo, orderDate, jobType)
.orElseThrow(() -> new RuntimeException("Order not found")); .orElseThrow(() -> new RuntimeException("Order not found"));
return mapToDto(order); return mapToDto(order);
} }
@ -113,12 +132,13 @@ public class CustomerDailyOrderService {
public CustomerDailyOrderResponseDto updateDailyOrderByCustomerNoAndOrderDate( public CustomerDailyOrderResponseDto updateDailyOrderByCustomerNoAndOrderDate(
String customerNo, String customerNo,
LocalDate orderDate, LocalDate orderDate,
String jobType,
CustomerDailyOrderRequestDto dto CustomerDailyOrderRequestDto dto
) { ) {
// daily order 조회 // daily order 조회
CustomerDailyOrder existing = dailyOrderRepository CustomerDailyOrder existing = dailyOrderRepository
.findByCdoCustomerNoAndCdoOrderDate(customerNo, orderDate) .findByCdoCustomerNoAndCdoOrderDateAndCdoJobType(customerNo, orderDate, jobType)
.orElseThrow(() -> new RuntimeException("Daily Order not found")); .orElseThrow(() -> new RuntimeException("Daily Order not found"));
// 기존 updateInternal 공통 업데이트 처리 // 기존 updateInternal 공통 업데이트 처리
@ -337,4 +357,57 @@ public class CustomerDailyOrderService {
return null; return null;
} }
private String resolveUpdatedBy(CustomerDailyOrderRequestDto dto) {
// 1. driver id
if (dto.getCdoLoginUser() != null) {
return dto.getCdoLoginUser();
}
// 2. MIS -> externalId (id to empNo)
if (dto.getCdoExternalUpdatedBy() != null) {
Map<String, Object> body = hcmEmployeeClient.getEmpFromExternalId( "MIS_MEMBER", dto.getCdoExternalUpdatedBy() );
if (body != null && body.get("eexEmpNo") != null) {
Object raw = body.get("eexEmpNo");
if (raw instanceof String) {
return ((String) raw);
}
// 예상 타입일 경우
}
}
// 3. ERP 내부 요청 (driverUuid 방식)
if (dto.getCdoDriverUuid() != null) {
Map<String, Object> body = hcmEmployeeClient.getEmpFromUuid(dto.getCdoDriverUuid());
if (body != null && body.get("empNo") != null) {
Object raw = body.get("empNo");
if (raw instanceof String) {
return ((String) raw);
}
// 예상 타입일 경우
}
}
return null;
}
private CustomerDailyOrder findByBusinessKey(
String customerNo,
LocalDate orderDate,
String jobType
) {
return dailyOrderRepository
.findByCdoCustomerNoAndCdoOrderDateAndCdoJobType(
customerNo,
orderDate,
jobType
)
.orElse(null);
}
} }

View File

@ -29,8 +29,18 @@ public class CustomerService {
private final CustomerRepository customerRepository; private final CustomerRepository customerRepository;
private final EntityChangeLogRepository entityChangeLogRepository; private final EntityChangeLogRepository entityChangeLogRepository;
private final HcmEmployeeClient hcmEmployeeClient;
public CustomerResponseDto createCustomer(CustomerRequestDto dto) { public CustomerResponseDto createCustomer(CustomerRequestDto dto) {
//
String contractedBy = dto.getCusContractedBy();
if ("MIS".equalsIgnoreCase(dto.getCusSourceType())) {
contractedBy = resolveEmpNo(null, dto.getCusContractedBy());
}
String createdBy = resolveEmpNo(dto.getCusLoginUser(),dto.getCusExternalCreatedBy());
//
Customer customer = Customer.builder() Customer customer = Customer.builder()
.cusUuid(UUID.randomUUID()) .cusUuid(UUID.randomUUID())
.cusNo(dto.getCusNo()) .cusNo(dto.getCusNo())
@ -49,18 +59,15 @@ public class CustomerService {
.cusPhone(dto.getCusPhone()) .cusPhone(dto.getCusPhone())
.cusPhoneExt(dto.getCusPhoneExt()) .cusPhoneExt(dto.getCusPhoneExt())
.cusContractDate(dto.getCusContractDate()) .cusContractDate(dto.getCusContractDate())
.cusContractedBy(dto.getCusContractedBy()) // .cusContractedBy(dto.getCusContractedBy())
.cusContractedBy(contractedBy)
.cusInstallDate(dto.getCusInstallDate()) .cusInstallDate(dto.getCusInstallDate())
.cusFullCycle(dto.getCusFullCycle())
.cusFullCycleFlag(dto.getCusFullCycleFlag())
.cusFullCycleForced(dto.getCusFullCycleForced())
.cusFullCycleForcedDate(dto.getCusFullCycleForcedDate())
.cusSchedule(dto.getCusSchedule()) .cusSchedule(dto.getCusSchedule())
.cusScheduledays(dto.getCusScheduledays()) .cusScheduledays(dto.getCusScheduledays())
.cusLastPaidDate(dto.getCusLastPaidDate()) .cusLastPaidDate(dto.getCusLastPaidDate())
.cusRate(dto.getCusRate() != null ? BigDecimal.valueOf(dto.getCusRate()) : null) .cusRate(dto.getCusRate() != null ? BigDecimal.valueOf(dto.getCusRate()) : null)
.cusPayMethod(dto.getCusPayMethod()) .cusPayMethod(dto.getCusPayMethod())
.cusAccountNo(dto.getCusAccountNo()) .cusBankAccountNo(dto.getCusBankAccountNo())
.cusIsccDate(dto.getCusIsccDate()) .cusIsccDate(dto.getCusIsccDate())
.cusCorsiaDate(dto.getCusCorsiaDate()) .cusCorsiaDate(dto.getCusCorsiaDate())
.cusHstNo(dto.getCusHstNo()) .cusHstNo(dto.getCusHstNo())
@ -68,6 +75,9 @@ public class CustomerService {
.cusComment(dto.getCusComment()) .cusComment(dto.getCusComment())
.cusContactComment(dto.getCusContactComment()) .cusContactComment(dto.getCusContactComment())
.cusInstallLocation(dto.getCusInstallLocation()) .cusInstallLocation(dto.getCusInstallLocation())
.cusCreatedBy(createdBy)
.cusCreatedAt(LocalDateTime.now())
.cusUpdatedAt(LocalDateTime.now())
.build(); .build();
customer = customerRepository.save(customer); customer = customerRepository.save(customer);
@ -116,12 +126,8 @@ public class CustomerService {
if (dto.getCusPhone() != null) customer.setCusPhone(dto.getCusPhone()); if (dto.getCusPhone() != null) customer.setCusPhone(dto.getCusPhone());
if (dto.getCusPhoneExt() != null) customer.setCusPhoneExt(dto.getCusPhoneExt()); if (dto.getCusPhoneExt() != null) customer.setCusPhoneExt(dto.getCusPhoneExt());
if (dto.getCusContractDate() != null) customer.setCusContractDate(dto.getCusContractDate()); if (dto.getCusContractDate() != null) customer.setCusContractDate(dto.getCusContractDate());
if (dto.getCusContractedBy() != null) customer.setCusContractedBy(dto.getCusContractedBy()); // if (dto.getCusContractedBy() != null) customer.setCusContractedBy(dto.getCusContractedBy());
if (dto.getCusInstallDate() != null) customer.setCusInstallDate(dto.getCusInstallDate()); if (dto.getCusInstallDate() != null) customer.setCusInstallDate(dto.getCusInstallDate());
if (dto.getCusFullCycle() != null) customer.setCusFullCycle(dto.getCusFullCycle());
if (dto.getCusFullCycleFlag() != null) customer.setCusFullCycleFlag(dto.getCusFullCycleFlag());
if (dto.getCusFullCycleForced() != null) customer.setCusFullCycleForced(dto.getCusFullCycleForced());
if (dto.getCusFullCycleForcedDate() != null) customer.setCusFullCycleForcedDate(dto.getCusFullCycleForcedDate());
if (dto.getCusSchedule() != null) customer.setCusSchedule(dto.getCusSchedule()); if (dto.getCusSchedule() != null) customer.setCusSchedule(dto.getCusSchedule());
if (dto.getCusScheduledays() != null) customer.setCusScheduledays(dto.getCusScheduledays()); if (dto.getCusScheduledays() != null) customer.setCusScheduledays(dto.getCusScheduledays());
if (dto.getCusLastPaidDate() != null) customer.setCusLastPaidDate(dto.getCusLastPaidDate()); if (dto.getCusLastPaidDate() != null) customer.setCusLastPaidDate(dto.getCusLastPaidDate());
@ -134,12 +140,31 @@ public class CustomerService {
if (dto.getCusTerminationReason() != null) customer.setCusTerminationReason(dto.getCusTerminationReason()); if (dto.getCusTerminationReason() != null) customer.setCusTerminationReason(dto.getCusTerminationReason());
if (dto.getCusLastPickupDate() != null) customer.setCusLastPickupDate(dto.getCusLastPickupDate()); if (dto.getCusLastPickupDate() != null) customer.setCusLastPickupDate(dto.getCusLastPickupDate());
if (dto.getCusLastPickupQty() != null) customer.setCusLastPickupQty(dto.getCusLastPickupQty()); if (dto.getCusLastPickupQty() != null) customer.setCusLastPickupQty(dto.getCusLastPickupQty());
if (dto.getCusLastSludge() != null) customer.setCusLastSludge(dto.getCusLastSludge());
if (dto.getCusLastPickupLat() != null) customer.setCusLastPickupLat(BigDecimal.valueOf(dto.getCusLastPickupLat())); if (dto.getCusLastPickupLat() != null) customer.setCusLastPickupLat(BigDecimal.valueOf(dto.getCusLastPickupLat()));
if (dto.getCusLastPickupLon() != null) customer.setCusLastPickupLon(BigDecimal.valueOf(dto.getCusLastPickupLon())); if (dto.getCusLastPickupLon() != null) customer.setCusLastPickupLon(BigDecimal.valueOf(dto.getCusLastPickupLon()));
if (dto.getCusOpenTime() != null) customer.setCusOpenTime(dto.getCusOpenTime()); if (dto.getCusOpenTime() != null) customer.setCusOpenTime(dto.getCusOpenTime());
if (dto.getCusComment() != null) customer.setCusComment(dto.getCusComment()); if (dto.getCusComment() != null) customer.setCusComment(dto.getCusComment());
if (dto.getCusContactComment() != null) customer.setCusContactComment(dto.getCusContactComment()); if (dto.getCusContactComment() != null) customer.setCusContactComment(dto.getCusContactComment());
if (dto.getCusInstallLocation() != null) customer.setCusInstallLocation(dto.getCusInstallLocation()); if (dto.getCusInstallLocation() != null) customer.setCusInstallLocation(dto.getCusInstallLocation());
// 보내는 무시
customer.setCusUpdatedAt(LocalDateTime.now());
// external
if (dto.getCusContractedBy() != null) {
String contractedBy = dto.getCusContractedBy();
if ("MIS".equalsIgnoreCase(dto.getCusSourceType())) {
contractedBy = resolveEmpNo(null, dto.getCusContractedBy());
}
customer.setCusContractedBy(contractedBy);
}
if (dto.getCusExternalUpdatedBy() != null) {
String updatedBy = dto.getCusExternalUpdatedBy();
if ("MIS".equalsIgnoreCase(dto.getCusSourceType())) {
updatedBy = resolveEmpNo(null, dto.getCusExternalUpdatedBy());
}
customer.setCusUpdatedBy(updatedBy);
}
customerRepository.save(customer); customerRepository.save(customer);
return mapToDto(customer); return mapToDto(customer);
@ -169,18 +194,15 @@ public class CustomerService {
dto.setCusInstallLocation(customer.getCusInstallLocation()); dto.setCusInstallLocation(customer.getCusInstallLocation());
dto.setCusLastPickupDate(customer.getCusLastPickupDate()); dto.setCusLastPickupDate(customer.getCusLastPickupDate());
dto.setCusLastPickupQty(customer.getCusLastPickupQty()); dto.setCusLastPickupQty(customer.getCusLastPickupQty());
dto.setCusLastSludge(customer.getCusLastSludge());
dto.setCusLastPickupLat(customer.getCusLastPickupLat()); dto.setCusLastPickupLat(customer.getCusLastPickupLat());
dto.setCusLastPickupLon(customer.getCusLastPickupLon()); dto.setCusLastPickupLon(customer.getCusLastPickupLon());
dto.setCusFullCycle(customer.getCusFullCycle());
dto.setCusFullCycleFlag(customer.getCusFullCycleFlag());
dto.setCusFullCycleForced(customer.getCusFullCycleForced());
dto.setCusFullCycleForcedDate(customer.getCusFullCycleForcedDate());
dto.setCusSchedule(customer.getCusSchedule()); dto.setCusSchedule(customer.getCusSchedule());
dto.setCusScheduledays(customer.getCusScheduledays()); dto.setCusScheduledays(customer.getCusScheduledays());
dto.setCusLastPaidDate(customer.getCusLastPaidDate()); dto.setCusLastPaidDate(customer.getCusLastPaidDate());
dto.setCusRate(customer.getCusRate()); dto.setCusRate(customer.getCusRate());
dto.setCusPayMethod(customer.getCusPayMethod()); dto.setCusPayMethod(customer.getCusPayMethod());
dto.setCusAccountNo(customer.getCusAccountNo()); dto.setCusBankAccountNo(customer.getCusBankAccountNo());
dto.setCusIsccDate(customer.getCusIsccDate()); dto.setCusIsccDate(customer.getCusIsccDate());
dto.setCusCorsiaDate(customer.getCusCorsiaDate()); dto.setCusCorsiaDate(customer.getCusCorsiaDate());
dto.setCusHstNo(customer.getCusHstNo()); dto.setCusHstNo(customer.getCusHstNo());
@ -191,6 +213,8 @@ public class CustomerService {
dto.setCusComment(customer.getCusComment()); dto.setCusComment(customer.getCusComment());
dto.setCusContactComment(customer.getCusContactComment()); dto.setCusContactComment(customer.getCusContactComment());
dto.setCusInstallLocation(customer.getCusInstallLocation()); dto.setCusInstallLocation(customer.getCusInstallLocation());
dto.setCusCreatedAt(customer.getCusCreatedAt());
dto.setCusUpdatedAt(customer.getCusUpdatedAt());
return dto; return dto;
} }
@ -224,18 +248,51 @@ public class CustomerService {
CustomerResponseDto response = updateCustomerInternal(oldCustomer, newCustomer); CustomerResponseDto response = updateCustomerInternal(oldCustomer, newCustomer);
// 4. 변경 비교 (old vs new) // 4. 변경 비교 (old vs new)
String misLoginUser = newCustomer.getCusLoginUser(); String updatedBy = resolveEmpNo(
compareAndLogChanges(beforeUpdate, oldCustomer, misLoginUser); newCustomer.getCusLoginUser(),
newCustomer.getCusExternalUpdatedBy()
);
compareAndLogChanges(beforeUpdate, oldCustomer, updatedBy);
return response; return response;
} }
private String resolveEmpNo(
String loginUser,
String externalId
) {
// 1. login user 우선
if (loginUser != null && !loginUser.isBlank()) {
return loginUser;
}
// 2. MIS external mapping
if (externalId != null && !externalId.isBlank()) {
Map<String, Object> body =
hcmEmployeeClient.getEmpFromExternalId(
"MIS_MEMBER",
externalId
);
if (body != null && body.get("eexEmpNo") != null) {
Object raw = body.get("eexEmpNo");
if (raw instanceof String str) {
return str;
}
}
}
return null;
}
// set change log // set change log
private void compareAndLogChanges(Customer oldData, Customer newData, String changedBy) { private void compareAndLogChanges(Customer oldData, Customer newData, String changedBy) {
// 필드 DB 컬럼 매핑 // 필드 DB 컬럼 매핑
Map<String, String> fieldToColumn = Map.ofEntries( Map<String, String> fieldToColumn = Map.ofEntries(
Map.entry("cusRegionId", "cus_region_id"),
Map.entry("cusName", "cus_name"), Map.entry("cusName", "cus_name"),
Map.entry("cusEmail", "cus_email"), Map.entry("cusEmail", "cus_email"),
Map.entry("cusPhone", "cus_phone"), Map.entry("cusPhone", "cus_phone"),
@ -251,16 +308,20 @@ public class CustomerService {
Map.entry("cusContractDate", "cus_contract_date"), Map.entry("cusContractDate", "cus_contract_date"),
Map.entry("cusContractedBy", "cus_contracted_by"), Map.entry("cusContractedBy", "cus_contracted_by"),
Map.entry("cusInstallDate", "cus_install_date"), Map.entry("cusInstallDate", "cus_install_date"),
Map.entry("cusFullCycle", "cus_full_cycle"), Map.entry("cusTerminatedDate", "cus_terminated_date"),
Map.entry("cusFullCycleFlag", "cus_full_cycle_flag"), Map.entry("cusTerminationReason", "cus_termination_reason"),
Map.entry("cusFullCycleForced", "cus_full_cycle_forced"),
Map.entry("cusFullCycleForcedDate", "cus_full_cycle_forced_date"),
Map.entry("cusSchedule", "cus_schedule"), Map.entry("cusSchedule", "cus_schedule"),
Map.entry("cusScheduledays", "cus_scheduledays"), Map.entry("cusScheduledays", "cus_scheduledays"),
Map.entry("cusLastPaidDate", "cus_last_paid_date"), Map.entry("cusLastPaidDate", "cus_last_paid_date"),
Map.entry("cusLastPickupDate", "cus_last_pickup_date"),
Map.entry("cusLastPickupQty", "cus_last_pickup_qty"),
Map.entry("cusLastSludge", "cus_last_sludge"),
Map.entry("cusLastPickupLat", "cus_last_pickup_lat"),
Map.entry("cusLastPickupLon", "cus_last_pickup_lon"),
Map.entry("cusLastPickupMin", "cus_last_pickup_min"),
Map.entry("cusRate", "cus_rate"), Map.entry("cusRate", "cus_rate"),
Map.entry("cusPayMethod", "cus_pay_method"), Map.entry("cusPayMethod", "cus_pay_method"),
Map.entry("cusAccountNo", "cus_account_no"), Map.entry("cusBankAccountNo", "cus_bank_account_no"),
Map.entry("cusIsccDate", "cus_iscc_date"), Map.entry("cusIsccDate", "cus_iscc_date"),
Map.entry("cusCorsiaDate", "cus_corsia_date"), Map.entry("cusCorsiaDate", "cus_corsia_date"),
Map.entry("cusHstNo", "cus_hst_no"), Map.entry("cusHstNo", "cus_hst_no"),