할인 앱 가이드

개요

"쉽고 빠르게" 할인 앱 제작하기

  • 본 가이드는 할인 앱(App) 을 손쉽게 제작할 수 있도록 개발 프로세스와 동작 구조를 설명합니다.
  • 더하여 간단한 할인 앱 예시를 통해 데이터 및 래퍼런스 제공하므로써 누구나 빠르게 제작이 가능합니다.
  • 가이드를 통해 할인 앱(App) 제작을 시작해 보세요. 언제나 카페24 앱 제작 지원팀이 개발과정의 어려운 부분을 지원하고 있습니다.

앱 개발 기본정보

앱(App) 등록에서 검수까지의 사전 준비작업은 아래의 링크를 참조하시기 바랍니다.

앱 동작 구조

  • 제작된 앱(App)의 스크립트(script)는 카페24 쇼핑몰의 장바구니/주문서에 삽입되어 할인에 필요한 기본 정보를 획득합니다.
  • 카페24 쇼핑몰의 할인 반영 기준은 크게 상품 할인과 주문 할인으로 구분되며 앱(App)별 로직에 따라 산정된 할인금액을 아래 규약에 따라 callback함수로 전달하고 있습니다.
  • 카페24 쇼핑몰은 전달된 할인금액에 대한 검증을 진행하고 실결제금액에 반영합니다.

카페24와 앱 사이의 동작 예를 나타낸 시퀀스 다이어그램

동작 프로세스

프로세스
순서 프로세스 내용 참고
1 카페24 Front Api 호출
  • 카페24에서 제공 하는 Front API를 활용하면 쇼핑몰과 회원의 기본 정보를 획득 할 수 있습니다.
    • 쇼핑몰ID, 멀티샵 번호, 회원 아이디, 게스트 키 등 기본정보 획득
  • Front API와 전역변수는 window.onload가 완료 되었을 때 사용하여야 합니다.
    • window.onload가 완료되기 전에는 해당 변수에 값이 완전하지 않을 수 있습니다.
2 할인 및 HMAC
  • 획득한 정보를 토대로 다양한 할인을 구현합니다.
  • 필수 조건 : hmac 암호화 키를 발행 후 평문데이터와 함께 응답 본문에 추가합니다.
  • Cross Domain 이슈 회피를 위해 Response Header에 ("Access-Control-Allow-Origin", "*")를 추가합니다.
  • 앱에서 할인 로직 수행시 마다 카페24의 API 호출을 엄격히 금합니다.
  • 앱할인 로직 구현시 카페24의 API 호출이 발견될 경우 심사를 통과하지 못할 수도 있습니다.
3 할인 적용
  • 응답 데이터는 카페24 장바구니/주문서의 Javascript callback함수(AppDiscount.setAppDiscountPrice(result);)를 호출하여 할인 결과를 화면에 노출합니다.
  • JS function / API를 통하여 원하는 디자인/후속 기능을 다양하게 추가할 수 있습니다.
  • result는 JSON.stringify()을 통하여 json 문자열로 변환하여 사용하여야 정상 동작합니다.

JSON.stringify() 바로가기

스펙 및 샘플 데이터

1. 카페24 장바구니/주문서 상품정보

  1.    a. 장바구니와 주문서의 주문/상품 정보의 변수는 꼭 구분하여 사용해야 합니다.
  2.    b. 장바구니와 주문서에서만 제공하는 Javascript 전역 변수
