๐Ÿ–ฅ๏ธ TurtleMartํ”„๋กœ์ ํŠธ/โœ๏ธ TIL

[TIL] ํ”„๋กœ์ ํŠธ 18์ผ์ฐจ.. ์Šฌ๋ž™ ์•Œ๋ฆผ ๋งˆ๋ฌด๋ฆฌํ•˜๊ธฐ!!

carrot0911 2025. 6. 5. 22:04

๐ŸŒž ์˜ค๋Š˜์€ ์–ด๋–ค ํ•˜๋ฃจ์˜€์ง€..

์šฐ์„  ์žฌ๊ณ  ๊ฐ์†Œ ์‹คํŒจ ๊ด€๋ จ Slack ์•Œ๋ฆผ์„ ๋งˆ๋ฌด๋ฆฌํ–ˆ๋‹ค!

// ์žฌ๊ณ  ๊ฐ์†Œ ์‹คํŒจ ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ
public String formatInventoryDecreaseFailureMessage(Long orderId, String memberName, String productId, String productName, String reason, LocalDateTime time) {
    Map<String, Object> payload = getPayload();
    List<Object> blocks = new ArrayList<>();

    blocks.add(Map.of(
        "type", "header",
        "text", Map.of("type", "plain_text", "text", "โŒ ์žฌ๊ณ  ๊ฐ์†Œ ์‹คํŒจ ์•Œ๋ฆผ")
    ));

    blocks.add(Map.of(
        "type", "section",
        "fields", List.of(
            markdownField("*์ฃผ๋ฌธ ID:*", orderId.toString()),
            markdownField("*ํšŒ์›๋ช…:*", memberName)
        )
    ));

    blocks.add(Map.of(
        "type", "section",
        "fields", List.of(
            markdownField("*์ƒํ’ˆ ID:*", productId),
            markdownField("*์ƒํ’ˆ๋ช…:*", productName)
        )
    ));

    blocks.add(Map.of(
        "type", "section",
        "text", markdownField("*\uD83D\uDD0D ์‚ฌ์œ :*", reason)
    ));

    blocks.add(Map.of(
        "type", "context",
        "elements", List.of(
            Map.of("type", "mrkdwn", "text", "\uD83D\uDD52 *์‹œ๊ฐ„:* " + time.format(formatter))
        )
    ));

    payload.put("blocks", blocks);

    return JsonHelper.toJson(payload);
}
public void sendInventoryDecreaseFailureAlert(Long orderId, String memberName, String productId, String productName, String reason) {
    String message = slackFormatter.formatInventoryDecreaseFailureMessage(orderId, memberName, productId, productName, reason, LocalDateTime.now());

    sendPayload(message);
}
@Transactional
public void decreaseProductOptionCombinationInventory(Long orderId) {
    List<OrderItem> orderItemList = orderItemRepository.findAllByOrderId(orderId);

    for (OrderItem orderItem : orderItemList) {
        Long productOptionCombinationId = orderItem.getProductOptionCombination().getId();
        Integer quantity = orderItem.getQuantity();

        ProductOptionCombination productOptionCombination = productOptionCombinationRepository
            .findByIdWithPessimisticLock(productOptionCombinationId)
            .orElseThrow(() -> new NotFoundException(ErrorCode.PRODUCT_OPTION_COMBINATION_NOT_FOUND));

        if (productOptionCombination.getInventory() < quantity) {
            slackNotifier.sendInventoryDecreaseFailureAlert(
                orderId,
                orderItem.getOrder().getMember().getName(),
                productOptionCombination.getProduct().getId().toString(),
                productOptionCombination.getProduct().getName(),
                ErrorCode.PRODUCT_OPTION_COMBINATION_OUT_OF_INVENTORY.getMessage());

            throw new ConflictException(ErrorCode.PRODUCT_OPTION_COMBINATION_OUT_OF_INVENTORY);
        }

        productOptionCombination.decreaseInventory(quantity);
    }
}

์žฌ๊ณ  ๊ฐ์†Œ ์‹คํŒจ Slack ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€

์ •์ƒ์ ์œผ๋กœ ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€๊ฐ€ ๋„์ฐฉํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค!

๊ทธ๋‹ค์Œ์œผ๋กœ๋Š” ๋ฐฐ์†ก ์ƒ์„ฑ ์„ฑ๊ณตํ–ˆ์„ ๋•Œ Slack ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€๊ฐ€ ๋„์ฐฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.

