- username 을 loginId 로 수정
[Customer]
- MIS 에서 integration 추가
- 변경 시 Entity Change Log 에 입력
This commit is contained in:
Hyojin Ahn 2025-11-28 13:24:00 -05:00
parent 026da5fdcf
commit 9894646e00
8 changed files with 349 additions and 74 deletions

View File

@ -55,8 +55,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
if (needsAuthentication && jwtService.isTokenValid(jwt)) { if (needsAuthentication && jwtService.isTokenValid(jwt)) {
// 토큰에서 empUuid와 PermissionSet 추출 // 토큰에서 loginId와 PermissionSet 추출
String empUuid = jwtService.extractEmpUuid(jwt); String loginId = jwtService.extractLoginId(jwt);
PermissionSet permissionSet = jwtService.getPermissions(jwt); PermissionSet permissionSet = jwtService.getPermissions(jwt);
if (permissionSet == null) { if (permissionSet == null) {
@ -70,7 +70,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
// PermissionAuthenticationToken 생성 // PermissionAuthenticationToken 생성
PermissionAuthenticationToken authToken = PermissionAuthenticationToken authToken =
new PermissionAuthenticationToken(empUuid, permissionSet, authorities); new PermissionAuthenticationToken(loginId, permissionSet, authorities);
// SecurityContextHolder에 세팅 // SecurityContextHolder에 세팅
SecurityContextHolder.getContext().setAuthentication(authToken); SecurityContextHolder.getContext().setAuthentication(authToken);

View File

@ -81,7 +81,7 @@ public class CustomerController {
} }
// READ ONE // READ ONE
@GetMapping("/{uuid}") @GetMapping("/uuid/{uuid}")
public ResponseEntity<CustomerResponseDto> getCustomer(@PathVariable UUID uuid) { public ResponseEntity<CustomerResponseDto> getCustomer(@PathVariable UUID uuid) {
// 권한 체크 // 권한 체크
PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
@ -99,7 +99,7 @@ public class CustomerController {
} }
// UPDATE // UPDATE
@PatchMapping("/{uuid}") @PatchMapping("/uuid/{uuid}")
public ResponseEntity<CustomerResponseDto> updateCustomer( public ResponseEntity<CustomerResponseDto> updateCustomer(
@PathVariable UUID uuid, @PathVariable UUID uuid,
@RequestBody CustomerRequestDto requestDto) { @RequestBody CustomerRequestDto requestDto) {
@ -119,7 +119,7 @@ public class CustomerController {
} }
// DELETE // DELETE
@DeleteMapping("/{uuid}") @DeleteMapping("/uuid/{uuid}")
public ResponseEntity<Void> deleteCustomer(@PathVariable UUID uuid) { public ResponseEntity<Void> deleteCustomer(@PathVariable UUID uuid) {
// 권한 체크 // 권한 체크
PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
@ -138,7 +138,7 @@ public class CustomerController {
} }
// from MIS // from MIS
@GetMapping("/{cusNo}") @GetMapping("/no/{cusNo}")
public ResponseEntity<CustomerResponseDto> getCustomer(@PathVariable String cusNo) { public ResponseEntity<CustomerResponseDto> getCustomer(@PathVariable String cusNo) {
// 권한 체크 // 권한 체크
PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); PermissionAuthenticationToken auth = (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
@ -157,7 +157,7 @@ public class CustomerController {
return ResponseEntity.ok(customer); return ResponseEntity.ok(customer);
} }
@PutMapping("/{cusNo}") @PatchMapping("/no/{cusNo}")
public ResponseEntity<CustomerResponseDto> updateCustomer(@PathVariable String cusNo, public ResponseEntity<CustomerResponseDto> updateCustomer(@PathVariable String cusNo,
@RequestBody CustomerRequestDto dto) { @RequestBody CustomerRequestDto dto) {
// 권한 체크 // 권한 체크

View File

@ -1,30 +1,62 @@
package com.goi.erp.dto; package com.goi.erp.dto;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime;
@Data @Data
public class CustomerRequestDto { public class CustomerRequestDto {
private String cusNo;
private String cusName; private String cusNo; // c_accountno
private String cusStatus; private String cusName; // c_name
private Integer cusAreaId; private String cusStatus; // c_status ('A', 'I', 'D' )
private String cusAddress1; private Integer cusAreaId; // region / area mapping
private String cusAddress2; private String cusAddress1; // c_address
private String cusPostalCode; private String cusAddress2; // c_mailingaddr or c_location
private String cusCity; private String cusPostalCode; // c_postal
private String cusProvince; private String cusCity; // c_city
private BigDecimal cusGeoLat; private String cusProvince; // c_province
private BigDecimal cusGeoLon; private Double cusGeoLat; // c_geolat
private String cusEmail; private Double cusGeoLon; // c_geolon
private String cusPhone; private String cusEmail; // c_email
private String cusPhoneExt; private String cusPhone; // c_phone
private LocalTime cusOpenTime; private String cusPhoneExt; // c_phoneext
private String cusNote;
private LocalDate cusContractDate; private LocalDate cusContractDate; // c_contractdate
private String cusContractedBy; private String cusContractedBy; // c_contractby
private LocalDate cusInstallDate; private LocalDate cusInstallDate; // c_installdate
private String cusInstallLocatoin;
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 LocalDate cusIsccDate; // c_form_eu
private LocalDate cusCorsiaDate; // c_form_corsia
private String cusHstNo; // c_hstno
private LocalDate cusTerminatedDate;
private String cusTerminationReason;
private String cusInstallLocation;
private LocalDate cusLastPickupDate;
private Integer cusLastPickupQty;
private Double cusLastPickupLat;
private Double cusLastPickupLon;
private String cusOpenTime;
private String cusComment;
private Integer cusLastPickupMin;
private String loginUser;
} }

View File

@ -1,23 +1,25 @@
package com.goi.erp.dto; package com.goi.erp.dto;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime;
import java.util.UUID; import java.util.UUID;
@Data @Data
@Builder @Builder
@NoArgsConstructor
@AllArgsConstructor
public class CustomerResponseDto { public class CustomerResponseDto {
private UUID cusUuid; private UUID cusUuid;
private String cusNo; private String cusNo;
private String cusName; private String cusName;
private String cusStatus; private String cusStatus;
private Integer cusAreaId;
private String cusAddress1; private String cusAddress1;
private String cusAddress2; private String cusAddress2;
private String cusPostalCode;
private String cusCity; private String cusCity;
private String cusProvince; private String cusProvince;
private BigDecimal cusGeoLat; private BigDecimal cusGeoLat;
@ -25,10 +27,30 @@ public class CustomerResponseDto {
private String cusEmail; private String cusEmail;
private String cusPhone; private String cusPhone;
private String cusPhoneExt; private String cusPhoneExt;
private LocalTime cusOpenTime;
private String cusNote;
private LocalDate cusContractDate; private LocalDate cusContractDate;
private String cusContractedBy; private String cusContractedBy;
private LocalDate cusInstallDate; private LocalDate cusInstallDate;
private String cusInstallLocatoin; private String cusInstallLocation;
private LocalDate cusLastPickupDate;
private Integer cusLastPickupQty;
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 LocalDate cusIsccDate;
private LocalDate cusCorsiaDate;
private String cusHstNo;
private LocalDate cusTerminatedDate;
private String cusTerminationReason;
private Integer cusLastPickupMin;
private String cusOpenTime;
private String cusComment;
} }

View File

@ -14,7 +14,6 @@ import lombok.NoArgsConstructor;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime;
import java.util.UUID; import java.util.UUID;
@Entity @Entity
@ -56,23 +55,23 @@ public class Customer {
private String cusPhone; private String cusPhone;
private String cusPhoneExt; private String cusPhoneExt;
private LocalTime cusOpenTime; private String cusOpenTime;
private String cusNote; private String cusComment;
private LocalDate cusContractDate; private LocalDate cusContractDate;
private String cusContractedBy; private String cusContractedBy;
private LocalDate cusInstallDate; private LocalDate cusInstallDate;
private String cusInstallLocatoin; private String cusInstallLocation;
private LocalDate cusLastPickupDate; private LocalDate cusLastPickupDate;
private Integer cusLastPickupQty; private Integer cusLastPickupQty;
private BigDecimal cusLastPickupLat; private BigDecimal cusLastPickupLat;
private BigDecimal cusLastPickupLon; private BigDecimal cusLastPickupLon;
private Integer cusFullCycle; private BigDecimal cusFullCycle;
private Boolean cusFullCycleFlag; private Boolean cusFullCycleFlag;
private Integer cusFullCycleForced; private BigDecimal cusFullCycleForced;
private LocalDate cusFullCycleForcedDate; private LocalDate cusFullCycleForcedDate;
private String cusSchedule; private String cusSchedule;
@ -90,4 +89,5 @@ public class Customer {
private LocalDate cusTerminatedDate; private LocalDate cusTerminatedDate;
private String cusTerminationReason; private String cusTerminationReason;
private Integer cusLastPickupMin;
} }

View File

@ -18,7 +18,7 @@ public interface CustomerRepository extends JpaRepository<Customer, Long> {
"c.cusUuid, c.cusNo, c.cusName, c.cusStatus, c.cusAreaId, " + "c.cusUuid, c.cusNo, c.cusName, c.cusStatus, c.cusAreaId, " +
"c.cusAddress1, c.cusAddress2, c.cusPostalCode, c.cusCity, c.cusProvince, " + "c.cusAddress1, c.cusAddress2, c.cusPostalCode, c.cusCity, c.cusProvince, " +
"c.cusGeoLat, c.cusGeoLon, c.cusEmail, c.cusPhone, c.cusPhoneExt, " + "c.cusGeoLat, c.cusGeoLon, c.cusEmail, c.cusPhone, c.cusPhoneExt, " +
"c.cusOpenTime, c.cusNote, c.cusContractDate, c.cusContractedBy, c.cusInstallDate, c.cusInstallLocatoin) " + "c.cusOpenTime, c.cusComment, c.cusContractDate, c.cusContractedBy, c.cusInstallDate, c.cusInstallLocation) " +
"FROM Customer c WHERE c.cusUuid = :uuid") "FROM Customer c WHERE c.cusUuid = :uuid")
Optional<CustomerResponseDto> findCustomerDtoByCusUuid(UUID uuid); Optional<CustomerResponseDto> findCustomerDtoByCusUuid(UUID uuid);
@ -26,7 +26,7 @@ public interface CustomerRepository extends JpaRepository<Customer, Long> {
"c.cusUuid, c.cusNo, c.cusName, c.cusStatus, c.cusAreaId, " + "c.cusUuid, c.cusNo, c.cusName, c.cusStatus, c.cusAreaId, " +
"c.cusAddress1, c.cusAddress2, c.cusPostalCode, c.cusCity, c.cusProvince, " + "c.cusAddress1, c.cusAddress2, c.cusPostalCode, c.cusCity, c.cusProvince, " +
"c.cusGeoLat, c.cusGeoLon, c.cusEmail, c.cusPhone, c.cusPhoneExt, " + "c.cusGeoLat, c.cusGeoLon, c.cusEmail, c.cusPhone, c.cusPhoneExt, " +
"c.cusOpenTime, c.cusNote, c.cusContractDate, c.cusContractedBy, c.cusInstallDate, c.cusInstallLocatoin) " + "c.cusOpenTime, c.cusComment, c.cusContractDate, c.cusContractedBy, c.cusInstallDate, c.cusInstallLocation) " +
"FROM Customer c") "FROM Customer c")
Page<CustomerResponseDto> findAllCustomerDtos(Pageable pageable); Page<CustomerResponseDto> findAllCustomerDtos(Pageable pageable);
@ -34,5 +34,6 @@ public interface CustomerRepository extends JpaRepository<Customer, Long> {
// from MIS // from MIS
Optional<Customer> findByCusNo(String cusNo); Optional<Customer> findByCusNo(String cusNo);
boolean existsByCusNo(String cusNo); boolean existsByCusNo(String cusNo);
} }

View File

@ -3,14 +3,26 @@ package com.goi.erp.service;
import com.goi.erp.dto.CustomerRequestDto; import com.goi.erp.dto.CustomerRequestDto;
import com.goi.erp.dto.CustomerResponseDto; import com.goi.erp.dto.CustomerResponseDto;
import com.goi.erp.entity.Customer; import com.goi.erp.entity.Customer;
import com.goi.erp.entity.EntityChangeLog;
import com.goi.erp.repository.CustomerRepository; import com.goi.erp.repository.CustomerRepository;
import com.goi.erp.repository.EntityChangeLogRepository;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@Service @Service
@ -18,18 +30,53 @@ import java.util.UUID;
public class CustomerService { public class CustomerService {
private final CustomerRepository customerRepository; private final CustomerRepository customerRepository;
private final EntityChangeLogRepository entityChangeLogRepository;
public CustomerResponseDto createCustomer(CustomerRequestDto dto) { public CustomerResponseDto createCustomer(CustomerRequestDto dto) {
Customer customer = Customer.builder() Customer customer = Customer.builder()
.cusUuid(UUID.randomUUID()) .cusUuid(UUID.randomUUID())
.cusName(dto.getCusName())
.cusNo(dto.getCusNo()) .cusNo(dto.getCusNo())
.cusName(dto.getCusName())
.cusStatus(dto.getCusStatus()) .cusStatus(dto.getCusStatus())
.cusAreaId(dto.getCusAreaId())
.cusAddress1(dto.getCusAddress1()) .cusAddress1(dto.getCusAddress1())
.cusAddress2(dto.getCusAddress2()) .cusAddress2(dto.getCusAddress2())
.cusPostalCode(dto.getCusPostalCode())
.cusCity(dto.getCusCity()) .cusCity(dto.getCusCity())
.cusProvince(dto.getCusProvince()) .cusProvince(dto.getCusProvince())
.cusGeoLat(dto.getCusGeoLat() != null ? BigDecimal.valueOf(dto.getCusGeoLat()) : null)
.cusGeoLon(dto.getCusGeoLon() != null ? BigDecimal.valueOf(dto.getCusGeoLon()) : null)
.cusEmail(dto.getCusEmail())
.cusPhone(dto.getCusPhone())
.cusPhoneExt(dto.getCusPhoneExt())
.cusContractDate(dto.getCusContractDate())
.cusContractedBy(dto.getCusContractedBy())
.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())
.cusIsccDate(dto.getCusIsccDate())
.cusCorsiaDate(dto.getCusCorsiaDate())
.cusHstNo(dto.getCusHstNo())
.cusOpenTime(dto.getCusOpenTime())
.cusComment(dto.getCusComment())
.cusInstallLocation(dto.getCusInstallLocation())
.build(); .build();
customer = customerRepository.save(customer); customer = customerRepository.save(customer);
return mapToDto(customer); // 생성 시에는 여전히 엔티티 DTO 필요 return mapToDto(customer); // 생성 시에는 여전히 엔티티 DTO 필요
} }
@ -47,16 +94,7 @@ public class CustomerService {
public CustomerResponseDto updateCustomer(UUID uuid, CustomerRequestDto dto) { public CustomerResponseDto updateCustomer(UUID uuid, CustomerRequestDto dto) {
Customer customer = customerRepository.findByCusUuid(uuid) Customer customer = customerRepository.findByCusUuid(uuid)
.orElseThrow(() -> new RuntimeException("Customer not found")); .orElseThrow(() -> new RuntimeException("Customer not found"));
return updateCustomerInternal(customer, dto);
if (dto.getCusName() != null) customer.setCusName(dto.getCusName());
if (dto.getCusStatus() != null) customer.setCusStatus(dto.getCusStatus());
if (dto.getCusAddress1() != null) customer.setCusAddress1(dto.getCusAddress1());
if (dto.getCusAddress2() != null) customer.setCusAddress2(dto.getCusAddress2());
if (dto.getCusCity() != null) customer.setCusCity(dto.getCusCity());
if (dto.getCusProvince() != null) customer.setCusProvince(dto.getCusProvince());
customerRepository.save(customer);
return mapToDto(customer);
} }
public void deleteCustomer(UUID uuid) { public void deleteCustomer(UUID uuid) {
@ -65,15 +103,101 @@ public class CustomerService {
customerRepository.delete(customer); customerRepository.delete(customer);
} }
private CustomerResponseDto mapToDto(Customer customer) { private CustomerResponseDto updateCustomerInternal(Customer customer, CustomerRequestDto dto) {
return CustomerResponseDto.builder()
.cusUuid(customer.getCusUuid()) if (dto.getCusName() != null) customer.setCusName(dto.getCusName());
.cusName(customer.getCusName()) if (dto.getCusStatus() != null) customer.setCusStatus(dto.getCusStatus());
.cusNo(customer.getCusNo()) if (dto.getCusNo() != null) customer.setCusNo(dto.getCusNo());
.cusStatus(customer.getCusStatus()) if (dto.getCusAreaId() != null) customer.setCusAreaId(dto.getCusAreaId());
.build(); if (dto.getCusAddress1() != null) customer.setCusAddress1(dto.getCusAddress1());
if (dto.getCusAddress2() != null) customer.setCusAddress2(dto.getCusAddress2());
if (dto.getCusPostalCode() != null) customer.setCusPostalCode(dto.getCusPostalCode());
if (dto.getCusCity() != null) customer.setCusCity(dto.getCusCity());
if (dto.getCusProvince() != null) customer.setCusProvince(dto.getCusProvince());
customer.setCusGeoLat(dto.getCusGeoLat() != null ? BigDecimal.valueOf(dto.getCusGeoLat()) : null);
customer.setCusGeoLon(dto.getCusGeoLon() != null ? BigDecimal.valueOf(dto.getCusGeoLon()) : null);
if (dto.getCusEmail() != null) customer.setCusEmail(dto.getCusEmail());
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.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());
customer.setCusRate(dto.getCusRate() != null ? BigDecimal.valueOf(dto.getCusRate()) : null);
if (dto.getCusPayMethod() != null) customer.setCusPayMethod(dto.getCusPayMethod());
if (dto.getCusIsccDate() != null) customer.setCusIsccDate(dto.getCusIsccDate());
if (dto.getCusCorsiaDate() != null) customer.setCusCorsiaDate(dto.getCusCorsiaDate());
if (dto.getCusHstNo() != null) customer.setCusHstNo(dto.getCusHstNo());
if (dto.getCusTerminatedDate() != null) customer.setCusTerminatedDate(dto.getCusTerminatedDate());
if (dto.getCusTerminationReason() != null) customer.setCusTerminationReason(dto.getCusTerminationReason());
if (dto.getCusLastPickupDate() != null) customer.setCusLastPickupDate(dto.getCusLastPickupDate());
if (dto.getCusLastPickupQty() != null) customer.setCusLastPickupQty(dto.getCusLastPickupQty());
customer.setCusLastPickupLat(dto.getCusLastPickupLat() != null ? BigDecimal.valueOf(dto.getCusLastPickupLat()) : null);
customer.setCusLastPickupLon(dto.getCusLastPickupLon() != null ? BigDecimal.valueOf(dto.getCusLastPickupLon()) : null);
if (dto.getCusOpenTime() != null) customer.setCusOpenTime(dto.getCusOpenTime());
if (dto.getCusComment() != null) customer.setCusComment(dto.getCusComment());
if (dto.getCusInstallLocation() != null) customer.setCusInstallLocation(dto.getCusInstallLocation());
customerRepository.save(customer);
return mapToDto(customer);
} }
public CustomerResponseDto mapToDto(Customer customer) {
if (customer == null) return null;
CustomerResponseDto dto = new CustomerResponseDto();
dto.setCusUuid(customer.getCusUuid());
dto.setCusNo(customer.getCusNo());
dto.setCusName(customer.getCusName());
dto.setCusStatus(customer.getCusStatus());
dto.setCusAddress1(customer.getCusAddress1());
dto.setCusAddress2(customer.getCusAddress2());
dto.setCusCity(customer.getCusCity());
dto.setCusProvince(customer.getCusProvince());
dto.setCusGeoLat(customer.getCusGeoLat());
dto.setCusGeoLon(customer.getCusGeoLon());
dto.setCusEmail(customer.getCusEmail());
dto.setCusPhone(customer.getCusPhone());
dto.setCusPhoneExt(customer.getCusPhoneExt());
dto.setCusContractDate(customer.getCusContractDate());
dto.setCusContractedBy(customer.getCusContractedBy());
dto.setCusInstallDate(customer.getCusInstallDate());
dto.setCusInstallLocation(customer.getCusInstallLocation());
dto.setCusLastPickupDate(customer.getCusLastPickupDate());
dto.setCusLastPickupQty(customer.getCusLastPickupQty());
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.setCusIsccDate(customer.getCusIsccDate());
dto.setCusCorsiaDate(customer.getCusCorsiaDate());
dto.setCusHstNo(customer.getCusHstNo());
dto.setCusTerminatedDate(customer.getCusTerminatedDate());
dto.setCusTerminationReason(customer.getCusTerminationReason());
dto.setCusLastPickupMin(customer.getCusLastPickupMin());
dto.setCusOpenTime(customer.getCusOpenTime());
dto.setCusComment(customer.getCusComment());
dto.setCusInstallLocation(customer.getCusInstallLocation());
return dto;
}
// from MIS // from MIS
public CustomerResponseDto getCustomerByNo(String cusNo) { public CustomerResponseDto getCustomerByNo(String cusNo) {
Customer customer = customerRepository.findByCusNo(cusNo) Customer customer = customerRepository.findByCusNo(cusNo)
@ -81,18 +205,107 @@ public class CustomerService {
return mapToDto(customer); return mapToDto(customer);
} }
public CustomerResponseDto updateCustomerByNo(String cusNo, CustomerRequestDto dto) { @Transactional
Customer customer = customerRepository.findByCusNo(cusNo) public CustomerResponseDto updateCustomerByNo(String cusNo, CustomerRequestDto newCustomer) {
Customer oldCustomer = customerRepository.findByCusNo(cusNo)
.orElseThrow(() -> new RuntimeException("Customer not found")); .orElseThrow(() -> new RuntimeException("Customer not found"));
customer.setCusName(dto.getCusName()); // 1. OLD VALUE 백업 (deep copy)
customer.setCusStatus(dto.getCusStatus()); Customer beforeUpdate = new Customer();
customer.setCusAddress1(dto.getCusAddress1()); BeanUtils.copyProperties(oldCustomer, beforeUpdate);
customer.setCusAddress2(dto.getCusAddress2());
customer.setCusCity(dto.getCusCity());
customer.setCusProvince(dto.getCusProvince());
customerRepository.save(customer); // 2. 주소/우편번호 변경 geo 초기화
return mapToDto(customer); if ((newCustomer.getCusAddress1() != null && !newCustomer.getCusAddress1().equals(oldCustomer.getCusAddress1())) ||
(newCustomer.getCusPostalCode() != null && !newCustomer.getCusPostalCode().equals(oldCustomer.getCusPostalCode()))) {
oldCustomer.setCusGeoLat(null);
oldCustomer.setCusGeoLon(null);
}
// 3. 실제 업데이트 적용
CustomerResponseDto response = updateCustomerInternal(oldCustomer, newCustomer);
// 4. 변경 비교 (old vs new)
String misLoginUser = newCustomer.getLoginUser(); // todo: 내부 loginId 변경
String loginId = SecurityContextHolder.getContext().getAuthentication().getName(); // 현재는 MIS login user
compareAndLogChanges(beforeUpdate, oldCustomer, misLoginUser, loginId);
return response;
} }
// set change log
private void compareAndLogChanges(Customer oldData, Customer newData, String changedBy, String createdBy) {
// 필드 DB 컬럼 매핑
Map<String, String> fieldToColumn = Map.ofEntries(
Map.entry("cusName", "cus_name"),
Map.entry("cusEmail", "cus_email"),
Map.entry("cusPhone", "cus_phone"),
Map.entry("cusGeoLat", "cus_geo_lat"),
Map.entry("cusGeoLon", "cus_geo_lon"),
Map.entry("cusStatus", "cus_status"),
Map.entry("cusAddress1", "cus_address1"),
Map.entry("cusAddress2", "cus_address2"),
Map.entry("cusPostalCode", "cus_postal_code"),
Map.entry("cusCity", "cus_city"),
Map.entry("cusProvince", "cus_province"),
Map.entry("cusPhoneExt", "cus_phone_ext"),
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("cusSchedule", "cus_schedule"),
Map.entry("cusScheduledays", "cus_scheduledays"),
Map.entry("cusLastPaidDate", "cus_last_paid_date"),
Map.entry("cusRate", "cus_rate"),
Map.entry("cusPayMethod", "cus_pay_method"),
Map.entry("cusAccountNo", "cus_account_no"),
Map.entry("cusIsccDate", "cus_iscc_date"),
Map.entry("cusCorsiaDate", "cus_corsia_date"),
Map.entry("cusHstNo", "cus_hst_no"),
Map.entry("cusOpenTime", "cus_open_time"),
Map.entry("cusComment", "cus_comment"),
Map.entry("cusInstallLocation", "cus_install_location")
);
Class<?> clazz = Customer.class;
for (var entry : fieldToColumn.entrySet()) {
String fieldName = entry.getKey();
String columnName = entry.getValue();
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
Object oldVal = field.get(oldData);
Object newVal = field.get(newData);
if (!Objects.equals(oldVal, newVal)) {
entityChangeLogRepository.save(
EntityChangeLog.builder()
.eclEntityType("Customer")
.eclEntityId(newData.getCusId())
.eclFieldName(fieldName)
.eclColumnName(columnName)
.eclOldValue(oldVal == null ? null : oldVal.toString())
.eclNewValue(newVal == null ? null : newVal.toString())
.eclEffectiveDate(LocalDate.now())
.eclChangedBy(changedBy)
.eclChangedAt(LocalDateTime.now())
.eclCreatedBy(changedBy)
.build()
);
}
} catch (Exception e) {
throw new RuntimeException("Failed to compare field: " + fieldName, e);
}
}
}
} }

View File

@ -35,6 +35,13 @@ public class JwtService {
return extractClaim(token, Claims::getSubject); return extractClaim(token, Claims::getSubject);
} }
/**
* loginId 추출
*/
public String extractLoginId(String token) {
return extractClaim(token, claims -> claims.get("loginId", String.class));
}
/** /**
* firstName 추출 * firstName 추출
*/ */
@ -117,7 +124,7 @@ public class JwtService {
JwtService jwtService = new JwtService(); JwtService jwtService = new JwtService();
jwtService.secretKey = "D0HaHnTPKLkUO9ULL1Ulm6XDZjhzuFtvTCcxTxSoCS8="; jwtService.secretKey = "D0HaHnTPKLkUO9ULL1Ulm6XDZjhzuFtvTCcxTxSoCS8=";
String token = "eyJhbGciOiJIUzI1NiJ9.eyJmaXJzdE5hbWUiOiJIeW9qaW4iLCJsYXN0TmFtZSI6IkFobiIsInBlcm1pc3Npb25zIjpbIkFMTCJdLCJyb2xlcyI6WyJBZG1pbiJdLCJzdWIiOiJhMjM4ZWQ0OC03OGRjLTQ2YWEtOWNiMC1hNWYxZGQyZDJmMTMiLCJpYXQiOjE3NjM2NDYzNzQsImV4cCI6MTc2MzczMjc3NH0.HwFZeNbxVldcBeiqc3TUO3x5on2Quy7_Yd_HTkIfOR4"; String token = "eyJhbGciOiJIUzI1NiJ9.eyJmaXJzdE5hbWUiOiJNSVMiLCJsYXN0TmFtZSI6IkNTIiwibG9naW5JZCI6ImNzX21pcyIsInBlcm1pc3Npb25zIjpbIkg6UjpTIiwiQzpDOkEiLCJDOlI6QSIsIkM6VTpBIiwiQzpEOkEiXSwicm9sZXMiOlsiQ1MgU3RhZmYiXSwic3ViIjoiMWU3NTU4YzYtOTFhZC00ZDcxLTg3ZTUtZGJjZmZiYjk5Zjg1IiwiaWF0IjoxNzY0MzQ3Nzg1LCJleHAiOjIwNzk3MDc3ODV9.lL-ZHEpiribxIrNmeYp6LAeU11z-KuRbgELkWjHCCSc";
// user 정보 // user 정보
Claims claims = jwtService.extractAllClaims(token); Claims claims = jwtService.extractAllClaims(token);