상세설명
변수명 타입 역할 sample data
sPage string 장바구니("ORDER_BASKET") / 주문서("ORDER_ORDERFORM")를 구분
var sPage
"ORDER_BASKET";//장바구니 일때
"ORDER_ORDERFORM"; //주문서 일때
aBasketProductData array 장바구니의 상품정보
var aBasketProductData
[
  {
    "delvtype": "A",
    "main_cate_no": 1,
    "product_no": 21,
    "opt_id": "000A",
    "product_type": "normal_type",
    "naver_used_exception": "F",
    "product_qty": 1,
    "quantity": 1,
    "check_quantity": 1,
    "check_quantity_type": "O",
    "option_add": "F",
    "product_min": 1,
    "product_max_type": "F",
    "product_max": 0,
    "product_code": "P000000V",
    "product_price": 10000,
    "opt_price": 0,
    "product_sum_price": 10000,
    "product_sale_price": 10000,
    "product_name": "상품A",
    "opt_str": "",
    "item_code": "P000000V000A",
    "option_type": "T",
    "has_option": "F",
    "has_option_add": "F",
    "is_set_product": "F",
    "set_product_name": "",
    "set_product_no": 0,
    "basket_prd_no": 101,
    "item_listing_type": "C",
    "is_oversea_able": true,
    "set_product_list": null,
    "buy_unit": 1,
    "check_buy_unit_type": "O",
    "wish_selected_item": "",
    "wish_save_data": "",
    "olink_data": "",
    "product_paymethod": "cash,mileage",
    "option_attached_file_info_json": "",
    "total_unit_add_sale": 0,
    "use_store_pickup": "F",
    "layer_option_str": null,
    "sIsBenefitEventProduct": "F",
    "check_buy_unit": 1
  }
];
aBasketProductOrderData array 주문서의 상품정보
var aBasketProductOrderData
[
  {
    "product_qty": 1,
    "quantity": 1,
    "product_sum_price": 10000,
    "option_add": "F",
    "option_type": "T",
    "set_product_no": 0,
    "basket_prd_no": 101,
    "product_no": 21,
    "item_code": "P000000V000A",
    "product_price": 10000,
    "opt_price": 0,
    "product_sale_price": 10000
  }
];

2. HMAC 스펙

  •    a. base64_encode(hash_hmac('sha256', 평문데이터, Service_key, true));
  •    b. 알고리즘은 'sha256'을 사용합니다.
  •    c. Service_key는 개발자센터에서 발급 받은 Service_key를 사용합니다.
  •    d. Service_key는 할인/결제에 관련된 무결성 검증을 위한 값으로 절대 외부에 노출 되어서는 안됩니다.
  •    e. Service_key가 노출 되었거나 노출이 의심되는경우 개발자센터에서 재발급하여 사용하시기 바랍니다.
  •    f. guest_key 값은 회원 : md5(member_id), 비회원 : EC_GUEST_KEY를 사용합니다.
  •    g. HMAC 추가요령
    •       - guest_key 값은 평문 데이터 제일 뒤에 위치해야 합니다.
    •       - guest_key값은 hmac으로 암호화한 후 평문데이터에서 삭제합니다.
    •       - 평문데이터 제일 뒤에 hmac값을 추가합니다.

3. 카페24 장바구니/주문서 callback 함수의 요청 스펙

   a. 파라미터1, 2, 3은 스펙에 Depth를 나타냅니다.

상세설명
파라미터1 파라미터2 파라미터3 용도 타입
mall_id 쇼핑몰ID string
shop_no 멀티샵 번호 string
member_id 회원ID string
member_group_no 회원그룹 string
product_discount 할인 상품 정보 array
basket_prd_no 장바구니 번호 string
product_no 상품번호 string
item_code 상품코드 string
product_qty 수량 string
product_price 상품 금액 string
opt_price 옵션 금액 string
product_sale_price 상품 할인 적용 금액 string
discount_price 상품 할인 금액 string
app_discount_info 적용 된 할인 고유번호 리스트 string[]
order_discount 주문 할인 정보 array
no 할인 고유번호 string
price 상품 할인 금액 string
apply_product 할인 적용 상품 코드 string
app_discount_info 할인의 상세 정보 array
no 할인 고유번호 string
type 할인 타입 string
name 할인명 string
icon 할인 아이콘 string
config 할인 설정 object
string
value 할인 금액 string
value_type 할인 타입(W:정액, P:정률) string
time 할인 요청 string
trace_no 추적번호
  • - transaction별 key 값
  • - app에서 생성
