Laravel 이니시스 결제

laravel-inicis
Standard

HOW TO RIP OFF KOREAN USERS BY USING INICIS. J/K.

It’s not intended to replace the whole manual from INICIS, one of major Korean PGs to allow you to accept Korean credit cards. The objective of this writing is provide you a feasible way to use INICIS while using Laravel 4.2.x PHP framework. It was a pain in the ass to read through their unbelievably crappy manual though. At the time of this writing, I am using L4 for my current project so bear with me until I upgrade to the version 5 if that’s what you want. So, let’s cut to the chase;

They have this legacy PHP class called INIpay50 which seems to be written in old school days. You may simply want to put them in the following directory;

    {project-root}/app/classes/INIpay50

and autoload ’em with composer.json like this;

    "autoload": {
        "classmap": [
            :
            "app/classes"
        ]
    }

Don’t forget to php artisan dump-audoload after updating composer.json. Another caveat you should keep in mind is that encryption key-file directory and log directory are under the directory as you may need to check out them later.

Unfortunately, the way the legacy classes are rigidly coupled with Views and JavaScripts forces me to follow their fragile coding style at least with my level of understanding of how they work. Too bad.

The following is the migration I work with. You should make a similar one for your own good:

    public function up()
    {
        Schema::create('payments', function(Blueprint $table)
        {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->string('transaction_id');
            $table->string('payment_type');
            $table->string('item_name');
            $table->integer('item_price');
            $table->tinyInteger('recurring')->default(0);
            $table->string('realname');
            $table->string('phone');
            $table->string('email');
            $table->timestamps();
            $table->dateTime('started_at')->nullable();
            $table->dateTime('ended_at')->nullable();
        });
    }

Then, the model, Payment:

    <?php namespace Teeshot\Payments;

    use Eloquent;
    use Laracasts\Presenter\PresentableTrait;

    class Payment extends Eloquent {

        use PresentableTrait;

        protected $fillable = [ 'user_id', 'transaction_id', 'payment_type', 'item_name', 'item_price', 'recurring', 'realname', 'phone', 'email', 'started_at', 'ended_at' ];

        protected $table = 'payments';
        protected $dates = [ 'started_at', 'ended_at' ];
        protected $presenter = 'Teeshot\Payments\PaymentPresenter';

        public function user()
        {
            return $this->belongsTo('User');
        }
    } 

Then the presenter which allows to separate logics from its View. You can ignore this but I’m attaching this for the integrity of source codes.

    <?php namespace Teeshot\Payments;

    use Carbon\Carbon;
    use Laracasts\Presenter\Presenter;

    class PaymentPresenter extends Presenter {

        public function typeOfPayment($key)
        {

            $arrTypes = [
                'Card'=>'신용카드',
                'VCard'=>'신용카드',
                'DirectBank'=>'실시간 계좌이체',
                'VBank'=>'가상계좌'
            ];

            return $arrTypes[$key];
        }

        public function nameOfCard($key)
        {
            $arrCards = [
                "01"=>"외환",
                "03"=>"롯데",
                "04"=>"현대",
                "06"=>"국민",
                "11"=>"BC",
                "12"=>"삼성",
                "13"=>"LG",
                "14"=>"신한",
                "15"=>"한미",
                "21"=>"해외비자",
                "22"=>"해외마스터",
                "23"=>"JCB",
                "24"=>"해외아멕스",
                "25"=>"해외다이너스"
            ];

            return $arrCards[$key];
        }


        public function nameOfCardIssuer($key)
        {
            $arrIssuers = [
                "02"=>"한국산업은행",
                "03"=>"기업은행",
                "04"=>"국민은행(주택은행)",
                "05"=>"외환은행",
                "07"=>"수협중앙회",
                "11"=>"농협중앙회",
                "12"=>"단위농협",
                "16"=>"축협중앙회",
                "20"=>"우리은행",
                "21"=>"신한은행(조흥은행)",
                "23"=>"제일은행",
                "25"=>"하나은행(서울은행)",
                "26"=>"신한은행",
                "27"=>"한국씨티은행(한미은행)",
                "31"=>"대구은행",
                "32"=>"부산은행",
                "34"=>"광주은행",
                "35"=>"제주은행",
                "37"=>"전북은행",
                "38"=>"강원은행",
                "39"=>"경남은행",
                "41"=>"비씨카드",
                "53"=>"씨티은행",
                "54"=>"홍콩상하이은행",
                "71"=>"우체국",
                "81"=>"하나은행",
                "83"=>"평화은행",
                "87"=>"신세계",
                "88"=>"신한은행(조흥 통합)"
            ];

            return $arrIssuers[$key];
        }
    }

