Laravel 모빌리언스 결제

moby
Standard

Mobilians is another Korean PG company allows users to pay for purchases with their Korean cell-phone, which is a pretty common practice in Korea. Let’s see how we can leverage this while using Laravel. It’s gonna be challenging for sure though. Everytime I had to deal with IT products from Korean companies, I found it unpleasantly difficult to follow their inferior manuals. We’ll see how it turns out this time soon.

If I understand it correctly, there’re 2 difference ways to make it work. One that forces you to compile a dependency module from a tarball and another without any dependency module. For the sake of simplicity, I’ll go with the latter. Now, it’s time to see their sample codes. (Oh great, you can’t extract the sample zip file on a Mac. It started to tick me off already.)

Configuration

I’ve attached the options that the PG company requires in app/config/services.php

    return array (
        :
        'mobillians' => [
            'svcid' => '120000000000', // a string id assigned to your account
            'url' => 'hanlingo.com', // a URL associated with this transaction
            'mode' => '00' // 00 for a sandbox transaction, 01 for a live transaction
        ],
        :
    );

Controller

After setting up the app/routes.php as follows:

    Route::post('payment/preview', [ 'as' => 'payments.preview', 'uses' => 'PaymentsController@preview' ]);
    Route::post('payments/moby',   [ 'as' => 'payments.moby',    'uses' => 'PaymentsController@postFromMoby' ]);

The only thing you need to set up is a controller to deal with user requests.

    public function preview()
    {
        $data = $this->paymentForm->validate(Input::all());
        $keys = Config::get('services.mobillians');

        $data['transaction_id'] = 'TEESHOT-'.$keys['svcid']."_".$this->randomShit();
        $data['phone'] = $this->me->profile->phone;
        $data['email'] = $this->me->email;
        $data['user_id'] = $this->me->id;
        $data['item_en'] = 'TeeShot Membership ('.(intval($data['product']) - 1).')';
        $data['post_url'] = "http://test.putting.co.kr/payments/moby";

        return View::make('payments.confirmmoby')->with(compact('data', 'keys'));
    }

    public function postFromMoby()
    {
        if (Input::get('Resultcd') != "0000")
            dd( '알수 없는 에러 발생 ('.$this->koreanShit(Input::get('Resultmsg')).', 1)' );

        $data = [
            'transaction_id' => Input::get('Tradeid'),
            'payment_type' => '휴대폰',
            'item_name' => Input::get('Prdtnm'),
            'item_price' => Input::get('Prdtprice'),
            'recurring' => 0,
            'realname' => $this->me->profile->realname,
            'phone' => Input::get('No'),
            'email' => Input::get('Payeremail'),
            'user_id' => Input::get('Userid'),
        ];

        $payment = $this->me->payments()->create($data);

        $this->updateUserRecord($ended_at);

        Event::fire('Teeshot.Events.UserHasPurchased', new UserHasPurchased($this->me, $payment));

        return View::make('payments.moby')->with(compact('data'));
    }

    private function updateUserRecord($date)
    {
        $this->me->expired_at = $date;
        $this->me->save();
    }

    private function randomShit() {
        $microtime = microtime();
        $comps = explode(" ", $microtime);
        return date("YmdHis") . sprintf("%04d", $comps[0] * 10000);
    }