string
app_key app_key string
hmac 암호화 정보 hmac 암호화 정보 string

Sample Data

var result
{
 "mall_id": "cafe24_mall",
 "shop_no": 1,
 "member_id": "",
 "member_group_no": 0,
 "product_discount": [
 {
 "basket_prd_no": 87,
 "product_no": 20,
 "item_code": "P000000U000A",
 "product_qty": 1,
 "product_price": 10000,
 "opt_price": 0,
 "product_sale_price": 10000,
 "discount_price": 0,
 "app_discount_info": []
 },
 {
 "basket_prd_no": 87,
 "product_no": 21,
 "item_code": "P000000U000B",
 "product_qty": 1,
 "product_price": 20000,
 "opt_price": 0,
 "product_sale_price": 20000,
 "discount_price": 0,
 "app_discount_info": []
 }
 ],
 "order_discount": [
 {
 "no": "200",
 "price": "1000",
 "apply_product": "P000000U000A,P000000U000B"
 }
 ],
 "app_discount_info": [
 {
 "no": 200,
 "type": "O",
 "name": "FRIDAY_DISCOUNT",
 "icon": "http://placehold.it/32x32",
 "config": {
 "value": 1000,
 "value_type": "W"
 }
 }
 ],
 "time": "1536672695",
 "trace_no": "20180911223134Qkgj54",
 "app_key": "9M0gI35ANt7gDicnD02u8D",
 "hmac": "eOEafN86qA4zh49BkjUAhlB3zF5CqVruBNpS46QTVVs="
}
  • 아래의 그림은 기본 흐름에 데이터와 호출, 응답 데이터를 추가한 내용입니다.
  • 각 중요 포인트를 클릭하시면 상세 가이드로 연결됩니다.

샘플 코드

  • 다음은 앱(App)에서 산정된 할인금액의 로직이 반영되는 예시입니다.
  • 예시를 바탕으로 작성된 샘플코드를 확인할 수 있습니다.

할인 예시: 매주 금요일 1,000원 주문 할인

Front-end

app.js
//App의 할인 로직 호출
function app_do_sale(params){
    $.ajax({
        url: "https://example.com/sale",
        dataType: "json",
        method: "POST",
        data: {
            'mall_id': params.ec_mall_id
            , 'shop_no': params.shop_no
            , 'member_id': params.member_id
            , 'guest_key': params.guest_key
            , 'member_group_no': params.group_no
            , 'product': JSON.stringify(params.orderInfos)
            , 'time':  Math.ceil(new Date().getTime() / 1000)
        },
        success: function (result) {
            console.log('SALE success!');
            AppDiscount.setAppDiscountPrice(JSON.stringify(result));
        }, error: function (e) {
            console.log('SALE error!');
        }
    });
}

//기본 정보 및 상품정보 세팅
var app_init_sale = function () {
    var app_req_params = {};
    var orderInfos;

    if (sPage == 'ORDER_BASKET')  //장바구니 일때
        orderInfos = aBasketProductData;
    else if (sPage == 'ORDER_ORDERFORM')    //주문서 일때
        orderInfos = aBasketProductOrderData;

    if (orderInfos.length <= 0) return;

    app_req_params.orderInfos = orderInfos;

    //CAFE24FrontAPI 활용 기본정보 조회
    (function(CAFE24API) {
        app_req_params.ec_mall_id = CAFE24API.MALL_ID;
        app_req_params.shop_no = CAFE24API.SHOP_NO;

        // 회원정보 조회
        CAFE24API.getMemberInfo(function (data) {
            app_req_params.member_id = data.id.member_id;
            app_req_params.group_no = Number(data.id.group_no);

            if (app_req_params.member_id == null)
                app_req_params.guest_key = data.id.guest_id;

            app_do_sale(app_req_params);
        });
    })(CAFE24API.init("CAFE24에서 발급받은 APP_KEY"));

};

