카페24 프로모션
작성: seokjin8678카페24 프로모션은 셀러들이 주로 할인을 할때 “카페24 헤택” 기능을 이용하는데, 이를 다른 플랫폼에도 적용시키기 위한 기능입니다.
카페24 상품 조회 API를 사용해서 가져오는 상품의 가격은 혜택이 적용되지 않은 가격이 조회되므로, 직접 혜택을 조회하여, 혜택의 할인 공식을 적용해야 합니다.
또한 카페24 혜택에는 여러 유형이 존재하는데, 그 중 “기간할인” 혜택만 지원합니다. (이하 “혜택, 기간할인”을 프로모션이라 함)
프로모션은 전체상품을 대상으로 하거나, 특정상품, 상품분류를 대상으로 지정할 수 있습니다.
또한 원으로 할인하는 정액할인과 %로 할인하는 정량할인이 지원됩니다.
정액할인에는 “구매수량에 따라”, “구매수량에 관계없이”라는 조건이 붙는데, 빈티지 상품의 특성상 이는 무시됩니다.
정량할인에는 자릿수에 따른 절삭 설정이 존재합니다.
할인에 대한 계산식은 Cafe24PromotionSaleCalculator 클래스를 통해 구현되어 있습니다.
프로모션은 시작시간과 종료시간이 있으며, 시작시간이 지나면 할인이 진행되고, 종료시간이 지나면 할인이 종료됩니다.
프로모션은 1회용이 아니며, 진행중인 프로모션은 실시간으로 수정이 가능합니다.
또한 카페24에 새로운 상품이 추가되었을 때, 프로모션에 해당하는 상품이면 자동으로 할인이 적용됩니다.
하지만 우리측에서 실시간으로 카페24 프로모션에 대한 변경은 감지할 수 없기에 프로모션을 새로 적용해야 한다면 수동으로 사용자가 갱신을 해줘야 합니다.
이를 위해 도메인 클래스와 이를 통한 유즈케이스들이 존재합니다.
또한 특정 시점에 시작되고 종료되어야 하며, 외부 API 호출이 강제되므로 JobQueue에 강하게 의존합니다.
도메인 클래스
Section titled “도메인 클래스”Cafe24Promotion
Section titled “Cafe24Promotion”카페24 프로모션을 다른 채널에 전파하기 위해 존재하는 도메인 클래스입니다.
생명주기는 프로모션이 등록될때 생성되고, 프로모션이 끝난 뒤, 명시적으로 사용자가 삭제를 하면 소멸됩니다.
핵심 필드로는
- 카페24 혜택의 식별자인
benefitNo - 전파할 채널인
provider - 시작시간과 종료시간
startDate,endDate - 상태를 나타내는
state
가 존재하며
그 외 원활한 동기화 상태를 보장하기 위한 refreshCount, discount_* 필드들이 존재합니다.
또한 중복된 benefitNo, provider를 가질 수 없습니다.
Cafe24PromotionSnapshot
Section titled “Cafe24PromotionSnapshot”카페24 프로모션의 전파대상이 되는 productNo를 핵심 필드로 가지고 있습니다.
또한 원활한 동기화 상태를 보장하기 위한 refreshCount, propagated 필드가 존재합니다.
refreshCount 필드를 통해 프로모션의 할인대상이 변경될 때, 제외된 대상을 분별할 수 있습니다.
propagated 필드를 통해 가격을 외부로 전파할 때, 중복으로 가격을 전파하는 비효율을 방지합니다.
생명주기는 프로모션이 등록될때가 아닌, 시작될 때 생성되며, 프로모션이 끝나면 소멸됩니다.
또한 더이상 프로모션의 대상에 포함되지 않아도 소멸됩니다.
PromotionState
Section titled “PromotionState”프로모션의 진행 상태를 나타내는 Enum 입니다.
종류로는 다음과 같습니다.
- PENDING
- 프로모션이 아직 시작되기 전의 상태입니다.
- PROPAGATING
- 프로모션이 시작되었고 플랫폼에 가격을 전파중인 상태입니다.
- 정확히는 해당 시점에
Cafe24PromotionSnapshot이 생성됩니다.
- ACTIVATED
- 프로모션이 시작되었고 활성화된 상태입니다.
- DEACTIVATED
- 프로모션이 종료되었고 비활성화된 상태입니다.
- 해당 상태는 삭제만 가능합니다.
또한 상태 다이어그램으로 나타내면 다음과 같습니다.
stateDiagram-v2 [*] --> PENDING PENDING --> PROPAGATING PENDING --> DEACTIVATED PROPAGATING --> ACTIVATED ACTIVATED --> PROPAGATING ACTIVATED --> DEACTIVATED이후 유즈케이스를 통해 어떤 기능을 통해 상태가 변경되는지 설명합니다.
프로모션 조회
Section titled “프로모션 조회”프로모션을 생성하기 위해, 카페24 혜택을 조회합니다.
이때 기간이 지난 혜택은 조회할 필요가 없으므로, 제외됩니다.
프로모션 등록
Section titled “프로모션 등록”조회한 프로모션 중 원하는 프로모션을 선택하여 등록할 수 있습니다.
여기서 프로모션의 기간에 따라 3가지 분기로 나뉩니다.
프로모션이 시작 이전 (now < start_date)
Section titled “프로모션이 시작 이전 (now < start_date)”PENDING 상태로 Cafe24Promotion 객체를 영속하고, 프로모션의 startDate, endDate를 기준으로 프로모션을 활성화하고
비활성화하는 JobQueue를 예약시킵니다.
프로모션이 시작 (now >= start_date && now < end_date)
Section titled “프로모션이 시작 (now >= start_date && now < end_date)”마찬가지로 PENDING 상태로 Cafe24Promotion 객체를 영속하며, 다른점은 프로모션을 활성화하는 JobQueue를 예약시키지 않고 바로 대기시킵니다. (
비활성화는 예약)
프로모션이 종료 (now >= end_date)
Section titled “프로모션이 종료 (now >= end_date)”이미 프로모션이 종료되었으므로, 아무것도 하지 않고 DEACTIVATED로 변경합니다.
프로모션을 조회할 시점에 종료한 프로모션은 조회하지 않기에 예외라고 볼 수 있으나, 재등록하는 유즈케이스가 존재하므로 일반적인 유즈케이스라 볼 수 있습니다.
프로모션 활성화, 비활성화 하는 JobQueue를 등록할 때 refreshCount를 같이 넘기는데, 이는 프로모션을 새롭게 갱신했을 때, 기간이 변경되거나 대상이
변경되었음을 반영하기 위함입니다.
따라서 Job Payload의 refreshCount와 프로모션의 refreshCount 필드가 다르면 실행하지 않고 바로 종료합니다.
프로모션 재갱신
Section titled “프로모션 재갱신”개요에서 설명했듯, 카페24 프로모션은 실시간으로 수정할 수 있습니다.
따라서 수정된 프로모션을 반영하기 위한 유즈케이스 입니다.
프로모션은 3개의 주요 변경사항이 있습니다.
- 기간 변경
- 할인대상 변경
- 힐인 변경
만약 상태가 아직 PENDING이면 외부로 전파가 되지 않았으므로, 기간이 변경된 경우에만 프로모션 등록 유즈케이스를 재사용하면 됩니다.
하지만 이미 외부에 가격이 전파된 경우 위 3개 변경에 대해 재갱신을 하는 작업이 필요합니다.
또한 재갱신을 수행하면 Cafe24Promotion의 refreshCount를 1 증가 시킵니다.
- 프로모션 시작 이전
전파된 가격을 모두 되돌리고, PENDING 상태로 되돌린 뒤, 새로운 시간으로 JobQueue를 발행해야 합니다.
일반적으로 발생되는 유즈케이스는 아니기 때문에 아무 행동도 하지 않도록 구현되었습니다.
- 프로모션 종료 이후
전파된 가격을 모두 되돌리고, DEACTIVATED 상태로 변경합니다.
일반적으로 발생되는 유즈케이스는 아니기 때문에 아무 행동도 하지 않도록 구현되었습니다.
- 프로모션 종료시간 연장
프로모션 비활성화 Job을 새로운 종료 시간 시점으로 예약합니다.
이후 이전에 예약된 Job은 refreshCount가 달라짐으로 실행되지 않고, 새롭게 예약한 Job이 최종적으로 실행되도록 합니다.
할인대상 변경
Section titled “할인대상 변경”- 할인대상 추가
기존 영속된 Cafe24PromotionSnapshot에 존재하지 않는 대상이며, 새로운 Cafe24PromotionSnapshot으로 만들어 영속합니다.
- 할인대상 제외
기존 영속된 Cafe24PromotionSnapshot이 대상에 존재하지 않는 목록을 통해 제외된 목록을 알 수 있습니다.
이 경우 Cafe24PromotionSnapshot에 refreshCount를 새롭게 갱신하지 않습니다.
refreshCount가 갱신되지 않은 Cafe24PromotionSnapshot은 이후 소멸 + 가격 복구 대상이 됩니다.
(snapshot.refreshCount != promotion.refreshCount)
- 기존 할인대상
기존 할인대상은 Cafe24PromotionSnapshot에 refreshCount를 새롭게 갱신합니다.
할인이 변경되면 모든 Cafe24PromotionSnapshot의 propagated 상태를 false로 변경합니다.
프로모션 종료
Section titled “프로모션 종료”진행중인 프로모션을 종료합니다.
이후 가격이 복구되면 DEACTIVATED 상태로 변경합니다.
프로모션 삭제
Section titled “프로모션 삭제”PENDING. DEACTIVATED 상태의 프로모션을 삭제합니다.
JobQueue
Section titled “JobQueue”주요 JobQueue는 4가지 종류가 있습니다.
- Cafe24PromotionActivateJob
- Cafe24PromotionPricePropagationJob
- Cafe24PromotionDeactivateJob
- Cafe24PromotionRefreshJob
Job에 대한 의존 관계는 다음과 같습니다.
flowchart TD
%% Activate Flow A[Cafe24PromotionActivateJob] --> B[Cafe24PromotionPricePropagationJob] B --> C{Snapshots가 마지막 페이지인가?} C -- 아니오 --> B C -- 예 --> D[종료]%% Deactivate Flow E[Cafe24PromotionDeactivateJob] --> F[종료]%% Refresh Flow G[Cafe24PromotionRefreshJob] --> H[Cafe24PromotionPricePropagationJob] H --> I{Snapshots가 마지막 페이지인가?} I -- 아니오 --> H I -- 예 --> J[종료]Cafe24PromotionActivateJob
Section titled “Cafe24PromotionActivateJob”프로모션 등록 유즈케이스에서 예약 또는 발행됩니다.
해당 Job은 프로모션의 생명주기 동안 단 한 번만 실행됩니다.
또한 처음으로 Cafe24PromotionSnapshot 객체를 영속합니다.
상태를 PROPAGATING으로 만들고 Cafe24PromotionPricePropagationJob를 발행하고 종료합니다.
Cafe24PromotionPricePropagationJob
Section titled “Cafe24PromotionPricePropagationJob”Cafe24PromotionActivateJob 또는 프로모션 재갱신 유즈케이스가 실행되면 발행됩니다.
발행 시점의 할인을 사용하기 위해 Payload에 할인에 대한 정보를 가지고 있습니다.
커서 기반 페이징을 통해 Cafe24PromotionSnapshot을 조회하고, 외부로 가격을 전파, 롤백합니다.
만약 조회한 결과가 마지막이면 프로모션을 ACTIVATED 상태로 변경하고 Job을 종료합니다.
외부 API 실패 시 실패 지점만 재시도를 위해 Job에서 같은 Job을 발행하는 구조로 되어 있습니다.
Cafe24PromotionDeactivateJob
Section titled “Cafe24PromotionDeactivateJob”프로모션 등록, 프로모션 종료 유즈케이스에서 예약 또는 발행됩니다.
커서 기반 페이징을 통해 Cafe24PromotionSnapshot을 조회하고, 외부로 가격을 롤백합니다.
외부 API 실패 시 실패 지점만 재시도를 위해 Job에서 같은 Job을 발행하는 구조로 되어 있습니다.
Cafe24PromotionRefreshJob
Section titled “Cafe24PromotionRefreshJob”프로모션 재갱신 유즈케이스에서 발행됩니다.
해당 Job에서 카페24 프로모션의 변경사항에 대한 처리를 수행합니다.
상태를 PROPAGATING으로 만들고 Cafe24PromotionPricePropagationJob를 발행하고 종료합니다.