Here’re the view files that I used in my project. First, payments/confirmmoby.blade.php

    @extends('layouts.default')

    @section('content')

        <div class="panel panel-default">
            <div class="panel-heading"><div class="panel-title">이용권 구매</div></div>
            <div class="panel-body">
                <div class="form-group golf-info">
                    {{ Form::open(['name' => 'payForm']) }}

                        <input type="hidden" name="MC_SVCID" id="MC_SVCID" size="30" value="{{ $keys['svcid'] }}">
                        <input type="hidden" name="Siteurl" id="Siteurl" size="30" value="{{ $keys['url'] }}">
                        <input type="hidden" name="PAY_MODE" id="PAY_MODE" size="30" value="{{ $keys['mode'] }}">
                        <input type="hidden" name="Prdtnm" id="Prdtnm" size="30" value="{{ $data['item_en'] }}">
                        <input type="hidden" name="Prdtprice" id="Prdtprice" size="30" value="{{ $data['amount'] }}">
                        <input type="hidden" name="Tradeid" id="Tradeid" size="50" value="{{ $data['transaction_id'] }}">
                        <input type="hidden" name="MC_No" id="MC_No" size="30" value="{{ $data['phone'] }}">
                        <input type="hidden" name="Okurl" id="Okurl" size="50" value="{{ $data['post_url'] }}">
                        <input type="hidden" name="Payeremail" id="Payeremail" size="30" value="{{ $data['email'] }}">
                        <input type="hidden" name="Userid" id="Userid" size="30" value="{{ $data['user_id'] }}">
                        <input type="hidden" name="CASH_GB" id="CASH_GB" size="30" value="MC">
                        <input type="hidden" name="LOGO_YN" id="LOGO_YN" size="30" value="N">
                        <input type="hidden" name="CALL_TYPE" id="CALL_TYPE" size="30" value="P">
                        <input type="hidden" name="Cryptyn" id="Cryptyn" size="30" value="N">
                        <input type="hidden" name="Notiemail" id="Notiemail" size="30" value="admin@admin.com">

                        <input type="hidden" name="MSTR" id="MSTR" size="50" value="">
                        <input type="hidden" name="Notiurl" id="Notiurl" size="50" value="">
                        <input type="hidden" name="Failurl" id="Failurl" size="50" value="">
                        <input type="hidden" name="Closeurl" id="Closeurl" size="50" value="">
                        <input type="hidden" name="MC_PARTPAY" id="MC_PARTPAY" size="30" value="">
                        <input type="hidden" name="MC_DEFAULTCOMMID" id="MC_DEFAULTCOMMID" size="30" value="">
                        <input type="hidden" name="MC_FIXCOMMID" id="MC_FIXCOMMID" size="30" value="">
                        <input type="hidden" name="MC_FIXNO" id="MC_FIXNO" size="30" value="">
                        <input type="hidden" name="MC_Cpcode" id="MC_Cpcode" size="30" value="">
                        <input type="hidden" name="Item" id="Item" size="30" value="">
                        <input type="hidden" name="Prdtcd" id="Prdtcd" size="30" value="">
                        <input type="hidden" name="Sellernm" id="Sellernm" size="30" value="">
                        <input type="hidden" name="Sellertel" id="Sellertel" size="30" value="">
                        <input type="hidden" name="IFRAME_NAME" id="IFRAME_NAME" size="30" value="">
                        <input type="hidden" name="INFOAREA_YN" id="INFOAREA_YN" size="30" value="">
                        <input type="hidden" name="FOOTER_YN" id="FOOTER_YN" size="30" value="">
                        <input type="hidden" name="HEIGHT" id="HEIGHT" size="30" value="">
                        <input type="hidden" name="PRDT_HIDDEN" id="PRDT_HIDDEN" size="30" value="">
                        <input type="hidden" name="EMAIL_HIDDEN" id="EMAIL_HIDDEN" size="30" value="">
                        <input type="hidden" name="CONTRACT_HIDDEN" id="CONTRACT_HIDDEN" size="30" value="">
                        <input type="hidden" name="Cryptstring" id="Cryptstring" size="50" value="">
                        <input type="hidden" name="Crypthash" id="Crypthash" size="50" value="">
                        <input type="hidden" name="MC_AUTHPAY" id="MC_AUTHPAY" size="30" value="">
                        <input type="hidden" name="MC_AUTOPAY" id="MC_AUTOPAY" size="30" value="">

                        <table class="table">
                            <tr>
                                <td>상품명</td>
                                <td>{{ $data['item'] }}</td>
                            </tr>
                            <tr>
                                <td>결제금액</td>
                                <td>{{ preg_replace("/(?<=\d)(?=(?:\d\d\d)+(?!\d))/", ",", $data['amount']) }} 원</td>
                            </tr>
                            <tr>
                                <td>구매수단</td>
                                <td>{{ $data['description'] }}</td>
                            </tr>
                        </table>

                        <div>
                            <p>아래의 결제 버튼을 누르면 모빌리언스를 통하여 결제가 진행됩니다.</p>
                            <div><button class="btn btn-lg btn-primary" id="btnPay">결제</button></div>
                        </div>

                    {{ Form::close() }}
                </div>
            </div>
        </div>

    @stop

    @section('scripts')

        <script src="https://mup.mobilians.co.kr/js/ext/ext_inc_comm.js"></script>
        <script type="text/javascript">
            $('#btnPay').click(function() {
                $(this).hide();
                MCASH_PAYMENT(document.payForm);
            });
       </script>

    @stop

Then, the 2nd view file named payments/moby.blade.php

    @extends('layouts.default')

    @section('content')

        <div class="header">
            <h4>결제결과</h4>
        </div>

        <table class="table">
            <tr><td>결제방법</td><td>{{ $data['payment_type'] }}</td></tr>
            <tr><td>결과내용</td><td>{{ '결제가 정상처리되었습니다.' }}</td></tr>
            <tr><td>거래금액</td><td>{{ $data['item_price'] }} 원</td></tr>
        </table>

        <button class="btn btn-lg btn-success" id="btnClose">창닫기</button>

    @stop

    @section('scripts')
        <script type="text/javascript">

            function redirectToPage(){
                window.opener.location.href="/users/{{ $data['user_id'] }}/payments";
                self.close();
            }

            $(function() {
                $('#btnClose').click(function(e) {
                    redirectToPage();
                });
            });
        </script>
    @stop

Like Inicis PG service I reviewed earlier, this company only uses EUC-KR instead of UTF-8. It means that passing string parameters using UTF-8 Korean will not work out of box. Use UTF-8, suckers.