본문 바로가기

notes

해외결제모듈 붙이기 ( eximbay,python )

@마크다운


해외결제를 붙여야 할 일이 생겨서 찾아보던중 eximbay라는 결제모듈을 찾았다.


eximbay를 선택한 이유는 해외결제 대상이 동남아쪽(태국)인데 동남아쪽은 카드발급율이 엄청나게 낮다고 한다. (10%이하)


그럼 인터넷 결제를 어떻게 하냐?


MOLPAY라는 동남아쪽 PG에서 주문을 하고 입금을 ATM기기로 MOLPAY측에 입금을 한다고 한다.


마치 무통장 입금같은 느낌으로


아무튼 위와같은 과정들을 진행하려면 상당히 까다로운 과정들을 거쳐야하는데 이 과정을 eximbay를 통해서 진행하면 좀 낫다.


eximbay에서는 당연?하게도 샘플코드를 자바와php만을 지원을 하고 있으며 나는 python이기 때문에 포팅을 하여 사용을 해야한다.


그러나 eximbay측 기술문서가 상당히 잘되어있어 몇번의 문의(????)만으로 구현을 할 수 있다.


여담이지만 이번에 eximbay를 달면서 iamport에 있는 eximbay도 같이 사용해 보았으나 생각보다 완성도가 높지않아 사용할 수 없었다.

(MOLPAY 지원이라 적혀있으나 태국이 결제 지원이 안되었다[지금은 됩니다.], 테스트를 거치지 않은 날것 같은 느낌의 에러를 뿜어내기도 했다.) 


기술문서를 읽어보면 알겠지만 엑심베이는 요청 파라미터들을 알파벳 순으로 sort하여 secret_key 와 "?"로 연결하여 sha256으로 해시한 값을 따로담아서 같이 보내줘야한다.


# code

```

class Eximbay():

    def __init__(self, secret_key=TEST_SECRET_KEY, mid=TEST_MID, mod="TEST"):

        self.secret_key = secret_key

        self.mid = mid


        if mod == "REAL":  # real

            self.url = "https://secureapi.eximbay.com/Gateway/BasicProcessor.krp"

        else:

            self.url = "https://secureapi.test.eximbay.com/Gateway/BasicProcessor.krp"


    # 파라미터 정렬

    @staticmethod

    def _sorting_params(**kwargs):

        """


        :param kwargs:

        :return:

        """

        return_data = sorted(kwargs.items(), key=operator.itemgetter(0))  # 키값으로 소팅

        params = ""

        for k, v in return_data:

            params += str(k) + "=" + str(v) + "&"

        params = params[:-1]

        return params


    def make_fgkey(self, **kwargs):

        """

        fgkey는

        A. 모든 요청/응답 파라미터를 알파벳순서로 sorting하여 데이터를 생성 B. secretkey와 A의 데이터를 "?"로 연결

        C. B의 결과를 SHA256 함수를 통해 Hashing 하여 생성합니다.

        """

        params = self._sorting_params(**kwargs)

        secret_key = self.secret_key

        secret_add_params = secret_key + "?" + params

        # params 과 시크릿키를 더한 후 단방향해시 후 str변환

        fgkey = hashlib.sha256(secret_add_params.encode("utf-8")).hexdigest()

        return fgkey


    # 결제 요청

    def payment(self, **kwargs):

        # cur : 통화 , amt : 금액, buyer : 구매자 이름, email : 이메일, lang : 언어팩, returnurl : 결제완료 or 취소시 리턴

        # statusurl : 결제 요청시 request 보내는곳 ,paymethod : 태국 MOLPAY 171

        required_param_list = ['cur', 'amt', 'buyer', 'email', 'lang', 'returnurl', 'statusurl', 'paymethod']

        # 요청 필수 값

        for key in required_param_list:

            if key not in kwargs:

                raise KeyError("Parameter is missing!: {}".format(key))

        # 결제 공통부분

        payment_params = {

            'ver': 230,  # 버전

            'txntype': "PAYMENT",  # 간편결제

            'charset': "UTF-8",

            'mid': self.mid,  # 가맹점 아이디

            'displaytype': "P"

        }

        payment_params.update(kwargs)

        payment_params['fgkey'] = self.make_fgkey(**payment_params)

        template = Template("""

                <!DOCTYPE html>

                <html>

                <head>

                <meta http-equiv="X-UA-Compatible" charset=UTF-8">

                </head>

                <body leftmargin="0" topmargin="0" align="center" onload="javascript:document.regForm.submit();">

                {% if data %}

                  <form name="regForm" method="post" action="{{ reqUrl }}" accept-charset="utf-8">

                  {% for key, value in data.items() %}

                    <input type="hidden" name="{{ key }}" value="{{ value }}" >

                  {% endfor %}

                  </form>

                {% else %}

                  <h1>No Data!!!</h1>

                {% endif %}

                </body>

                <script>

                document.regForm.submit()

                </script>


                </html>

                """)

        return template.render(reqUrl=self.url, data=payment_params)

```


제일 헤메던 부분이 데이터를 엑심베이측으로 넘겨줘야하는 부분인데


자꾸 이부분에서 인코딩이 박살이 나는 것이었다.


코드상의 문제는 암만봐도 없는것 같은데 인코딩이 박살이 나니 여기저기 쑤시고 문의를 보냈다.


엑심베이의 기술지원문의는 상당히 깔끔하게 답변을 잘해주신다.


>KRP 김종민님께 감사드립니다. 매번 깔끔한 답변 감사합니다.



답변중 엑심베이의 로그 데이터를 보여주셨는데 그 데이터가 다음과 같았다.


```
buyer:&#3610;&#3640;&#3625;&#3618;&#3616;&#3633;&#3607;&#3619;&#3660; &#3616;&#3640;&#3617;&#3619;&#3636;&#3609;&#3607;&#3619;&#3660;
```


나는 분명 utf-8로 인코딩해서 보냈는데 받는쪽에서 이렇게 박살이 나는것 아닌가?


뭔가 삘이 왔다

[string conversion](http://coderstoolbox.net/string/#!encoding=xml&action=encode&charset=us_ascii)


여기로가서 내가 보내려고했던 문자열을 입력하고 똑같이 박살나는 녀석을 찾기 시작했다.


그 결과 ISO-8859-1이라는 놈이랑 정확하게 일치했다.


원인은 알았으니 이제 해결만 하면 된다.


대체 ISO-8859-1이라는놈이 뭔가?


찾아보니 html4의 디폴트 인코딩 타입이라고 한다.


왜 이녀석이 말썽을 부리는건지 도저히 1도 모르겠지만

```
<meta http-equiv="X-UA-Compatible" charset=UTF-8">
```

이코드를 집어넣고 다시 돌려봤다.


안된다.


다시 멘붕에 빠져있을때, 혹시 form에서 문제를 일으키는건 아닐까 라는 생각이들어 form에서 인코딩을 바꿀수 있는 요소를 찾기 시작했다.


[코드쓰는사람](https://taegon.kim/archives/1692)

다음과 같은 게시물을 발견했고 바로 적용했다.


이 모든 과정을 거쳐서 만들어진게 상기의 코드이며 2018-06-18 현재 정상작동이 되고 있음을 확인했다.


이렇게 쓰고보니 상당히 간단한 과정이지만 삽질을 반복하던 나로써는 엄청난 발전을 한것 같았다.


물론 지금의 코드를 그대로 쓰면 결제가 진행만 된다.


서비스로직에 붙이는건 더 고단한 일이다. ㅠㅠ


아무튼.. 누군가에겐 도움이 되었으면 좋겠다.