Skip to content

Commit

Permalink
Merge pull request #120 from Orange-Co/feature/fcm
Browse files Browse the repository at this point in the history
Feat: separate admin message
  • Loading branch information
Kang1221 authored Oct 15, 2024
2 parents 7c048cb + 4885b78 commit c119106
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 86 deletions.
8 changes: 4 additions & 4 deletions src/main/java/co/orange/ddanzi/domain/user/enums/FcmCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ public enum FcmCase {
B4("상품 배송에 문제가 생겼나요?","24시간 후에 자동 구매확정 됩니다."),

//관리자
C1("관리자 알림: 회원가입", "새로운 유저가 등록되었습니다."),
C2("관리자 알림: 구매실행", "결제가 실행되었습니다."),
C3("관리자 알림: 환불실행", "중복 결제로 인해 환불되었습니다."),
C4("관리자 알림: 환불실행", "판매자가 상품을 판매하여 결제내역이 환불되었습니다.")
C1("⚠️관리자 알림: 회원가입", "새로운 유저가 등록되었습니다."),
C2("⚠️관리자 알림: 구매실행", "결제가 실행되었습니다."),
C3("⚠️관리자 알림: 환불실행", "중복 결제로 인해 환불되었습니다."),
C4("⚠️관리자 알림: 환불실행", "판매자가 상품을 판매하여 결제내역이 환불되었습니다."),
;

private final String title;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package co.orange.ddanzi.dto.payment;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class PortOneTokenRequestDto {
@JsonProperty("imp_key")
private String impKey; // 필드 이름을 camelCase로 수정

@JsonProperty("imp_secret")
private String impSecret;
private String imp_key;
private String imp_secret;
}
30 changes: 30 additions & 0 deletions src/main/java/co/orange/ddanzi/global/firebase/FirebaseUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ public String sendMessage(String fcmToken, FcmCase fcmCase) {
}
}

public String sendAdminMessage(String fcmToken, String title, String body) {
try {
log.info("관리자 Sending FCM message: {}", title);
return FirebaseMessaging.getInstance().send(makeAdminMessage(fcmToken , title, body));
} catch (FirebaseMessagingException e) {
log.error("관리자 FirebaseMessagingException occurred: {}", e.getMessage());
return "관리자 FCM 메시지 전송 실패: " + e.getMessage();
} catch (Exception e) {
log.info(e.getMessage());
return e.getMessage();
}
}