//window.onload 확인 후 이벤트 리스너에 등록
if (document.readyState == 'complete') {
    app_init_sale();
}  else {
    window.addEventListener('load', app_init_sale);
}

Data

요청 데이터 (var params)
{
 "mall_id": "cafe24_mall",
 "shop_no": "1",
 "member_id": "",
 "guest_key": "9f2c9a3cb0c04a4ff394596ebb23f5cc",
 "member_group_no": "0",
 "time": "1536672695",
 "product": [
 {
 "product_qty": 1,
 "product_no": 20,
 "product_price": 10000,
 "product_sale_price": 100000,
 "opt_price": 0,
 "product_name": "상품A",
 "basket_prd_no": 87,
 "item_code": "P000000U000A"
 },
 {
 "product_qty": 1,
 "product_no": 21,
 "product_price": 20000,
 "product_sale_price": 20000,
 "opt_price": 0,
 "product_name": "상품B",
 "basket_prd_no": 87,
 "item_code": "P000000U000B"
 }
 ]
};
응답 데이터 (var result)
{
 "mall_id": "cafe24_mall",
 "shop_no": 1,
 "member_id": "",
 "member_group_no": 0,
 "product_discount": [
 {
 "basket_prd_no": 87,
 "product_no": 20,
 "item_code": "P000000U000A",
 "product_qty": 1,
 "product_price": 10000,
 "opt_price": 0,
 "product_sale_price": 10000,
 "discount_price": 0,
 "app_discount_info": []
 },
 {
 "basket_prd_no": 87,
 "product_no": 21,
 "item_code": "P000000U000B",
 "product_qty": 1,
 "product_price": 20000,
 "opt_price": 0,
 "product_sale_price": 20000,
 "discount_price": 0,
 "app_discount_info": []
 }
 ],
 "order_discount": [
 {
 "no": "200",
 "price": "1000",
 "apply_product": "P000000U000A,P000000U000B"
 }
 ],
 "app_discount_info": [
 {
 "no": 200,
 "type": "O",
 "name": "FRIDAY_DISCOUNT",
 "icon": "http://placehold.it/32x32",
 "config": {
 "value": 1000,
 "value_type": "W"
 }
 }
 ],
 "time": "1536672695",
 "trace_no": "20180911223134Qkgj54",
 "app_key": "9M0gI35ANt7gDicnD02u8D",
 "hmac": "eOEafN86qA4zh49BkjUAhlB3zF5CqVruBNpS46QTVVs="
}

Back-end

https://example.com/sale
public String orderSale(@RequestParam OrderVo orderInfo, HttpServletResponse res) {
    //크로스 도메인 이슈 회피를 위해 필수
    res.addHeader("Access-Control-Allow-Origin", "*");

    Gson gson = new Gson();
    String trace_no = makeTrace_no();

    LinkedHashMap respOrderMap = saleService.doSale(orderInfo, trace_no);

    if (orderInfo.getMember_id() != null && !orderInfo.getMember_id().isEmpty())
        respOrderMap.put("guest_key", saleService.getEncMD5(orderInfo.getMember_id()));
    else
        respOrderMap.put("guest_key", orderInfo.getGuest_key());

    respOrderMap.put("hmac", saleService.getHmac(respOrderMap));
    respOrderMap.remove("guest_key");

    log.info("[" + trace_no + "]" + "response_params : " + respOrderMap.toString());

    return gson.toJson(respOrderMap);
}

Data

