From 2493f1ce662a2cf63f6c0feb727a1c2239118138 Mon Sep 17 00:00:00 2001 From: Hyojin Ahn Date: Mon, 8 Jun 2026 09:27:08 -0400 Subject: [PATCH] =?UTF-8?q?MIS=20driver=20id,=20region=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9.=20audit=20=EC=A0=81=EC=9A=A9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../erp/config/JwtAuthenticationFilter.java | 18 +++ .../com/goi/erp/config/SecurityConfig.java | 24 ++-- .../erp/controller/CustomerController.java | 5 +- .../CustomerDailyOrderController.java | 10 +- .../erp/dto/CustomerDailyOrderRequestDto.java | 1 + .../com/goi/erp/dto/CustomerRequestDto.java | 14 ++- .../com/goi/erp/dto/CustomerResponseDto.java | 10 +- .../java/com/goi/erp/entity/Customer.java | 16 +-- .../goi/erp/entity/CustomerDailyOrder.java | 4 - .../CustomerDailyOrderRepository.java | 2 +- .../service/CustomerDailyOrderService.java | 83 ++++++++++++- .../com/goi/erp/service/CustomerService.java | 113 ++++++++++++++---- 12 files changed, 227 insertions(+), 73 deletions(-) diff --git a/src/main/java/com/goi/erp/config/JwtAuthenticationFilter.java b/src/main/java/com/goi/erp/config/JwtAuthenticationFilter.java index 1d12892..cd77e6d 100644 --- a/src/main/java/com/goi/erp/config/JwtAuthenticationFilter.java +++ b/src/main/java/com/goi/erp/config/JwtAuthenticationFilter.java @@ -35,6 +35,9 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { String jwt = null; + /** + * 1. Cookie 우선 + */ if (request.getCookies() != null) { 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()) { filterChain.doFilter(request, response); return; diff --git a/src/main/java/com/goi/erp/config/SecurityConfig.java b/src/main/java/com/goi/erp/config/SecurityConfig.java index 3dfe4ad..c670255 100644 --- a/src/main/java/com/goi/erp/config/SecurityConfig.java +++ b/src/main/java/com/goi/erp/config/SecurityConfig.java @@ -14,7 +14,8 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; + +import jakarta.servlet.DispatcherType; @Configuration @EnableMethodSecurity // @PreAuthorize 등 사용 가능 @@ -26,14 +27,19 @@ public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http - .csrf(csrf -> csrf.disable()) // CSRF 비활성화 (API 서버라면 stateless) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 세션 사용 안함 - .authorizeHttpRequests(auth -> auth - .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() - .anyRequest().authenticated() - ) // 요청 권한 설정 - .addFilterBefore(new CorsFilter(corsConfigurationSource()), UsernamePasswordAuthenticationFilter.class) // JWT 필터 전에 CorsFilter 등록 - .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); // JWT 필터 + .csrf(csrf -> csrf.disable()) + .cors(cors -> cors.configurationSource(corsConfigurationSource())) + .sessionManagement(session -> + session.sessionCreationPolicy(SessionCreationPolicy.STATELESS) + ) + .authorizeHttpRequests(auth -> auth + .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll() + .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll() + .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() + .anyRequest().authenticated() + ) + .addFilterBefore(jwtAuthFilter, + UsernamePasswordAuthenticationFilter.class); return http.build(); } diff --git a/src/main/java/com/goi/erp/controller/CustomerController.java b/src/main/java/com/goi/erp/controller/CustomerController.java index 03167fd..694aeda 100644 --- a/src/main/java/com/goi/erp/controller/CustomerController.java +++ b/src/main/java/com/goi/erp/controller/CustomerController.java @@ -186,7 +186,8 @@ public class CustomerController { @GetMapping("/no/{cusNo}/daily-orders/{orderDate}") public ResponseEntity getDailyOrderByCustomerNo( @PathVariable String cusNo, - @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate + @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate, + @PathVariable String jobType ) { PermissionAuthenticationToken auth = @@ -202,7 +203,7 @@ public class CustomerController { } return ResponseEntity.ok( - dailyOrderService.getDailyOrderByCustomerNo(cusNo, orderDate) + dailyOrderService.getDailyOrderByCustomerNo(cusNo, orderDate, jobType) ); } } diff --git a/src/main/java/com/goi/erp/controller/CustomerDailyOrderController.java b/src/main/java/com/goi/erp/controller/CustomerDailyOrderController.java index 6c9e640..f5ce95c 100644 --- a/src/main/java/com/goi/erp/controller/CustomerDailyOrderController.java +++ b/src/main/java/com/goi/erp/controller/CustomerDailyOrderController.java @@ -100,9 +100,10 @@ public class CustomerDailyOrderController { // READ BY CUSTOMER + DATE - @GetMapping("/customer/{customerNo}/{orderDate}") + @GetMapping("/customer/{customerNo}/{jobType}/{orderDate}") public ResponseEntity getDailyOrderByCustomerNo( @PathVariable String customerNo, + @PathVariable String jobType, @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"); } - return ResponseEntity.ok(dailyOrderService.getDailyOrderByCustomerNo(customerNo, orderDate)); + return ResponseEntity.ok(dailyOrderService.getDailyOrderByCustomerNo(customerNo, orderDate, jobType)); } // UPDATE BY CUSTOMER + DATE - @PatchMapping("/customer/{customerNo}/{orderDate}") + @PatchMapping("/customer/{customerNo}/{jobType}/{orderDate}") public ResponseEntity updateDailyOrderByCustomerNo( @PathVariable String customerNo, + @PathVariable String jobType, @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate, @RequestBody CustomerDailyOrderRequestDto dto ) { @@ -129,7 +131,7 @@ public class CustomerDailyOrderController { } return ResponseEntity.ok( - dailyOrderService.updateDailyOrderByCustomerNoAndOrderDate(customerNo, orderDate, dto) + dailyOrderService.updateDailyOrderByCustomerNoAndOrderDate(customerNo, orderDate, jobType, dto) ); } diff --git a/src/main/java/com/goi/erp/dto/CustomerDailyOrderRequestDto.java b/src/main/java/com/goi/erp/dto/CustomerDailyOrderRequestDto.java index 3845949..12655b7 100644 --- a/src/main/java/com/goi/erp/dto/CustomerDailyOrderRequestDto.java +++ b/src/main/java/com/goi/erp/dto/CustomerDailyOrderRequestDto.java @@ -18,6 +18,7 @@ public class CustomerDailyOrderRequestDto { private String cdoRequestNote; // 주문 요청 메모 private String cdoExternalDriverId; // MIS 에서 driverId 로 호출해서 employee_external_map 참조해야함 private String cdoExternalCreatedBy; // MIS 에서 memberId 로 호출해서 employee_external_map 참조해야함 + private String cdoExternalUpdatedBy; // MIS 에서 memberId 로 호출해서 employee_external_map 참조해야함 private Long cdoRegionId; // 배정 지역 private Long cdoDriverId; // 배정된 driver id private UUID cdoDriverUuid; // ERP 에서는 uuid 로 호출 diff --git a/src/main/java/com/goi/erp/dto/CustomerRequestDto.java b/src/main/java/com/goi/erp/dto/CustomerRequestDto.java index 35d6307..84f732d 100644 --- a/src/main/java/com/goi/erp/dto/CustomerRequestDto.java +++ b/src/main/java/com/goi/erp/dto/CustomerRequestDto.java @@ -3,8 +3,8 @@ package com.goi.erp.dto; import lombok.Data; import lombok.NoArgsConstructor; -import java.math.BigDecimal; import java.time.LocalDate; +import java.time.LocalDateTime; @Data @NoArgsConstructor @@ -28,16 +28,12 @@ public class CustomerRequestDto { private LocalDate cusContractDate; // c_contractdate private String cusContractedBy; // c_contractby 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 cusScheduledays; // c_scheduleday private LocalDate cusLastPaidDate; // c_lastpaiddate private Double cusRate; // c_rate private String cusPayMethod; // c_paymenttype - private String cusAccountNo; // c_accountno + private String cusBankAccountNo; // private LocalDate cusIsccDate; // c_form_eu private LocalDate cusCorsiaDate; // c_form_corsia private String cusHstNo; // c_hstno @@ -46,6 +42,7 @@ public class CustomerRequestDto { private String cusInstallLocation; private LocalDate cusLastPickupDate; private Integer cusLastPickupQty; + private Integer cusLastSludge; private Double cusLastPickupLat; private Double cusLastPickupLon; private String cusOpenTime; @@ -53,5 +50,10 @@ public class CustomerRequestDto { private String cusContactComment; // c_comment_ci private Integer cusLastPickupMin; private String cusLoginUser; + private String cusExternalCreatedBy; + private String cusExternalUpdatedBy; + private String cusSourceType; + private LocalDateTime cusCreatedAt; + private LocalDateTime cusUpdatedAt; } diff --git a/src/main/java/com/goi/erp/dto/CustomerResponseDto.java b/src/main/java/com/goi/erp/dto/CustomerResponseDto.java index d848601..07fae88 100644 --- a/src/main/java/com/goi/erp/dto/CustomerResponseDto.java +++ b/src/main/java/com/goi/erp/dto/CustomerResponseDto.java @@ -7,6 +7,7 @@ import lombok.NoArgsConstructor; import java.math.BigDecimal; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.UUID; @Data @@ -34,18 +35,15 @@ public class CustomerResponseDto { private String cusInstallLocation; private LocalDate cusLastPickupDate; private Integer cusLastPickupQty; + private Integer cusLastSludge; private BigDecimal cusLastPickupLat; private BigDecimal cusLastPickupLon; - private BigDecimal cusFullCycle; - private Boolean cusFullCycleFlag; - private BigDecimal cusFullCycleForced; - private LocalDate cusFullCycleForcedDate; private String cusSchedule; private String cusScheduledays; private LocalDate cusLastPaidDate; private BigDecimal cusRate; private String cusPayMethod; - private String cusAccountNo; + private String cusBankAccountNo; private LocalDate cusIsccDate; private LocalDate cusCorsiaDate; private String cusHstNo; @@ -55,4 +53,6 @@ public class CustomerResponseDto { private String cusOpenTime; private String cusComment; private String cusContactComment; + private LocalDateTime cusCreatedAt; + private LocalDateTime cusUpdatedAt; } diff --git a/src/main/java/com/goi/erp/entity/Customer.java b/src/main/java/com/goi/erp/entity/Customer.java index 95b9690..daf4d28 100644 --- a/src/main/java/com/goi/erp/entity/Customer.java +++ b/src/main/java/com/goi/erp/entity/Customer.java @@ -15,10 +15,9 @@ import lombok.NoArgsConstructor; import java.math.BigDecimal; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.UUID; -import org.springframework.data.annotation.CreatedBy; -import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Entity @@ -67,28 +66,23 @@ public class Customer { private String cusInstallLocation; private LocalDate cusLastPickupDate; private Integer cusLastPickupQty; + private Integer cusLastSludge; private BigDecimal cusLastPickupLat; private BigDecimal cusLastPickupLon; - private BigDecimal cusFullCycle; - private Boolean cusFullCycleFlag; - private BigDecimal cusFullCycleForced; - private LocalDate cusFullCycleForcedDate; private String cusSchedule; private String cusScheduledays; private LocalDate cusLastPaidDate; private BigDecimal cusRate; private String cusPayMethod; - private String cusAccountNo; + private String cusBankAccountNo; private LocalDate cusIsccDate; private LocalDate cusCorsiaDate; private String cusHstNo; private LocalDate cusTerminatedDate; private String cusTerminationReason; private Integer cusLastPickupMin; - - @CreatedBy private String cusCreatedBy; - - @LastModifiedBy private String cusUpdatedBy; + private LocalDateTime cusCreatedAt; + private LocalDateTime cusUpdatedAt; } diff --git a/src/main/java/com/goi/erp/entity/CustomerDailyOrder.java b/src/main/java/com/goi/erp/entity/CustomerDailyOrder.java index 239729a..784511e 100644 --- a/src/main/java/com/goi/erp/entity/CustomerDailyOrder.java +++ b/src/main/java/com/goi/erp/entity/CustomerDailyOrder.java @@ -11,8 +11,6 @@ import java.time.LocalDate; import java.time.LocalDateTime; 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 jakarta.persistence.Column; @@ -63,13 +61,11 @@ public class CustomerDailyOrder { private LocalDateTime cdoCreatedAt; - @CreatedBy @Column(name = "cdo_created_by") private String cdoCreatedBy; private LocalDateTime cdoUpdatedAt; - @LastModifiedBy @Column(name = "cdo_updated_by") private String cdoUpdatedBy; diff --git a/src/main/java/com/goi/erp/repository/CustomerDailyOrderRepository.java b/src/main/java/com/goi/erp/repository/CustomerDailyOrderRepository.java index 75da40f..8a1559f 100644 --- a/src/main/java/com/goi/erp/repository/CustomerDailyOrderRepository.java +++ b/src/main/java/com/goi/erp/repository/CustomerDailyOrderRepository.java @@ -22,7 +22,7 @@ public interface CustomerDailyOrderRepository extends JpaRepository findByCdoUuid(UUID cdoUuid); // 특정 고객의 특정 날짜 주문 조회 - Optional findByCdoCustomerNoAndCdoOrderDate(String cdoCustomerNo, LocalDate cdoOrderDate); + Optional findByCdoCustomerNoAndCdoOrderDateAndCdoJobType(String cdoCustomerNo, LocalDate cdoOrderDate, String jobType); // 특정 고객의 모든 주문 리스트 List findByCdoCustomerNo(String cdoCustomerNo); diff --git a/src/main/java/com/goi/erp/service/CustomerDailyOrderService.java b/src/main/java/com/goi/erp/service/CustomerDailyOrderService.java index 64b3bda..c611edf 100644 --- a/src/main/java/com/goi/erp/service/CustomerDailyOrderService.java +++ b/src/main/java/com/goi/erp/service/CustomerDailyOrderService.java @@ -31,8 +31,7 @@ public class CustomerDailyOrderService { * CREATE */ public CustomerDailyOrderResponseDto createDailyOrder(CustomerDailyOrderRequestDto dto) { - - // customer id + // customer id Long customerId = resolveCustomerId(dto); // driver id (employee id) @@ -40,7 +39,27 @@ public class CustomerDailyOrderService { // created by (employee no) 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() .cdoUuid(UUID.randomUUID()) .cdoOrderDate(dto.getCdoOrderDate()) @@ -99,9 +118,9 @@ public class CustomerDailyOrderService { /** * GET BY CUSTOMER + DATE */ - public CustomerDailyOrderResponseDto getDailyOrderByCustomerNo(String cusNo, LocalDate orderDate) { + public CustomerDailyOrderResponseDto getDailyOrderByCustomerNo(String cusNo, LocalDate orderDate, String jobType) { CustomerDailyOrder order = dailyOrderRepository - .findByCdoCustomerNoAndCdoOrderDate(cusNo, orderDate) + .findByCdoCustomerNoAndCdoOrderDateAndCdoJobType(cusNo, orderDate, jobType) .orElseThrow(() -> new RuntimeException("Order not found")); return mapToDto(order); } @@ -113,12 +132,13 @@ public class CustomerDailyOrderService { public CustomerDailyOrderResponseDto updateDailyOrderByCustomerNoAndOrderDate( String customerNo, LocalDate orderDate, + String jobType, CustomerDailyOrderRequestDto dto ) { // daily order 조회 CustomerDailyOrder existing = dailyOrderRepository - .findByCdoCustomerNoAndCdoOrderDate(customerNo, orderDate) + .findByCdoCustomerNoAndCdoOrderDateAndCdoJobType(customerNo, orderDate, jobType) .orElseThrow(() -> new RuntimeException("Daily Order not found")); // 기존 updateInternal 로 공통 업데이트 처리 @@ -336,5 +356,58 @@ public class CustomerDailyOrderService { 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 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 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); + } } diff --git a/src/main/java/com/goi/erp/service/CustomerService.java b/src/main/java/com/goi/erp/service/CustomerService.java index 18b66f3..f0b1a76 100644 --- a/src/main/java/com/goi/erp/service/CustomerService.java +++ b/src/main/java/com/goi/erp/service/CustomerService.java @@ -29,8 +29,18 @@ public class CustomerService { private final CustomerRepository customerRepository; private final EntityChangeLogRepository entityChangeLogRepository; + private final HcmEmployeeClient hcmEmployeeClient; 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() .cusUuid(UUID.randomUUID()) .cusNo(dto.getCusNo()) @@ -49,18 +59,15 @@ public class CustomerService { .cusPhone(dto.getCusPhone()) .cusPhoneExt(dto.getCusPhoneExt()) .cusContractDate(dto.getCusContractDate()) - .cusContractedBy(dto.getCusContractedBy()) +// .cusContractedBy(dto.getCusContractedBy()) + .cusContractedBy(contractedBy) .cusInstallDate(dto.getCusInstallDate()) - .cusFullCycle(dto.getCusFullCycle()) - .cusFullCycleFlag(dto.getCusFullCycleFlag()) - .cusFullCycleForced(dto.getCusFullCycleForced()) - .cusFullCycleForcedDate(dto.getCusFullCycleForcedDate()) .cusSchedule(dto.getCusSchedule()) .cusScheduledays(dto.getCusScheduledays()) .cusLastPaidDate(dto.getCusLastPaidDate()) .cusRate(dto.getCusRate() != null ? BigDecimal.valueOf(dto.getCusRate()) : null) .cusPayMethod(dto.getCusPayMethod()) - .cusAccountNo(dto.getCusAccountNo()) + .cusBankAccountNo(dto.getCusBankAccountNo()) .cusIsccDate(dto.getCusIsccDate()) .cusCorsiaDate(dto.getCusCorsiaDate()) .cusHstNo(dto.getCusHstNo()) @@ -68,6 +75,9 @@ public class CustomerService { .cusComment(dto.getCusComment()) .cusContactComment(dto.getCusContactComment()) .cusInstallLocation(dto.getCusInstallLocation()) + .cusCreatedBy(createdBy) + .cusCreatedAt(LocalDateTime.now()) + .cusUpdatedAt(LocalDateTime.now()) .build(); customer = customerRepository.save(customer); @@ -99,8 +109,8 @@ public class CustomerService { } private CustomerResponseDto updateCustomerInternal(Customer customer, CustomerRequestDto dto) { - - if (dto.getCusName() != null) customer.setCusName(dto.getCusName()); + + if (dto.getCusName() != null) customer.setCusName(dto.getCusName()); if (dto.getCusStatus() != null) customer.setCusStatus(dto.getCusStatus()); if (dto.getCusNo() != null) customer.setCusNo(dto.getCusNo()); if (dto.getCusRegionId() != null) customer.setCusRegionId(dto.getCusRegionId()); @@ -116,12 +126,8 @@ public class CustomerService { if (dto.getCusPhone() != null) customer.setCusPhone(dto.getCusPhone()); if (dto.getCusPhoneExt() != null) customer.setCusPhoneExt(dto.getCusPhoneExt()); 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.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.getCusScheduledays() != null) customer.setCusScheduledays(dto.getCusScheduledays()); 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.getCusLastPickupDate() != null) customer.setCusLastPickupDate(dto.getCusLastPickupDate()); 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.getCusLastPickupLon() != null) customer.setCusLastPickupLon(BigDecimal.valueOf(dto.getCusLastPickupLon())); if (dto.getCusOpenTime() != null) customer.setCusOpenTime(dto.getCusOpenTime()); if (dto.getCusComment() != null) customer.setCusComment(dto.getCusComment()); if (dto.getCusContactComment() != null) customer.setCusContactComment(dto.getCusContactComment()); 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); return mapToDto(customer); @@ -169,18 +194,15 @@ public class CustomerService { dto.setCusInstallLocation(customer.getCusInstallLocation()); dto.setCusLastPickupDate(customer.getCusLastPickupDate()); dto.setCusLastPickupQty(customer.getCusLastPickupQty()); + dto.setCusLastSludge(customer.getCusLastSludge()); dto.setCusLastPickupLat(customer.getCusLastPickupLat()); 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.setCusScheduledays(customer.getCusScheduledays()); dto.setCusLastPaidDate(customer.getCusLastPaidDate()); dto.setCusRate(customer.getCusRate()); dto.setCusPayMethod(customer.getCusPayMethod()); - dto.setCusAccountNo(customer.getCusAccountNo()); + dto.setCusBankAccountNo(customer.getCusBankAccountNo()); dto.setCusIsccDate(customer.getCusIsccDate()); dto.setCusCorsiaDate(customer.getCusCorsiaDate()); dto.setCusHstNo(customer.getCusHstNo()); @@ -191,6 +213,8 @@ public class CustomerService { dto.setCusComment(customer.getCusComment()); dto.setCusContactComment(customer.getCusContactComment()); dto.setCusInstallLocation(customer.getCusInstallLocation()); + dto.setCusCreatedAt(customer.getCusCreatedAt()); + dto.setCusUpdatedAt(customer.getCusUpdatedAt()); return dto; } @@ -224,19 +248,52 @@ public class CustomerService { CustomerResponseDto response = updateCustomerInternal(oldCustomer, newCustomer); // 4. 변경 비교 (old vs new) - String misLoginUser = newCustomer.getCusLoginUser(); - compareAndLogChanges(beforeUpdate, oldCustomer, misLoginUser); + String updatedBy = resolveEmpNo( + newCustomer.getCusLoginUser(), + newCustomer.getCusExternalUpdatedBy() + ); + compareAndLogChanges(beforeUpdate, oldCustomer, updatedBy); 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 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 private void compareAndLogChanges(Customer oldData, Customer newData, String changedBy) { // 필드 → DB 컬럼 매핑 Map fieldToColumn = Map.ofEntries( - Map.entry("cusName", "cus_name"), + Map.entry("cusRegionId", "cus_region_id"), + Map.entry("cusName", "cus_name"), Map.entry("cusEmail", "cus_email"), Map.entry("cusPhone", "cus_phone"), Map.entry("cusGeoLat", "cus_geo_lat"), @@ -251,16 +308,20 @@ public class CustomerService { Map.entry("cusContractDate", "cus_contract_date"), Map.entry("cusContractedBy", "cus_contracted_by"), Map.entry("cusInstallDate", "cus_install_date"), - Map.entry("cusFullCycle", "cus_full_cycle"), - Map.entry("cusFullCycleFlag", "cus_full_cycle_flag"), - Map.entry("cusFullCycleForced", "cus_full_cycle_forced"), - Map.entry("cusFullCycleForcedDate", "cus_full_cycle_forced_date"), + Map.entry("cusTerminatedDate", "cus_terminated_date"), + Map.entry("cusTerminationReason", "cus_termination_reason"), Map.entry("cusSchedule", "cus_schedule"), Map.entry("cusScheduledays", "cus_scheduledays"), 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("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("cusCorsiaDate", "cus_corsia_date"), Map.entry("cusHstNo", "cus_hst_no"),