public Message makeMessage(String fcmSendDto, FcmCase fcmCase) {
Notification notification = Notification
.builder()
Expand All @@ -44,6 +58,22 @@ public Message makeMessage(String fcmSendDto, FcmCase fcmCase) {
.build();
}

public Message makeAdminMessage(String fcmSendDto, String title, String body) {
Notification notification = Notification
.builder()
.setTitle(title)
.setBody(body)
.build();
return Message
.builder()
.setNotification(notification)
.putData("title", title)
.putData("body",body)
.setToken(fcmSendDto)
.build();
}


public MulticastMessage makeMessages(List<String> targetTokens, String title, String body) {
Notification notification = Notification.builder()
.setTitle(title)
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/co/orange/ddanzi/repository/ItemRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
import java.util.Optional;

public interface ItemRepository extends JpaRepository<Item, String> {
List<Item> findAllBySeller(User user);
@Query("SELECT i FROM Item i WHERE i.seller = :user AND i.status <> 'DELETED'")
List<Item> findAllBySellerAndNotDeleted(User user);

Integer countAllBySeller(User user);

@Query("SELECT MAX(CAST(RIGHT(i.id, 2) AS integer)) FROM Item i WHERE i.product = :product")
Integer findMaxSequenceNumberByProduct(@Param("product") Product product);
Expand Down
26 changes: 17 additions & 9 deletions src/main/java/co/orange/ddanzi/service/ItemService.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,31 +138,39 @@ public ApiResponse<?> getItem(String itemId){
public ApiResponse<?> deleteItem(String itemId){
User user = authUtils.getUser();
Item item = itemRepository.findById(itemId).orElseThrow(ItemNotFoundException::new);

if(!item.getSeller().equals(user))
return ApiResponse.onFailure(Error.ITEM_UNAUTHORIZED_USER, null);

Order order = orderRepository.findByItemAndStatus(item).orElse(null);
if(order==null){
log.info("거래 취소 중 - 거래중이지 않아 바로 제품을 삭제합니다.");
item.updateStatus(ItemStatus.DELETED);
}
else{
if(order!=null){
log.info("거래 취소 중 - 거래중인 상품이 있습니다. 대안을 탐색합니다.");
Item newItem = itemRepository.findNearestExpiryItem(item.getProduct()).orElse(null);
if(newItem == null) {
log.info("환불을 진행합니다.");
log.info("대안이 없음 - 거래를 취소하고 환불을 진행합니다.");
Payment payment = paymentRepository.findByOrder(order);
User buyer = order.getBuyer();
try {
paymentService.refundPayment(buyer, order, "현재 남은 재고가 없어 고객에게 결제 금액 환불합니다.");
payment.updatePaymentStatusAndEndedAt(PayStatus.CANCELLED);
historyService.createPaymentHistoryWithError(buyer, payment, "재퓸 삭제- 환불 처리 성공");
historyService.createPaymentHistoryWithError(buyer, payment, "제품 삭제- 환불 처리 성공");
}catch (Exception e){
log.info("환불이 불가능하여 제품 삭제에 실패했습니다.");
historyService.createPaymentHistoryWithError(buyer, payment, "제품 삭제 - 환불 처리 실패");
return ApiResponse.onFailure(Error.REFUND_FAILED, Map.of("orderId", order.getId()));
return ApiResponse.onFailure(Error.REFUND_FAILED, Map.of("itemId", item.getId()));
}
}
else{
log.info("대안이 있음 - 거래에 새로운 제품을 할당합니다.");
order.updateItem(newItem);
}
}
log.info("제품을 삭제합니다.");
item.updateStatus(ItemStatus.DELETED);
log.info("재고를 감소시킵니다.");
Product product = item.getProduct();
product.updateStock(product.getStock() - 1);

return ApiResponse.onSuccess(Success.DELETE_ITEM_SUCCESS, true);
}

Expand Down Expand Up @@ -219,7 +227,7 @@ private List<SelectedOption> setSelectedOptionList(Order order){
}

public List<MyItem> getMyItemList(User user){
List<Item> itemList = itemRepository.findAllBySeller(user);
List<Item> itemList = itemRepository.findAllBySellerAndNotDeleted(user);
List<MyItem> myItemList = new ArrayList<>();
for(Item item : itemList){
Product product = item.getProduct();
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/co/orange/ddanzi/service/OrderService.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ public void checkOrderPlacedOrder(){
LocalDateTime oneDayLimit = LocalDateTime.now().minusMinutes(1);
List<Order> orderPlaceOrders = orderRepository.findOverLimitTimeOrders(OrderStatus.ORDER_PLACE, oneDayLimit);
for(Order order : orderPlaceOrders){
fcmService.sendMessageToUser(order.getItem().getSeller(), FcmCase.A2, order);
fcmService.sendMessageToUser(order.getBuyer(), FcmCase.B1, order);
paymentService.refundPayment(order.getBuyer(), order, "고객이 판매확정을 하지 않아 거래가 취소되어 결제 금액을 환불합니다.");
order.updateStatus(OrderStatus.CANCELLED);
fcmService.sendMessageToUser(order.getItem().getSeller(), FcmCase.A2, order);
fcmService.sendMessageToUser(order.getBuyer(), FcmCase.B1, order);
}
}

Expand Down
54 changes: 30 additions & 24 deletions src/main/java/co/orange/ddanzi/service/PaymentService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import co.orange.ddanzi.domain.product.Product;
import co.orange.ddanzi.domain.product.enums.ItemStatus;
import co.orange.ddanzi.domain.user.User;
import co.orange.ddanzi.domain.user.enums.FcmCase;
import co.orange.ddanzi.dto.payment.*;
import co.orange.ddanzi.global.jwt.AuthUtils;
import co.orange.ddanzi.repository.*;
Expand Down Expand Up @@ -126,7 +125,7 @@ else if(payment.getPayStatus().equals(PayStatus.PAID)){
log.info("Payment is paid!!");
item.updateStatus(ItemStatus.CLOSED);
product.updateStock(product.getStock() - 1);
fcmService.sendMessageToAdmin(FcmCase.C2);
fcmService.sendMessageToAdmins("⚠️관리자 알림: 구매실행", "결제가 실행되었습니다. orderId:" + order.getId());
}

historyService.createPaymentHistory(buyer, payment);
Expand Down Expand Up @@ -168,8 +167,8 @@ public String getPortOneAccessToken(){
headers.set("Content-Type", "application/json");

PortOneTokenRequestDto requestBody = PortOneTokenRequestDto.builder()
.impKey(accessKey)
.impSecret(accessSecret)
.imp_key(accessKey)
.imp_secret(accessSecret)
.build();

HttpEntity<PortOneTokenRequestDto> entity = new HttpEntity<>(requestBody, headers);
Expand All @@ -183,28 +182,35 @@ public String getPortOneAccessToken(){
public void refundPayment(User user, Order order, String reason){
if(!user.equals(order.getBuyer()))
throw new RuntimeException("결제자와 요청자가 다르므로 환불이 어렵습니다.");
String baseUrl = "https://api.iamport.kr/payments/cancel";
String url = UriComponentsBuilder.fromUriString(baseUrl)
.toUriString();
log.info("결제 취소 url 생성, url-> {}", url);

String key = getPortOneAccessToken();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", key);

RefundRequestDto requestDto = RefundRequestDto.builder()
.merchant_uid(order.getId())
.reason(reason)
.build();

HttpEntity<Object> entity = new HttpEntity<>(requestDto, headers);
log.info("헤더 및 request body 생성");
try{
String baseUrl = "https://api.iamport.kr/payments/cancel";
String url = UriComponentsBuilder.fromUriString(baseUrl)
.toUriString();
log.info("결제 취소 url 생성, url-> {}", url);

String key = getPortOneAccessToken();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", key);

RefundRequestDto requestDto = RefundRequestDto.builder()
.merchant_uid(order.getId())
.reason(reason)
.build();

HttpEntity<Object> entity = new HttpEntity<>(requestDto, headers);
log.info("헤더 및 request body 생성");

RestTemplate restTemplate = new RestTemplate();
restTemplate.postForObject(url, entity, String.class);
log.info("결제 취소 api 호출");
fcmService.sendMessageToAdmins("⚠️관리자 알림: 환불실행", "중복 결제로 인해 환불되었습니다. orderId:" + order.getId());
}catch (Exception e){
log.info("환불 실패");
fcmService.sendMessageToAdmins("⚠️관리자 알림: 환불 실패", "환불에 실패했습니다. orderId:" + order.getId());
}

RestTemplate restTemplate = new RestTemplate();
restTemplate.postForObject(url, entity, String.class);
log.info("결제 취소 api 호출");
fcmService.sendMessageToAdmin(FcmCase.C3);
}

}
34 changes: 2 additions & 32 deletions src/main/java/co/orange/ddanzi/service/auth/OAuthService.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package co.orange.ddanzi.service.auth;

import co.orange.ddanzi.domain.user.User;
import co.orange.ddanzi.domain.user.enums.FcmCase;
import co.orange.ddanzi.domain.user.enums.LoginType;
import co.orange.ddanzi.domain.user.enums.UserStatus;
import co.orange.ddanzi.dto.auth.SigninRequestDto;
Expand Down Expand Up @@ -69,7 +68,7 @@ public User kakaoSignIn(SigninRequestDto requestDto) throws JsonProcessingExcept
User user = userRepository.findByEmail(email).orElse(null);

if (user == null){
fcmService.sendMessageToAdmin(FcmCase.C1);
fcmService.sendMessageToAdmins("⚠️관리자 알림: 카카오 회원가입", "새로운 유저가 등록되었습니다. 총 유저 수: " + userRepository.count());
return kakaoSignUp(email);
}
return user;
Expand Down Expand Up @@ -132,6 +131,7 @@ public User appleSignin(SigninRequestDto requestDto) throws JsonProcessingExcept
User user = userRepository.findByEmail(email).orElse(null);
if (user == null) {
log.info("애플 회원가입 시작");
fcmService.sendMessageToAdmins("⚠️관리자 알림: 애플 회원가입", "새로운 유저가 등록되었습니다. 총 유저 수: " + userRepository.count());
return appleSignup(email);
}
return user;
Expand Down Expand Up @@ -178,21 +178,6 @@ public String getAppleEmail(String authorizationCode) {
return payload.getEmail();
}

// private String generateClientSecret() {
//
// LocalDateTime expiration = LocalDateTime.now().plusMinutes(5);
//
// return Jwts.builder()
// .setHeaderParam(JwsHeader.KEY_ID, appleProperties.getKeyId())
// .setIssuer(appleProperties.getTeamId())
// .setAudience(appleProperties.getAudience())
// .setSubject(appleProperties.getClientId())
// .setExpiration(Date.from(expiration.atZone(ZoneId.systemDefault()).toInstant()))
// .setIssuedAt(new Date())
// .signWith(getPrivateKey(), SignatureAlgorithm.ES256)
// .compact();
// }

public String createClientSecret() {

JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.ES256).keyID(appleProperties.getKeyId()).build();
Expand Down Expand Up @@ -239,21 +224,6 @@ public byte[] readPrivateKey() {
return content;
}

// private PrivateKey getPrivateKey() {
// Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
//
// try {
// byte[] privateKeyBytes = Base64.getDecoder().decode(appleProperties.getPrivateKey());
//
// PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(privateKeyBytes);
// return converter.getPrivateKey(privateKeyInfo);
// } catch (Exception e) {
// throw new RuntimeException("Error converting private key from String", e);
// }
// }


// TokenDecoder 메소드를 GetMemberInfoService 내부에 통합
private <T> T decodePayload(String token, Class<T> targetClass) {
String[] tokenParts = token.split("\\.");
Expand Down
23 changes: 16 additions & 7 deletions src/main/java/co/orange/ddanzi/service/common/FcmService.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,27 @@ public boolean sendMessageToUser(User user, FcmCase fcmCase, Order order) {
return true;
}

public boolean sendMessageToAdmin(FcmCase fcmCase) {
log.info("Sending FCM message to admin: {}", fcmCase.getTitle());
public boolean sendMessageToAdmin(User user, String title, String body) {
PushAlarm pushAlarm = pushAlarmRepository.findByUser(user).orElse(null);
if(pushAlarm == null)
return false;
String fcmToken = pushAlarm.getFcmToken();
firebaseUtils.sendAdminMessage(fcmToken, title, body);
alarmService.createAlarm(user, FcmCase.C1, null);
return true;
}

public boolean sendMessageToAdmins(String title, String body) {
log.info("Sending FCM message to admins: {}", title);
User sj = userRepository.findByEmail("[email protected]").orElse(null);
User jh = userRepository.findByEmail("[email protected]").orElse(null);
User sh = userRepository.findByEmail("[email protected]").orElse(null);
User ys = userRepository.findByEmail("[email protected]").orElse(null);

sendMessageToUser(sj, fcmCase, null);
sendMessageToUser(jh, fcmCase, null);
sendMessageToUser(sh, fcmCase, null);
sendMessageToUser(ys, fcmCase, null);
sendMessageToAdmin(sj, title, body);
sendMessageToAdmin(jh, title, body);
sendMessageToAdmin(sh, title, body);
sendMessageToAdmin(ys, title, body);
return true;
}

}

0 comments on commit c119106

Please sign in to comment.