요청데이터 (OrderVo orderInfo)
{
 "mall_id": "cafe24_mall",
 "shop_no": "1",
 "member_id": "",
 "guest_key": "9f2c9a3cb0c04a4ff394596ebb23f5cc",
 "member_group_no": "0",
 "time": "1536672695",
 "product": [
 {
 "product_qty": 1,
 "product_no": 20,
 "product_price": 10000,
 "product_sale_price": 100000,
 "opt_price": 0,
 "product_name": "상품A",
 "basket_prd_no": 87,
 "item_code": "P000000U000A"
 },
 {
 "product_qty": 1,
 "product_no": 21,
 "product_price": 20000,
 "product_sale_price": 20000,
 "opt_price": 0,
 "product_name": "상품B",
 "basket_prd_no": 87,
 "item_code": "P000000U000B"
 }
 ]
};
응답 데이터 (LinkedHashMap respOrderMap)
{
 "mall_id": "cafe24_mall",
 "shop_no": 1,
 "member_id": "",
 "member_group_no": 0,
 "product_discount": [
 {
 "basket_prd_no": 87,
 "product_no": 20,
 "item_code": "P000000U000A",
 "product_qty": 1,
 "product_price": 10000,
 "opt_price": 0,
 "product_sale_price": 10000,
 "discount_price": 0,
 "app_discount_info": []
 },
 {
 "basket_prd_no": 87,
 "product_no": 21,
 "item_code": "P000000U000B",
 "product_qty": 1,
 "product_price": 20000,
 "opt_price": 0,
 "product_sale_price": 20000,
 "discount_price": 0,
 "app_discount_info": []
 }
 ],
 "order_discount": [
 {
 "no": "200",
 "price": "1000",
 "apply_product": "P000000U000A,P000000U000B"
 }
 ],
 "app_discount_info": [
 {
 "no": 200,
 "type": "O",
 "name": "FRIDAY_DISCOUNT",
 "icon": "http://placehold.it/32x32",
 "config": {
 "value": 1000,
 "value_type": "W"
 }
 }
 ],
 "time": "1536672695",
 "trace_no": "20180911223134Qkgj54",
 "app_key": "9M0gI35ANt7gDicnD02u8D",
 "hmac": "eOEafN86qA4zh49BkjUAhlB3zF5CqVruBNpS46QTVVs="
}

Back-end

getDiscountAmount
public double getDiscountAmount() {

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(new Date());
    int day_num = calendar.get(Calendar.DAY_OF_WEEK);
    double discount_amount = 0;

    if (day_num == 6) {
        discount_amount = 1000;
    }

    return discount_amount;
}

Back-end

HMAC
private String makeHmac(String plainText) {
    log.info("[" + trace_no + "]" + "makeHmac plainText : " + plainText);

    String CypHmac = "";

    try {
        Mac mac = Mac.getInstance(Const.algorithm);
        mac.init(new SecretKeySpec(Const.app_secret_key.getBytes(), Const.algorithm));
        mac.update(plainText.getBytes(Const.character_set));

        CypHmac = Base64.encodeBase64String(mac.doFinal());
    } catch (UnsupportedEncodingException | NoSuchAlgorithmException | InvalidKeyException e) {
        e.printStackTrace();
    }

    log.info("[" + trace_no + "]" + "CypHmac : " + CypHmac);

    return CypHmac;
}

Data

