iT邦幫忙

2021 iThome 鐵人賽

DAY 14
0
永豐金融APIs

試著讀懂與串接永豐金融APIs系列 第 14

Day 0xE - 建立訂單紀錄到資料庫

0x1 前言

目前還沒有畫面可以看或操作,所以單就資料流的部分先寫進資料庫,
而建立訂單目前也是先塞變數進去,所以每次都會是新單。
今天的目標就是寫進資料庫,並產生一個簡單的表格來看(最陽春的那種)

0x2 處理流程

主要記錄的有幾個欄位

  • 請求
    1. OrderNo - 訂單編號
    2. Amonut - 訂單金額
    3. PrdtName - 顧客名稱
    4. PayType - 付款方式
      虛擬 ATM
    5. ExpireDate - 訂單逾期日期
      信用卡
    6. AutoBilling - 是否自動請款
    7. ExpBillingDays - 自動請款天數
  • 回應
    9. TSNo - 交易編號
    10. Status - 處理狀態
    11. Description - 回應訊息
    虛擬 ATM
    12. AtmPayNo - 虛擬帳號
    13. WebAtmURL - Web ATM 網址
    14. OtpURL - 一次性密碼網址
    信用卡
    15. CardPayURL - 信用卡付款網址

之前規劃的欄位已經有了 [訂單編號, 訂單總金額, 付款方式, 訂單狀態, 訂單過期日期],
還缺少 [顧客名稱, 是否自動請款, 自動請款天數, 交易編號, 回應訊息, 虛擬帳號, Web ATM 網址, 一次性密碼網址, 信用卡付款網址]

  • 建立 migration
>  php artisan make:migration --table=sale_orders update_sale_order
  • 更改 migration 檔案
