From 06d24c2e6f88adc9e8febada41cdf91ae8377b4c Mon Sep 17 00:00:00 2001 From: Hyojin Ahn Date: Tue, 2 Dec 2025 11:05:49 -0500 Subject: [PATCH] [customer-daily-order] - Added [all] - Changed ID data type to Long - Added Created By, Updated By --- .../com/goi/erp/config/ApplicationConfig.java | 2 +- .../erp/controller/CustomerController.java | 29 +++ .../CustomerDailyOrderController.java | 165 ++++++++++++ .../erp/dto/CustomerDailyOrderRequestDto.java | 54 ++++ .../dto/CustomerDailyOrderResponseDto.java | 59 +++++ .../com/goi/erp/dto/CustomerRequestDto.java | 2 +- .../java/com/goi/erp/entity/Customer.java | 16 +- .../goi/erp/entity/CustomerDailyOrder.java | 105 ++++++++ .../java/com/goi/erp/entity/Employee.java | 2 +- .../com/goi/erp/entity/EntityChangeLog.java | 9 +- .../CustomerDailyOrderRepository.java | 35 +++ .../service/CustomerDailyOrderService.java | 242 ++++++++++++++++++ .../com/goi/erp/service/CustomerService.java | 9 +- .../goi/erp/token/ApplicationAuditAware.java | 31 ++- 14 files changed, 734 insertions(+), 26 deletions(-) create mode 100644 src/main/java/com/goi/erp/controller/CustomerDailyOrderController.java create mode 100644 src/main/java/com/goi/erp/dto/CustomerDailyOrderRequestDto.java create mode 100644 src/main/java/com/goi/erp/dto/CustomerDailyOrderResponseDto.java create mode 100644 src/main/java/com/goi/erp/entity/CustomerDailyOrder.java create mode 100644 src/main/java/com/goi/erp/repository/CustomerDailyOrderRepository.java create mode 100644 src/main/java/com/goi/erp/service/CustomerDailyOrderService.java diff --git a/src/main/java/com/goi/erp/config/ApplicationConfig.java b/src/main/java/com/goi/erp/config/ApplicationConfig.java index 3e10dec..c2805bb 100644 --- a/src/main/java/com/goi/erp/config/ApplicationConfig.java +++ b/src/main/java/com/goi/erp/config/ApplicationConfig.java @@ -14,7 +14,7 @@ public class ApplicationConfig { private String jwtSecret; @Bean - public AuditorAware auditorAware() { + public AuditorAware auditorAware() { return new ApplicationAuditAware(jwtSecret); } diff --git a/src/main/java/com/goi/erp/controller/CustomerController.java b/src/main/java/com/goi/erp/controller/CustomerController.java index 7ff39be..03167fd 100644 --- a/src/main/java/com/goi/erp/controller/CustomerController.java +++ b/src/main/java/com/goi/erp/controller/CustomerController.java @@ -2,8 +2,10 @@ package com.goi.erp.controller; import com.goi.erp.common.permission.PermissionChecker; import com.goi.erp.common.permission.PermissionSet; +import com.goi.erp.dto.CustomerDailyOrderResponseDto; import com.goi.erp.dto.CustomerRequestDto; import com.goi.erp.dto.CustomerResponseDto; +import com.goi.erp.service.CustomerDailyOrderService; import com.goi.erp.service.CustomerService; import com.goi.erp.token.PermissionAuthenticationToken; @@ -11,12 +13,14 @@ import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; +import java.time.LocalDate; import java.util.UUID; @RestController @@ -33,6 +37,7 @@ public class CustomerController { private int maxSize; private final CustomerService customerService; + private final CustomerDailyOrderService dailyOrderService; // CREATE @PostMapping @@ -176,4 +181,28 @@ public class CustomerController { CustomerResponseDto updated = customerService.updateCustomerByNo(cusNo, dto); return ResponseEntity.ok(updated); } + + // READ DAILY ORDER BY CUSTOMER NO + DATE + @GetMapping("/no/{cusNo}/daily-orders/{orderDate}") + public ResponseEntity getDailyOrderByCustomerNo( + @PathVariable String cusNo, + @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate + ) { + + PermissionAuthenticationToken auth = + (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + + if (auth == null || auth.getPermissionSet() == null) { + throw new AccessDeniedException("Permission information is missing"); + } + + PermissionSet permissionSet = auth.getPermissionSet(); + if (!PermissionChecker.canReadCRM(permissionSet)) { + throw new AccessDeniedException("You do not have permission to read daily order"); + } + + return ResponseEntity.ok( + dailyOrderService.getDailyOrderByCustomerNo(cusNo, orderDate) + ); + } } diff --git a/src/main/java/com/goi/erp/controller/CustomerDailyOrderController.java b/src/main/java/com/goi/erp/controller/CustomerDailyOrderController.java new file mode 100644 index 0000000..6c9e640 --- /dev/null +++ b/src/main/java/com/goi/erp/controller/CustomerDailyOrderController.java @@ -0,0 +1,165 @@ +package com.goi.erp.controller; + +import com.goi.erp.common.permission.PermissionChecker; +import com.goi.erp.common.permission.PermissionSet; + +import com.goi.erp.dto.CustomerDailyOrderRequestDto; +import com.goi.erp.dto.CustomerDailyOrderResponseDto; +import com.goi.erp.service.CustomerDailyOrderService; +import com.goi.erp.token.PermissionAuthenticationToken; + +import lombok.RequiredArgsConstructor; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.core.context.SecurityContextHolder; + +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.util.UUID; + +@RestController +@RequestMapping("/customer-daily-order") +@RequiredArgsConstructor +public class CustomerDailyOrderController { + + @Value("${pagination.default-page:0}") + private int defaultPage; + + @Value("${pagination.default-size:20}") + private int defaultSize; + + @Value("${pagination.max-size:100}") + private int maxSize; + + private final CustomerDailyOrderService dailyOrderService; + + private PermissionSet getPermission() { + PermissionAuthenticationToken auth = + (PermissionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + + if (auth == null || auth.getPermissionSet() == null) { + throw new AccessDeniedException("Permission information is missing"); + } + + return auth.getPermissionSet(); + } + + + // CREATE + @PostMapping + public ResponseEntity createDailyOrder( + @RequestBody CustomerDailyOrderRequestDto dto) { + + PermissionSet permissions = getPermission(); + if (!PermissionChecker.canCreateCRM(permissions)) { + throw new AccessDeniedException("You do not have permission to create daily orders"); + } + + CustomerDailyOrderResponseDto created = dailyOrderService.createDailyOrder(dto); + return new ResponseEntity<>(created, HttpStatus.CREATED); + } + + + // READ ALL (paged) + @GetMapping + public ResponseEntity> getAllDailyOrders( + @RequestParam(required = false) Integer page, + @RequestParam(required = false) Integer size) { + + PermissionSet permissions = getPermission(); + if (!PermissionChecker.canReadCRMAll(permissions)) { + throw new AccessDeniedException("You do not have permission to read all daily orders"); + } + + int p = (page == null) ? defaultPage : page; + int s = (size == null) ? defaultSize : size; + if (s > maxSize) s = maxSize; + + return ResponseEntity.ok(dailyOrderService.getAllDailyOrders(p, s)); + } + + + // READ ONE BY UUID + @GetMapping("/{uuid}") + public ResponseEntity getDailyOrder(@PathVariable UUID uuid) { + + PermissionSet permissions = getPermission(); + if (!PermissionChecker.canReadCRM(permissions)) { + throw new AccessDeniedException("You do not have permission to read daily order"); + } + + return ResponseEntity.ok(dailyOrderService.getDailyOrderByUuid(uuid)); + } + + + // READ BY CUSTOMER + DATE + @GetMapping("/customer/{customerNo}/{orderDate}") + public ResponseEntity getDailyOrderByCustomerNo( + @PathVariable String customerNo, + @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate + ) + { + + PermissionSet permissions = getPermission(); + if (!PermissionChecker.canReadCRM(permissions)) { + throw new AccessDeniedException("You do not have permission to read daily order"); + } + + return ResponseEntity.ok(dailyOrderService.getDailyOrderByCustomerNo(customerNo, orderDate)); + } + + // UPDATE BY CUSTOMER + DATE + @PatchMapping("/customer/{customerNo}/{orderDate}") + public ResponseEntity updateDailyOrderByCustomerNo( + @PathVariable String customerNo, + @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate orderDate, + @RequestBody CustomerDailyOrderRequestDto dto + ) { + + PermissionSet permissions = getPermission(); + if (!PermissionChecker.canUpdateCRM(permissions)) { + throw new AccessDeniedException("You do not have permission to update daily order"); + } + + return ResponseEntity.ok( + dailyOrderService.updateDailyOrderByCustomerNoAndOrderDate(customerNo, orderDate, dto) + ); + } + + + + // UPDATE + @PatchMapping("/{uuid}") + public ResponseEntity updateDailyOrder( + @PathVariable UUID uuid, + @RequestBody CustomerDailyOrderRequestDto dto) { + + PermissionSet permissions = getPermission(); + if (!PermissionChecker.canUpdateCRM(permissions)) { + throw new AccessDeniedException("You do not have permission to update daily order"); + } + + return ResponseEntity.ok(dailyOrderService.updateDailyOrder(uuid, dto)); + } + + + // DELETE + @DeleteMapping("/{uuid}") + public ResponseEntity deleteDailyOrder(@PathVariable UUID uuid) { + + PermissionSet permissions = getPermission(); + if (!PermissionChecker.canDeleteCRM(permissions)) { + throw new AccessDeniedException("You do not have permission to delete daily order"); + } + + dailyOrderService.deleteDailyOrder(uuid); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/goi/erp/dto/CustomerDailyOrderRequestDto.java b/src/main/java/com/goi/erp/dto/CustomerDailyOrderRequestDto.java new file mode 100644 index 0000000..373a49b --- /dev/null +++ b/src/main/java/com/goi/erp/dto/CustomerDailyOrderRequestDto.java @@ -0,0 +1,54 @@ +package com.goi.erp.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.UUID; + +@Data +@NoArgsConstructor +public class CustomerDailyOrderRequestDto { + + private LocalDate cdoOrderDate; // 주문 날짜 (YYYY-MM-DD) + private String cdoOrderType; // 주문 타입 ('N' 등) + + private String cdoRequestNote; // 주문 요청 메모 + + private Long cdoDriverId; // MIS 에서는 driverId 로 호출해서 employee_external_map 참조해야함 + private UUID cdoDriverUuid; // ERP 에서는 uuid 로 호출 + private Long cdoCustomerId; // 고객 ID + private String cdoCustomerNo; + + private String cdoPaymentType; // 결제 타입 + private String cdoCycle; // Cycle (방문 주기) + + private BigDecimal cdoRate; // 요율 (리터당 가격 등) + + private String cdoCreatedBy; // 생성자 ID + private String cdoUpdatedBy; // 수정자 ID + + private String cdoStatus; // 상태 ('A', 'F', 'D') + private String cdoVisitFlag; // 방문 여부 Flag + + private LocalDateTime cdoInputAt; // 입력 시간 + + private BigDecimal cdoEstimatedQty; // 예상 수거량 + private BigDecimal cdoQuantity; // 실제 수거량 + + private Integer cdoSludge; // Sludge 여부/수치 + + private String cdoPayStatus; // 결제 여부 ('N', 'Y') + private BigDecimal cdoPayAmount; // 결제 금액 + + private String cdoPayeeName; // Payee 이름 + private String cdoPayeeSign; // Payee 사인 (이미지 경로 등) + + private BigDecimal cdoPickupLat; // 픽업 위도 + private BigDecimal cdoPickupLon; // 픽업 경도 + private Integer cdoPickupMin; // 픽업 작업 시간(분) + + private String cdoLoginUser; // 로그인한 User (CreatedBy/UpdatedBy 용) +} diff --git a/src/main/java/com/goi/erp/dto/CustomerDailyOrderResponseDto.java b/src/main/java/com/goi/erp/dto/CustomerDailyOrderResponseDto.java new file mode 100644 index 0000000..299d966 --- /dev/null +++ b/src/main/java/com/goi/erp/dto/CustomerDailyOrderResponseDto.java @@ -0,0 +1,59 @@ +package com.goi.erp.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.UUID; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CustomerDailyOrderResponseDto { + + private UUID cdoUuid; // UUID + + private LocalDate cdoOrderDate; // YYYYMMDD + private String cdoOrderType; // 주문 타입 + + private String cdoRequestNote; // 요청 메모 + + private Long cdoDriverId; // Driver ID + private String cdoCustomerNo; // Customer No + + private String cdoPaymentType; // 결제 방식 + private String cdoCycle; // Cycle 값 + + private BigDecimal cdoRate; // 요율 + + private LocalDateTime cdoCreatedAt; // 생성 시간 + private String cdoCreatedBy; // 생성자 + + private LocalDateTime cdoUpdatedAt; // 수정 시간 + private String cdoUpdatedBy; // 수정자 + + private String cdoStatus; // 상태 + private String cdoVisitFlag; // 방문 여부 + + private LocalDateTime cdoInputAt; // 입력 시간 + + private BigDecimal cdoEstimatedQty; // 예상 수거량 + private BigDecimal cdoQuantity; // 실제 수거량 + + private Integer cdoSludge; // Sludge 값 + + private String cdoPayStatus; // 결제 상태 + private BigDecimal cdoPayAmount; // 결제 금액 + + private String cdoPayeeName; // Payee 이름 + private String cdoPayeeSign; // Payee 사인 + + private BigDecimal cdoPickupLat; // 픽업 위도 + private BigDecimal cdoPickupLon; // 픽업 경도 + private Integer cdoPickupMin; // 픽업 시간(분) +} diff --git a/src/main/java/com/goi/erp/dto/CustomerRequestDto.java b/src/main/java/com/goi/erp/dto/CustomerRequestDto.java index cce1365..477468f 100644 --- a/src/main/java/com/goi/erp/dto/CustomerRequestDto.java +++ b/src/main/java/com/goi/erp/dto/CustomerRequestDto.java @@ -13,7 +13,7 @@ public class CustomerRequestDto { private String cusNo; // c_accountno private String cusName; // c_name private String cusStatus; // c_status → ('A', 'I', 'D' 등) - private Integer cusAreaId; // region / area mapping + private Long cusAreaId; // region / area mapping private String cusAddress1; // c_address private String cusAddress2; // c_mailingaddr or c_location private String cusPostalCode; // c_postal diff --git a/src/main/java/com/goi/erp/entity/Customer.java b/src/main/java/com/goi/erp/entity/Customer.java index fbf47d1..d11b25d 100644 --- a/src/main/java/com/goi/erp/entity/Customer.java +++ b/src/main/java/com/goi/erp/entity/Customer.java @@ -2,6 +2,7 @@ package com.goi.erp.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -16,17 +17,22 @@ import java.math.BigDecimal; import java.time.LocalDate; 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 @Table(name = "customer") @Data @NoArgsConstructor @AllArgsConstructor @Builder +@EntityListeners(AuditingEntityListener.class) public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Integer cusId; + private Long cusId; @Column(nullable = false, unique = true) private UUID cusUuid; @@ -40,7 +46,7 @@ public class Customer { @Column(length = 1) private String cusStatus; - private Integer cusAreaId; + private Long cusAreaId; private String cusAddress1; private String cusAddress2; @@ -90,4 +96,10 @@ public class Customer { private LocalDate cusTerminatedDate; private String cusTerminationReason; private Integer cusLastPickupMin; + + @CreatedBy + private String cusCreatedBy; + + @LastModifiedBy + private String cusUpdatedBy; } diff --git a/src/main/java/com/goi/erp/entity/CustomerDailyOrder.java b/src/main/java/com/goi/erp/entity/CustomerDailyOrder.java new file mode 100644 index 0000000..940ced3 --- /dev/null +++ b/src/main/java/com/goi/erp/entity/CustomerDailyOrder.java @@ -0,0 +1,105 @@ +package com.goi.erp.entity; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +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; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "customer_daily_order") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@EntityListeners(AuditingEntityListener.class) +public class CustomerDailyOrder { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long cdoId; + + private UUID cdoUuid; + + private LocalDate cdoOrderDate; + + @Column(length = 1) + private String cdoOrderType; + + private String cdoRequestNote; + + private Long cdoDriverId; + + private Long cdoCustomerId; + private String cdoCustomerNo; + + @Column(length = 10) + private String cdoPaymentType; + + @Column(length = 1) + private String cdoCycle; + + private BigDecimal cdoRate; + + private LocalDateTime cdoCreatedAt; + + @CreatedBy + @Column(name = "cdo_created_by") + private String cdoCreatedBy; + + private LocalDateTime cdoUpdatedAt; + + @LastModifiedBy + @Column(name = "cdo_updated_by") + private String cdoUpdatedBy; + + @Column(length = 1) + private String cdoStatus; + + @Column(length = 1) + private String cdoVisitFlag; + + private LocalDateTime cdoInputAt; + + private BigDecimal cdoEstimatedQty; + + private BigDecimal cdoQuantity; + + private Integer cdoSludge; + + @Column(length = 1) + private String cdoPayStatus; + + private BigDecimal cdoPayAmount; + + @Column(length = 200) + private String cdoPayeeName; + + @Column(length = 200) + private String cdoPayeeSign; + + @Column(precision = 10, scale = 7) + private BigDecimal cdoPickupLat; + + @Column(precision = 10, scale = 7) + private BigDecimal cdoPickupLon; + + private Integer cdoPickupMin; +} diff --git a/src/main/java/com/goi/erp/entity/Employee.java b/src/main/java/com/goi/erp/entity/Employee.java index 4799b24..0d0c7d4 100644 --- a/src/main/java/com/goi/erp/entity/Employee.java +++ b/src/main/java/com/goi/erp/entity/Employee.java @@ -23,7 +23,7 @@ public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "emp_id") - private Integer empId; // 내부 PK, 외부 노출 X + private Long empId; // 내부 PK, 외부 노출 X @Column(name = "emp_uuid", unique = true, nullable = false) private UUID empUuid; // 외부 키로 사용 diff --git a/src/main/java/com/goi/erp/entity/EntityChangeLog.java b/src/main/java/com/goi/erp/entity/EntityChangeLog.java index 18633d7..f7239bd 100644 --- a/src/main/java/com/goi/erp/entity/EntityChangeLog.java +++ b/src/main/java/com/goi/erp/entity/EntityChangeLog.java @@ -10,6 +10,9 @@ import jakarta.persistence.Table; import java.time.LocalDate; import java.time.LocalDateTime; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.LastModifiedBy; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -25,13 +28,13 @@ public class EntityChangeLog { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "ecl_id") - private Integer eclId; + private Long eclId; @Column(name = "ecl_entity_type") private String eclEntityType; @Column(name = "ecl_entity_id") - private Integer eclEntityId; + private Long eclEntityId; @Column(name = "ecl_field_name") private String eclFieldName; @@ -48,12 +51,14 @@ public class EntityChangeLog { @Column(name = "ecl_effective_date") private LocalDate eclEffectiveDate; + @LastModifiedBy @Column(name = "ecl_changed_by") private String eclChangedBy; @Column(name = "ecl_changed_at") private LocalDateTime eclChangedAt; + @CreatedBy @Column(name = "ecl_created_by") private String eclCreatedBy; } diff --git a/src/main/java/com/goi/erp/repository/CustomerDailyOrderRepository.java b/src/main/java/com/goi/erp/repository/CustomerDailyOrderRepository.java new file mode 100644 index 0000000..75da40f --- /dev/null +++ b/src/main/java/com/goi/erp/repository/CustomerDailyOrderRepository.java @@ -0,0 +1,35 @@ +package com.goi.erp.repository; + +import com.goi.erp.entity.CustomerDailyOrder; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; +import java.util.UUID; +import java.time.LocalDate; +import java.util.List; + +@Repository +public interface CustomerDailyOrderRepository extends JpaRepository { + + // 기본 페이징 조회 + Page findAll(Pageable pageable); + + // UUID 로 조회 + Optional findByCdoUuid(UUID cdoUuid); + + // 특정 고객의 특정 날짜 주문 조회 + Optional findByCdoCustomerNoAndCdoOrderDate(String cdoCustomerNo, LocalDate cdoOrderDate); + + // 특정 고객의 모든 주문 리스트 + List findByCdoCustomerNo(String cdoCustomerNo); + + // 특정 날짜의 전체 주문 + List findByCdoOrderDate(LocalDate cdoOrderDate); + + // 존재 여부 체크 (중복 입력 방지) + boolean existsByCdoCustomerNoAndCdoOrderDate(String cdoCustomerNo, LocalDate cdoOrderDate); +} diff --git a/src/main/java/com/goi/erp/service/CustomerDailyOrderService.java b/src/main/java/com/goi/erp/service/CustomerDailyOrderService.java new file mode 100644 index 0000000..240905b --- /dev/null +++ b/src/main/java/com/goi/erp/service/CustomerDailyOrderService.java @@ -0,0 +1,242 @@ +package com.goi.erp.service; + +import com.goi.erp.dto.CustomerDailyOrderRequestDto; +import com.goi.erp.dto.CustomerDailyOrderResponseDto; +import com.goi.erp.entity.CustomerDailyOrder; +import com.goi.erp.repository.CustomerDailyOrderRepository; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class CustomerDailyOrderService { + + private final CustomerDailyOrderRepository dailyOrderRepository; + + /** + * CREATE + */ + public CustomerDailyOrderResponseDto createDailyOrder(CustomerDailyOrderRequestDto dto) { + + CustomerDailyOrder order = CustomerDailyOrder.builder() + .cdoUuid(UUID.randomUUID()) + .cdoOrderDate(dto.getCdoOrderDate()) + .cdoOrderType(dto.getCdoOrderType()) + + .cdoRequestNote(dto.getCdoRequestNote()) + .cdoDriverId(dto.getCdoDriverId()) + .cdoCustomerNo(dto.getCdoCustomerNo()) + + .cdoPaymentType(dto.getCdoPaymentType()) + .cdoCycle(dto.getCdoCycle()) + .cdoRate(dto.getCdoRate()) + + .cdoCreatedAt(LocalDateTime.now()) + .cdoCreatedBy(dto.getCdoLoginUser()) + + .cdoStatus(dto.getCdoStatus()) + .cdoVisitFlag(dto.getCdoVisitFlag()) + + .cdoInputAt(dto.getCdoInputAt()) + .cdoEstimatedQty(dto.getCdoEstimatedQty()) + .cdoQuantity(dto.getCdoQuantity()) + + .cdoSludge(dto.getCdoSludge()) + .cdoPayStatus(dto.getCdoPayStatus()) + .cdoPayAmount(dto.getCdoPayAmount()) + + .cdoPayeeName(dto.getCdoPayeeName()) + .cdoPayeeSign(dto.getCdoPayeeSign()) + + .cdoPickupLat(dto.getCdoPickupLat()) + .cdoPickupLon(dto.getCdoPickupLon()) + .cdoPickupMin(dto.getCdoPickupMin()) + .build(); + + order = dailyOrderRepository.save(order); + return mapToDto(order); + } + + + /** + * GET ALL (with paging) + */ + public Page getAllDailyOrders(int page, int size) { + Pageable pageable = PageRequest.of(page, size); + Page orders = dailyOrderRepository.findAll(pageable); + return orders.map(this::mapToDto); + } + + + /** + * GET BY UUID + */ + public CustomerDailyOrderResponseDto getDailyOrderByUuid(UUID uuid) { + CustomerDailyOrder order = dailyOrderRepository.findByCdoUuid(uuid) + .orElseThrow(() -> new RuntimeException("Daily Order not found")); + return mapToDto(order); + } + + + /** + * GET BY CUSTOMER + DATE + */ + public CustomerDailyOrderResponseDto getDailyOrderByCustomerNo(String cusNo, LocalDate orderDate) { + CustomerDailyOrder order = dailyOrderRepository + .findByCdoCustomerNoAndCdoOrderDate(cusNo, orderDate) + .orElseThrow(() -> new RuntimeException("Order not found")); + return mapToDto(order); + } + + /** + * UPDATE BY CUSTOMER + DATE + */ + @Transactional + public CustomerDailyOrderResponseDto updateDailyOrderByCustomerNoAndOrderDate( + String customerNo, + LocalDate orderDate, + CustomerDailyOrderRequestDto dto + ) { + + // daily order 조회 + CustomerDailyOrder existing = dailyOrderRepository + .findByCdoCustomerNoAndCdoOrderDate(customerNo, orderDate) + .orElseThrow(() -> new RuntimeException("Daily Order not found")); + + // 기존 updateInternal 로 공통 업데이트 처리 + updateInternal(existing, dto); + + // audit field 업데이트 + existing.setCdoUpdatedAt(LocalDateTime.now()); + existing.setCdoUpdatedBy(dto.getCdoLoginUser()); + + // 저장 + dailyOrderRepository.save(existing); + + return mapToDto(existing); + } + + + /** + * UPDATE + */ + @Transactional + public CustomerDailyOrderResponseDto updateDailyOrder(UUID uuid, CustomerDailyOrderRequestDto dto) { + CustomerDailyOrder existing = dailyOrderRepository.findByCdoUuid(uuid) + .orElseThrow(() -> new RuntimeException("Daily Order not found")); + + updateInternal(existing, dto); + + existing.setCdoUpdatedAt(LocalDateTime.now()); + existing.setCdoUpdatedBy(dto.getCdoLoginUser()); + + dailyOrderRepository.save(existing); + + return mapToDto(existing); + } + + + /** + * DELETE + */ + public void deleteDailyOrder(UUID uuid) { + CustomerDailyOrder existing = dailyOrderRepository.findByCdoUuid(uuid) + .orElseThrow(() -> new RuntimeException("Daily Order not found")); + dailyOrderRepository.delete(existing); + } + + + /** + * Internal Update Logic (CustomerService 동일 스타일) + */ + private void updateInternal(CustomerDailyOrder order, CustomerDailyOrderRequestDto dto) { + + if (dto.getCdoOrderDate() != null) order.setCdoOrderDate(dto.getCdoOrderDate()); + if (dto.getCdoOrderType() != null) order.setCdoOrderType(dto.getCdoOrderType()); + + if (dto.getCdoRequestNote() != null) order.setCdoRequestNote(dto.getCdoRequestNote()); + if (dto.getCdoDriverId() != null) order.setCdoDriverId(dto.getCdoDriverId()); + if (dto.getCdoCustomerNo() != null) order.setCdoCustomerNo(dto.getCdoCustomerNo()); + + if (dto.getCdoPaymentType() != null) order.setCdoPaymentType(dto.getCdoPaymentType()); + if (dto.getCdoCycle() != null) order.setCdoCycle(dto.getCdoCycle()); + if (dto.getCdoRate() != null) order.setCdoRate(dto.getCdoRate()); + + if (dto.getCdoStatus() != null) order.setCdoStatus(dto.getCdoStatus()); + if (dto.getCdoVisitFlag() != null) order.setCdoVisitFlag(dto.getCdoVisitFlag()); + + if (dto.getCdoInputAt() != null) order.setCdoInputAt(dto.getCdoInputAt()); + + if (dto.getCdoEstimatedQty() != null) order.setCdoEstimatedQty(dto.getCdoEstimatedQty()); + if (dto.getCdoQuantity() != null) order.setCdoQuantity(dto.getCdoQuantity()); + + if (dto.getCdoSludge() != null) order.setCdoSludge(dto.getCdoSludge()); + + if (dto.getCdoPayStatus() != null) order.setCdoPayStatus(dto.getCdoPayStatus()); + if (dto.getCdoPayAmount() != null) order.setCdoPayAmount(dto.getCdoPayAmount()); + + if (dto.getCdoPayeeName() != null) order.setCdoPayeeName(dto.getCdoPayeeName()); + if (dto.getCdoPayeeSign() != null) order.setCdoPayeeSign(dto.getCdoPayeeSign()); + + if (dto.getCdoPickupLat() != null) order.setCdoPickupLat(dto.getCdoPickupLat()); + if (dto.getCdoPickupLon() != null) order.setCdoPickupLon(dto.getCdoPickupLon()); + if (dto.getCdoPickupMin() != null) order.setCdoPickupMin(dto.getCdoPickupMin()); + } + + + /** + * ENTITY → RESPONSE DTO + */ + public CustomerDailyOrderResponseDto mapToDto(CustomerDailyOrder order) { + + if (order == null) return null; + + return CustomerDailyOrderResponseDto.builder() + .cdoUuid(order.getCdoUuid()) + .cdoOrderDate(order.getCdoOrderDate()) + .cdoOrderType(order.getCdoOrderType()) + + .cdoRequestNote(order.getCdoRequestNote()) + .cdoDriverId(order.getCdoDriverId()) + .cdoCustomerNo(order.getCdoCustomerNo()) + + .cdoPaymentType(order.getCdoPaymentType()) + .cdoCycle(order.getCdoCycle()) + .cdoRate(order.getCdoRate()) + + .cdoCreatedAt(order.getCdoCreatedAt()) + .cdoCreatedBy(order.getCdoCreatedBy()) + .cdoUpdatedAt(order.getCdoUpdatedAt()) + .cdoUpdatedBy(order.getCdoUpdatedBy()) + + .cdoStatus(order.getCdoStatus()) + .cdoVisitFlag(order.getCdoVisitFlag()) + + .cdoInputAt(order.getCdoInputAt()) + .cdoEstimatedQty(order.getCdoEstimatedQty()) + .cdoQuantity(order.getCdoQuantity()) + + .cdoSludge(order.getCdoSludge()) + + .cdoPayStatus(order.getCdoPayStatus()) + .cdoPayAmount(order.getCdoPayAmount()) + + .cdoPayeeName(order.getCdoPayeeName()) + .cdoPayeeSign(order.getCdoPayeeSign()) + + .cdoPickupLat(order.getCdoPickupLat()) + .cdoPickupLon(order.getCdoPickupLon()) + .cdoPickupMin(order.getCdoPickupMin()) + .build(); + } +} diff --git a/src/main/java/com/goi/erp/service/CustomerService.java b/src/main/java/com/goi/erp/service/CustomerService.java index 5f29daf..6348a46 100644 --- a/src/main/java/com/goi/erp/service/CustomerService.java +++ b/src/main/java/com/goi/erp/service/CustomerService.java @@ -14,7 +14,6 @@ import org.springframework.beans.BeanUtils; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import java.lang.reflect.Field; @@ -228,16 +227,15 @@ public class CustomerService { CustomerResponseDto response = updateCustomerInternal(oldCustomer, newCustomer); // 4. 변경 비교 (old vs new) - String misLoginUser = newCustomer.getCusLoginUser(); // todo: 내부 loginId 로 변경 - String loginId = SecurityContextHolder.getContext().getAuthentication().getName(); // 현재는 MIS login user - compareAndLogChanges(beforeUpdate, oldCustomer, misLoginUser, loginId); + String misLoginUser = newCustomer.getCusLoginUser(); + compareAndLogChanges(beforeUpdate, oldCustomer, misLoginUser); return response; } // set change log - private void compareAndLogChanges(Customer oldData, Customer newData, String changedBy, String createdBy) { + private void compareAndLogChanges(Customer oldData, Customer newData, String changedBy) { // 필드 → DB 컬럼 매핑 Map fieldToColumn = Map.ofEntries( @@ -299,7 +297,6 @@ public class CustomerService { .eclEffectiveDate(LocalDate.now()) .eclChangedBy(changedBy) .eclChangedAt(LocalDateTime.now()) - .eclCreatedBy(changedBy) .build() ); } diff --git a/src/main/java/com/goi/erp/token/ApplicationAuditAware.java b/src/main/java/com/goi/erp/token/ApplicationAuditAware.java index feb95f1..ee72a5e 100644 --- a/src/main/java/com/goi/erp/token/ApplicationAuditAware.java +++ b/src/main/java/com/goi/erp/token/ApplicationAuditAware.java @@ -2,14 +2,15 @@ package com.goi.erp.token; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; import org.springframework.data.domain.AuditorAware; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import jakarta.servlet.http.HttpServletRequest; -import java.nio.charset.StandardCharsets; import java.util.Optional; +import java.security.Key; /** * auth-service에서 발급한 JWT 토큰 기반으로 현재 사용자(empId)를 가져오는 AuditorAware 구현체 @@ -18,7 +19,7 @@ import java.util.Optional; * - SecurityContextHolder 없이도 동작 가능 * - HttpServletRequest에서 Authorization 헤더를 읽어 토큰 파싱 */ -public class ApplicationAuditAware implements AuditorAware { +public class ApplicationAuditAware implements AuditorAware { private final String jwtSecret; @@ -31,8 +32,8 @@ public class ApplicationAuditAware implements AuditorAware { * @return Optional - empId가 없거나 토큰이 유효하지 않으면 Optional.empty() */ @Override - public Optional getCurrentAuditor() { - HttpServletRequest request = getCurrentHttpRequest(); + public Optional getCurrentAuditor() { + HttpServletRequest request = getCurrentHttpRequest(); if (request == null) { return Optional.empty(); } @@ -44,18 +45,22 @@ public class ApplicationAuditAware implements AuditorAware { try { // JWT 파싱 - Claims claims = Jwts.parserBuilder() - // HMAC SHA 키 객체 생성 (secret 길이와 안전성 체크) - .setSigningKey(Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8))) - .build() - .parseClaimsJws(token) - .getBody(); + byte[] keyBytes = Decoders.BASE64.decode(jwtSecret); + Key key = Keys.hmacShaKeyFor(keyBytes); - // 토큰에 empId 클레임이 있어야 함 - Integer empId = claims.get("empId", Integer.class); - return Optional.ofNullable(empId); + Claims claims = Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); + + // 토큰에 loginId 클레임이 있어야 함 + String loginId = claims.get("loginId", String.class); + return Optional.ofNullable(loginId); } catch (Exception e) { // 토큰 파싱/검증 실패 시 Optional.empty() 반환 + e.printStackTrace(); // 🔥 예외 확인 + System.out.println("JWT Error: " + e.getMessage()); return Optional.empty(); } }