요청데이터 (plainText)
{ "mall_id": "cafe24_mall",
 "shop_no": 1,
 "member_id": "",
 "member_group_no": 0,
 "product_discount": [
 {
 "basket_prd_no": 87,
 "product_no": 20,
 "item_code": "P000000U000A",
 "product_qty": 1,
 "product_price": 10000,
 "opt_price": 0,
 "product_sale_price": 10000,
 "discount_price": 0,
 "app_discount_info": []
 },
 {
 "basket_prd_no": 87,
 "product_no": 21,
 "item_code": "P000000U000B",
 "product_qty": 1,
 "product_price": 20000,
 "opt_price": 0,
 "product_sale_price": 20000,
 "discount_price": 0,
 "app_discount_info": []
 }
 ],
 "order_discount": [
 {
 "no": "200",
 "price": "1000",
 "apply_product": "P000000U000A,P000000U000B"
 }
 ],
 "app_discount_info": [
 {
 "no": 200,
 "type": "O",
 "name": "FRIDAY_DISCOUNT",
 "icon": "http://placehold.it/32x32",
 "config": {
 "value": 1000,
 "value_type": "W"
 }
 }
 ],
 "time": "1536672695",
 "trace_no": "20180911223134Qkgj54",
 "app_key": "9M0gI35ANt7gDicnD02u8D",
 "guest_key": "9f2c9a3cb0c04a4ff394596ebb23f5cc"
}
응답 데이터 (plainText)
{ "mall_id": "cafe24_mall",
 "shop_no": 1,
 "member_id": "",
 "member_group_no": 0,
 "product_discount": [
 {
 "basket_prd_no": 87,
 "product_no": 20,
 "item_code": "P000000U000A",
 "product_qty": 1,
 "product_price": 10000,
 "opt_price": 0,
 "product_sale_price": 10000,
 "discount_price": 0,
 "app_discount_info": []
 },
 {
 "basket_prd_no": 87,
 "product_no": 21,
 "item_code": "P000000U000B",
 "product_qty": 1,
 "product_price": 20000,
 "opt_price": 0,
 "product_sale_price": 20000,
 "discount_price": 0,
 "app_discount_info": []
 }
 ],
 "order_discount": [
 {
 "no": "200",
 "price": "1000",
 "apply_product": "P000000U000A,P000000U000B"
 }
 ],
 "app_discount_info": [
 {
 "no": 200,
 "type": "O",
 "name": "FRIDAY_DISCOUNT",
 "icon": "http://placehold.it/32x32",
 "config": {
 "value": 1000,
 "value_type": "W"
 }
 }
 ],
 "time": "1536672695",
 "trace_no": "20180911223134Qkgj54",
 "app_key": "9M0gI35ANt7gDicnD02u8D",
 "hmac": "FR/ZWH2Fj6cF5KMyCEqxIOELFVNRFcaPmmQBbAj7N7U="
}

샘플 코드의 UI 예시

  • 위에서 언급된 예시가 적용된 쇼핑몰 화면입니다.
  • 기본적으로 카페24 쇼핑몰의 정보를 토대로 노출됩니다.
    (JS function / API를 통하여 원하는 디자인/후속 기능을 다양하게 추가할 수 있습니다.)

프론트 UI (장바구니)

프론트 UI (주문서)

어드민 UI (마이앱)

참고사항

카페24 쇼핑몰 데이터 정의 및 할인 적용 순서

카페24 쇼핑몰 데이터 정의

해당 데이터는 카페24 쇼핑몰과의 연동 데이터입니다.

카페24 쇼핑몰 데이터 정의
항목 설명
할인 종류
  • 상품 할인
  • 주문 할인
적용범위
  • 모든 상품
  • 특정 상품
  • 특정 카테고리
적용 방법
  • 상품별 할인
  • 주문단위 할인
할인 종류
  • 정액 할인
  • 정률 할인
할인 적용 회원 범위
  • 비회원+회원
  • 회원
  • 특정 회원그룹
할인 가능한 가격 범위 구매 금액 ~이상
할인 가능한 구매갯수 범위 구매 갯수 ~ 이상

할인 적용 순서

  • 카페24 쇼핑몰에서는 할인 앱을 다운받아 단독적으로 사용할 수 있지만 기본적으로 카페24에서 제공하는 할인 혜택과 함께 사용이 가능합니다.
  • 앱(App)과 카페24 쇼핑몰의 할인의 계산연관성 / 혜택 적용 순서는 다음 그림을 참고하시면 됩니다.

후속연동

할인혜택 어플리케이션(App) 를 통해 생성된 주문에 대한 후속연동이 필요한 경우 '카페24 개발자센터'를 통해 제공되고 있는 주문(order) API를 참고하시길 바랍니다.
(Recipe 서비스 오픈되면 실시간 연동 가능하게 될 예정입니다.)

카페24 개발자센터 API안내보기 (API 상세 사양(Admin)