Then, the controller. I believe it wouldn’t be hard to follow the logic. The only thing I want to mention is how the validate method works in the paymentForm class. It’s a simple decorator after validating user inputs, which returns only the data that Payment model requires.

    <?php

    use Teeshot\Forms\PaymentForm;
    use Teeshot\Payments\Payment;
    use Teeshot\Payments\PaymentRepository;
    use Teeshot\Events\UserHasPurchased;
    use Carbon\Carbon;

    class PaymentsController extends \BaseController
    {
        private $paymentForm;
        protected $payments;
        protected $me;

        function __construct(PaymentForm $paymentForm, PaymentRepository $paymentRepository)
        {
            parent::__construct();

            $this->paymentForm = $paymentForm;
            $this->payments = $paymentRepository;
            $this->me = Auth::user();
        }

        public function preview()
        {
            $formData = $this->paymentForm->validate(Input::all());

            $keys = Config::get('services.inicis');
            $transition_id = 'TEESHOT-INICIS-'.date("ymd-His").'-'.sprintf("%09d", $this->me->id);  // INICIS-150325-142412-0000000031

            $inipay = new INIpay50;
            $inipay->SetField("inipayhome", app_path()."/classes/INIpay50");
            $inipay->SetField("type", "chkfake");
            $inipay->SetField("debug", "false"); // to exclude logging
            $inipay->SetField("enctype", "asym");
            $inipay->SetField("admin", $keys['admin']);
            $inipay->SetField("checkopt", "false");
            $inipay->SetField("mid", $keys['mid']);
            $inipay->SetField("price", $formData['amount']);
            $inipay->SetField("nointerest", "no");
            $inipay->SetField("quotabase", "선택:일시불:2개월:3개월:6개월");
            $inipay->startAction();

            if ($inipay->GetResult("ResultCode") != "00")
                dd( '알수없는 에러 ('.$inipay->GetResult("ResultMsg").')' );

            Session::put('INI_MID', $keys['mid']);
            Session::put('INI_ADMIN', $keys['admin']);
            Session::put('INI_OID', $transition_id);
            Session::put('INI_PRICE', $formData['amount']);
            Session::put('INI_RN', $inipay->GetResult("rn"));
            Session::put('INI_ENCTYPE', $inipay->GetResult("enctype"));

            // Add 3 more data that this shit requires
            $formData['today'] = date("Ymd", time());
            $formData['ini_encfield'] = $inipay->GetResult("encfield");
            $formData['ini_certid'] = $inipay->GetResult("certid");

            return View::make('payments.preview')->with(compact('formData'));
        }

        public function bill()
        {
            $inipay = new INIpay50;
            $inipay->SetField("inipayhome", app_path()."/classes/INIpay50");
            $inipay->SetField("type", "securepay");
            $inipay->SetField("pgid", "INIphp".Input::get('pgid'));
            $inipay->SetField("subpgip","203.238.3.10");
            $inipay->SetField("admin", Session::get('INI_ADMIN'));
            $inipay->SetField("debug", "false");
            $inipay->SetField("uid", Input::get('uid'));
            $inipay->SetField("goodname", Input::get('goodname'));
            $inipay->SetField("currency", Input::get('currency'));
            $inipay->SetField("mid",Session::get('INI_MID'));
            $inipay->SetField("rn", Session::get('INI_RN'));
            $inipay->SetField("price", Session::get('INI_PRICE'));
            $inipay->SetField("enctype", Session::get('INI_ENCTYPE'));
            $inipay->SetField("buyername", Input::get('buyername'));
            $inipay->SetField("buyertel",  Input::get('buyertel'));
            $inipay->SetField("buyeremail", Input::get('buyeremail'));
            $inipay->SetField("paymethod", Input::get('paymethod'));
            $inipay->SetField("encrypted", Input::get('encrypted'));
            $inipay->SetField("sessionkey", Input::get('sessionkey'));
            $inipay->SetField("url", "http://teeshot.app:8000"); // REPLACE IT WITH YOUR URL
            $inipay->SetField("cardcode", Input::get('cardcode'));
            $inipay->SetField("parentemail", "your@parent.com");
            $inipay->SetField("joincard", Input::get('joincard'));
            $inipay->SetField("joinexpire", Input::get('joinexpire'));
            $inipay->SetField("id_customer", Input::get('id_customer'));
            $inipay->startAction();

            if ($inipay->GetResult("ResultCode") != "00")
                dd( '알수없는 에러 ('.$inipay->GetResult("ResultMsg").')' );
            else {

                $data = [
                    'transaction_id' => Input::get('oid'),
                    'payment_type' => Input::get('paymethod'),
                    'item_name' => Input::get('goodname'),
                    'item_price' => Input::get('price'),
                    'recurring' => Input::get('recurring'),
                    'realname' => $this->me->profile->realname,
                    'phone' => $this->me->profile->phone,
                    'email' => $this->me->email,
                    'started_at' => Carbon::now()->toDateTimeString(),
                    'ended_at' => Carbon::now()->addDays(31)->toDateTimeString()
                ];

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

                $this->me->expired_at = $ended_at;
                $this->me->save();

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

                Session::forget('INI_ADMIN');
                Session::forget('INI_ENCTYPE');
                Session::forget('INI_MID');
                Session::forget('INI_OID');
                Session::forget('INI_PRICE');
                Session::forget('INI_RN');
            }

            return View::make('payments.inicis')->with(compact('inipay', 'payment'));
        }
    }

And, finally, the views:

1st view with options

https://gist.github.com/jinseokoh/edf8b3c3afe5845e16a7

2nd view which loads preview screen and brings in Active X encryption modules;

https://gist.github.com/jinseokoh/1489dacc6d527d6fb97c

3rd view which shows the result;

https://gist.github.com/jinseokoh/d0f2bcd9de475cde3f91

I know there’re rooms to improve. But, hopefully, my codes here would eventually help you get you going with the INICIS PG service without pulling your hair out. Even though I followed their instructions to load the JavaScript file written in UTF-8 Korean code. Their server isn’t smart enough to figure I’m using UTF-8. This is the level of service from a company called themselves number 1 in Korea. guess they’re all too busy doing shit.