// database/migrations/[current_date_time]_update_sale_order.php
public function up()
{
    Schema::table('sale_orders', function (Blueprint $table) {
        $table->string('prdt_name', 50)->comment('顧客名稱');
        $table->string('auto_billing', 1)->nullable()->comment('是否自動請款');
        $table->tinyInteger('exp_billing_days')->nullable()->comment('自動請款天數');
        $table->string('ts_no', 20)->nullable(false)->comment('交易編號');
        $table->string('description', 50)->nullable()->comment('回應訊息');
        $table->string('atm_pay_no', 14)->nullable()->comment('虛擬帳號');
        $table->string('web_atm_url', 255)->nullable()->comment('Web ATM 網址');
        $table->string('otp_url', 255)->nullable()->comment('一次性密碼網址');
        $table->string('card_pay_url', 255)->nullable()->comment('信用卡付款網址');
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::table('sale_orders', function (Blueprint $table) {
        $table->dropColumn(['prdt_name', 'auto_billing', 'exp_billing_days', 'ts_no', 'description', 'atm_pay_no', 'web_atm_url', 'otp_url', 'card_pay_url']);
    });
}
  • 修正 付款時間能為空值
// database/migrations/[create_date_time]_create_sale_orders_table.php
    ...
    $table->dateTime('pay_datetime')->nullable()->comment('付款時間');
    ...
  • 執行 migrate,查看 table 欄位就能看到已經變更了(fresh 會把所有 table 都移除後,重新執行所有 migrate)
>  php artisan migrate:fresh

https://ithelp.ithome.com.tw/upload/images/20210924/20141805A6C5AfB4ss.png
(此工具為 PhpStorm 的 Database,在開發的時候能檢查SQL語法對應的表格或欄位,非工商 XD)

  • 增加 model fillable 陣列,讓 orm 可以寫
// app/Models/sale_order.php
protected $fillable = [
    ...
    'prdt_name',
    'auto_billing',
    'exp_billing_days',
    'ts_no',
    'description',
    'atm_pay_no',
    'web_atm_url',
    'otp_url',
    'card_pay_url'
];
  • 接下來 改寫 create_order 函數,讓資料可以寫進資料庫
public function create_order(Request $request)
{
    $sinopac = $this->initSinopac();
    $order_no = date('YmdHis');
    $amount = random_int(4000, 10000);
    $pay_type = ($request->get('credit', '') === 'Y') ? 'C' : 'A';
    $expire_date = date('Ymd', time() + 604800);

    $data = [
        'ShopNo'        => $sinopac->shop_no,
        'OrderNo'       => $order_no,
        'Amount'        => $amount . '00',
        'CurrencyID'    => 'TWD',
        'PrdtName'      => '大河',
        'ReturnURL'     => 'http://10.11.22.113:8803/QPay.ApiClient-Sandbox/Store/Return',
        'BackendURL'    => 'https://sandbox.sinopac.com/funBIZ.ApiClient/AutoPush/PushSuccess',
        'PayType'       => $pay_type,
        'ATMParam'      => [
            'ExpireDate' => $expire_date,
        ],
    ];

    $data = $sinopac->requestDataset('OrderCreate', $data);
    $message = $sinopac->callApi('https://apisbx.sinopac.com/funBIZ/QPay.WebAPI/api/Order', $data);

    $reply_nonce = $message['Nonce'] | '';
    if (!$reply_nonce) {
        $msg = 'Reply message haven\'t Nonce';
        Log::error($msg , $message);
        throw new \Exception($msg);
    }

    // 1. nonce 計算 iv
    $iv = $sinopac->calculateIv($reply_nonce);
    // 2. 計算 hash_id (AES key)
    $hash_id = $sinopac->calcHashId();
    // 3. message 解密
    $decrypt_message = $sinopac->decryptMessage($message['Message'], $hash_id, $iv);
    // 4. 驗證 sign
    $sign = $sinopac->generateSign($decrypt_message, $reply_nonce, $hash_id);

    if (!($sign === $message['Sign'])) {
        return ['msg' => '驗證錯誤,內文簽章不同'];
    }

    // 這裡的 – 是 \xE2  不是 \x2D
    $description = explode(' – ', $decrypt_message['Description']);
    if ($description[0] !== 'S0000') {
        Log::alert('訂單未建立成功', $decrypt_message);
    }

    $dataset = [
        'customer_id'       => 0,
        'order_no'          => $order_no,
        'total'             => $amount,
        'pay_type'          => $pay_type,
        'expire_date'       => $expire_date,
        'ts_no'             => $decrypt_message['TSNo'],
        'status'            => $decrypt_message['Status'],
        'description'       => $decrypt_message['Description'],
        'mailing_address'   => '',
        'prdt_name'         => '大河',
    ];
    if ($pay_type === 'C') {
        // 信用卡
        $card_param = $decrypt_message['CardParam'];
        $dataset = array_merge($dataset, [
            'card_pay_url'  => $card_param['CardPayURL'],
        ]);
    } else {
        // 虛擬帳號
        $atm_param = $decrypt_message['ATMParam'];
        $dataset = array_merge($dataset, [
            'atm_pay_no'    => $atm_param['AtmPayNo'],
            'web_atm_url'   => $atm_param['WebAtmURL'],
            'otp_url'       => $atm_param['OtpURL'],
        ]);
    }
    $id = sale_order::create($dataset)->id;

    return [
        'dataset' => $dataset,
        'id' => $id
    ];
}
  • 建立 Web controller,然後資料全部倒出來啦
> php .\artisan make:controller Web
// app/Http/Controllers/Web.php
public function orders()
{
    return view('orders', [
        'dataset' => sale_order::all()->toArray()
    ]);
}
  • resources/views 建立 orders.blade.php
// resources/views/orders.blade.php
<style>
    table {
        width: 100%;
        text-align: center;
    }

    thead > tr, tr:hover {
        background: #1a202c30;
    }
</style>
<table>
    <thead>
        <tr>
            <th>#</th>
            <th>訂單編號</th>
            <th>訂單金額</th>
            <th>訂單類型</th>
            <th>客戶名稱</th>
            <th>客戶住址</th>
            <th>處理狀態</th>
            <th>銀行回覆內容</th>
            <th>付款期限</th>
            <th>建立日期</th>
            <th>更新日期</th>
        </tr>
    </thead>
    <tbody>
        @foreach($dataset as $index => $line)
            <tr>
                <td>{{ $index + 1 }}</td>
                <td>{{ $line['order_no'] }}</td>
                <td>{{ $line['total'] }}</td>
                <td>{{ $line['pay_type'] }}</td>
                <td>{{ $line['prdt_name'] }}</td>
                <td>{{ $line['mailing_address'] }}</td>
                <td>{{ $line['status'] }}</td>
                <td>{{ $line['description'] }}</td>
                <td>{{ $line['expire_date'] }}</td>
                <td>{{ $line['created_at'] }}</td>
                <td>{{ $line['updated_at'] }}</td>
            </tr>
        @endforeach
    </tbody>
</table>
  • 建立看訂單的 route
// routes/web.php
Route::get('/orders', [Web::class, 'orders']);

OK~來看個成果
https://ithelp.ithome.com.tw/upload/images/20210924/20141805HYOEYbrdce.png

0x3 今日結語

差點趕不上發文阿,要改的bug好多阿,有點懷疑自己為什麼要參賽了/images/emoticon/emoticon02.gif
明天要把讓自己輕鬆一些,簡單看一下回應的網頁長怎麼樣好了 ('web_atm_url', 'otp_url', 'card_pay_url')


上一篇
Day 0xD - 解開建立訂單回覆的訊息,建立訂單的 Amount 要注意
下一篇
Day 0xF - Web ATM 內容?,測試模擬交易回傳資訊
系列文
試著讀懂與串接永豐金融APIs30

尚未有邦友留言

立即登入留言