// ๋ฐฐ์†ก ์ƒ์„ฑ ์„ฑ๊ณต ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ
public String formatDeliveryCreateMessage(Long orderId, String memberName, String phoneNumber, String receiver, String receiverPhone, String address, String detailAddress, LocalDateTime time) {
    Map<String, Object> payload = getPayload();
    List<Object> blocks = new ArrayList<>();

    blocks.add(Map.of(
        "type", "header",
        "text", Map.of("type", "plain_text", "text", "โœ… ๋ฐฐ์†ก ์ƒ์„ฑ ์„ฑ๊ณต ์•Œ๋ฆผ")
    ));

    blocks.add(Map.of(
        "type", "section",
        "fields", List.of(
            markdownField("*์ฃผ๋ฌธ ID:*", orderId.toString())
        )
    ));

    blocks.add(Map.of(
        "type", "section",
        "fields", List.of(
            markdownField("*ํšŒ์›๋ช…:*", memberName),
            markdownField("*์—ฐ๋ฝ์ฒ˜:*", phoneNumber)
        )
    ));

    blocks.add(Map.of(
        "type", "section",
        "fields", List.of(
            markdownField("*์ˆ˜๋ น์ธ:*", receiver),
            markdownField("*์ˆ˜๋ น์ธ ์—ฐ๋ฝ์ฒ˜:*", receiverPhone),
            markdownField("*์ฃผ์†Œ:*", address),
            markdownField("*์ƒ์„ธ์ฃผ์†Œ:*", detailAddress)
        )
    ));

    blocks.add(Map.of(
        "type", "section",
        "fields", List.of(
            markdownField("*์ƒํƒœ:*", "๋ฐฐ์†ก ์ƒ์„ฑ ์™„๋ฃŒ โœ…")
        )
    ));

    blocks.add(Map.of(
        "type", "context",
        "elements", List.of(
            Map.of("type", "mrkdwn", "text", "\uD83D\uDCE6 ๋ฐฐ์†ก ์ •๋ณด๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n"),
            Map.of("type", "mrkdwn", "text", "\uD83D\uDD52 *์‹œ๊ฐ„:* " + time.format(formatter))
        )
    ));

    payload.put("blocks", blocks);

    return JsonHelper.toJson(payload);
}
public void sendDeliveryCreateAlert(Long orderId, String memberName, String phoneNumber, String receiver, String receiverPhone, String address, String detailAddress) {
    String message = slackFormatter.formatDeliveryCreateMessage(orderId, memberName, phoneNumber, receiver, receiverPhone, address, detailAddress, LocalDateTime.now());

    sendPayload(message);
}
@Transactional
public CreateDeliveryResponse createDelivery(CreateDeliveryRequest request) {
    if (!orderRepository.existsById(request.orderId())) {
        throw new NotFoundException(ErrorCode.ORDER_NOT_FOUND);
    }
    if (!sellerRepository.existsById(request.sellerId())) {
        throw new NotFoundException(ErrorCode.SELLER_NOT_FOUND);
    }
    if (!senderRepository.existsById(request.senderId())) {
        throw new NotFoundException(ErrorCode.SENDER_NOT_FOUND);
    }
    if (!addressRepository.existsById(request.addressId())) {
        throw new NotFoundException(ErrorCode.ADDRESS_NOT_FOUND);
    }
    Order order = orderRepository.getReferenceById(request.orderId());
    Seller seller = sellerRepository.getReferenceById(request.sellerId());
    Sender sender = senderRepository.getReferenceById(request.senderId());

    Address address = addressRepository.findById(request.addressId())
        .orElseThrow(() -> new NotFoundException(ErrorCode.ADDRESS_NOT_FOUND));

    Delivery delivery = Delivery.of(order, seller, sender, address, request.deliveryRequest());

    deliveryRepository.save(delivery);

    slackNotifier.sendDeliveryCreateAlert(
        request.orderId(),
        delivery.getOrder().getMember().getName(),
        delivery.getOrder().getMember().getPhoneNumber(),
        delivery.getReceiverName(),
        delivery.getReceiverPhone(),
        delivery.getReceiverAddress(),
        delivery.getReceiverDetailAddress());

    return CreateDeliveryResponse.from(delivery);
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Slack ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€๊ฐ€ ์–ด๋–ป๊ฒŒ ์˜ค๋А๋ƒ?!

๋ฐฐ์†ก ์ƒ์„ฑ ์„ฑ๊ณต Slack ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€

๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐฐ์†ก ์ƒ์„ฑ ์‹คํŒจํ–ˆ์„ ๋•Œ ๊ด€๋ จํ•ด์„œ Slack ์•Œ๋ฆผ์„ ๊ณ ๋ฏผํ–ˆ๋‹ค.
์ •๋ณด ํ•„์š” ์—†์ด ์˜ˆ์™ธ ๊ด€๋ จ ๋‚ด์šฉ๋งŒ ๋ฉ”์‹œ์ง€๋กœ ๋ณด์—ฌ์ฃผ๋ฉด ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๊ณ , ๊ทธ๋ ‡๊ฒŒ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ ์ •์ž‘ ์‹คํ–‰ํ•ด์„œ ํ…Œ์ŠคํŠธํ•ด ๋ณด๋‹ˆ Kafka์˜ ์žฌ์‹œ๋„๋กœ ์ธํ•ด์„œ ๋ฉ”์‹œ์ง€๊ฐ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋งŒํผ ์ „์†ก๋˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค......

๊ทธ๋ž˜์„œ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š๊ณ  Slack ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€ ํ•œ ๋ฒˆ๋งŒ ์ „์†กํ•  ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •ํ–ˆ๊ณ  ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ฉ”์‹œ์ง€๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ์ „์†ก๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

๐Ÿ—“๏ธ ๋‚ด์ผ์€ ๋ญ ํ•˜์ง€?!

โœ”๏ธ ํ”„๋กœ์ ํŠธ ๊ณ ๋„ํ™”
โœ”๏ธ ๋กœ์ง ๋‚ด ๋ฌธ์ œ์  ์ˆ˜์ •
โœ”๏ธ TIL ์ž‘์„ฑํ•˜๊ธฐ