Aplikasi E-Commerce Laravel 6 #19: Fitur Ongkos Kirim

Aplikasi E-Commerce Laravel 6 #19: Fitur Ongkos Kirim

Pendahuluan

Sejak pertama kali serial Membuat Aplikasi E-Commerce Laravel 6 di-release, ada banyak permintaan untuk menerapkan fitur ongkos kirim, namun kendalanya, tidak satupun yang memiliki license ongkos kirim untuk digunakan secara public. Hal ini tentu saja menjadi kendala kami dalam menuliskan materi karena tidak adanya sumber untuk mengambil data ongkos kirim.

Kendala lainnya adalah license yang dimiliki jika tidak didonasikan ke public akan menjadi halangan bagi teman-teman pembaca lainnya dalam mengikuti serial tersebut, sehingga kami putuskan untuk tidak membahas terkait fitur ongkos kirim pada aplikasi ecommerce yang kita bangun.

Beruntungnya saat ini sudah tersedia RuangAPI, dimana kita bisa menggunakannya secara gratis untuk diterapkan pada project apapun yang membutuhkan data ongkos kirim. Berikut adalah materi bagaimana menerapkan fitur ongkos kirim pada Aplikasi E-Commerce Laravel 6.

Baca Juga: Membuat Aplikasi Ekspedisi NuxtJS #4: Manage Categories

Integrasi Data Ongkos Kirim RuangAPI

Proses integrasi untuk mengambil data ongkos kirim pada platform RuangAPI adalah dengan melakukan hit ke API yang sudah disediakan. Akan tetapi, agar bisa mendapatkan izin, maka kita wajib melakukan pendaftaran untuk mendapatkan API Key. Tenang saja, pendaftarannya gratis dan setelah proses pendaftaran selesai, kamu bisa mendapatkan API Key nya pada menu RuangAPI Key.

Adapun HTTP Client yang akan digunakan adalah Guzzle, install terlebih dahulu dengan command

composer require guzzlehttp/guzzle

Buka file Ecommerce/CartController.php dan tambahkan method berikut

public function getCourier(Request $request)
{
    $this->validate($request, [
        'destination' => 'required',
        'weight' => 'required|integer'
    ]);

    //MENGIRIM PERMINTAAN KE API RUANGAPI UNTUK MENGAMBIL DATA ONGKOS KIRIM
    //BACA DOKUMENTASI UNTUK PENJELASAN LEBIH LANJUT
    $url = 'https://ruangapi.com/api/v1/shipping';
    $client = new Client();
    $response = $client->request('POST', $url, [
        'headers' => [
            'Authorization' => 'API KEY ANDA'
        ],
        'form_params' => [
            'origin' => 22, //ASAL PENGIRIMAN, 22 = BANDUNG
            'destination' => $request->destination,
            'weight' => $request->weight,
            'courier' => 'jne,jnt' //MASUKKAN KEY KURIR LAINNYA JIKA INGIN MENDAPATKAN DATA ONGKIR DARI KURIR YANG LAIN
        ]
    ]);

    $body = json_decode($response->getBody(), true);
    return $body;
}

Masih dengan file yang sama, tambahkan use statement

use GuzzleHttp\Client;

Definisikan routing dari method di atas, buka file routes/api.php dan tambahkan code

Route::post('cost', 'Ecommerce\CartController@getCourier');

Tiba saatnya bagi kita untuk meng-handle view halaman checkout, buka file ecommerce/checkout.blade.php dan tambahkan tag berikut tepat di bawah tag kecamatan.

<div class="col-md-12 form-group p_star">
    <label for="">Kurir</label>
    <input type="hidden" name="weight" id="weight" value="{{ $weight }}">
    <select class="form-control" name="courier" id="courier" required>
        <option value="">Pilih Kurir</option>
    </select>
    <p class="text-danger">{{ $errors->first('courier') }}</p>
</div>

Kemudian modifikasi tag untuk menampilkan summary pesanan, masih dengan file yang sama, modifikasi bagian berikut

<ul class="list list_2">
  <li>
    <a href="#">Subtotal
      <span>Rp {{ number_format($subtotal) }}</span>
    </a>
  </li>
  <li>
    <a href="#">Pengiriman
      <span id="ongkir">Rp 0</span>
    </a>
  </li>
  <li>
    <a href="#">Total
      <span id="total">Rp {{ number_format($subtotal) }}</span>
    </a>
  </li>
</ul>

Note: Bagian yang di-edit adalah menambahkan id ongkir dan total.

Bergeser pada bagian javascriptnya, tambahkan code berikut di dalam file yang sama

//JIKA KECAMATAN DIPILIH
$('#district_id').on('change', function() {
    //MEMBUAT EFEK LOADING SELAMA PROSES REQUEST BERLANGSUNG
    $('#courier').empty()
    $('#courier').append('<option value="">Loading...</option>')
  
    //MENGIRIM PERMINTAAN KE SERVER UNTUK MENGAMBIL DATA API
    $.ajax({
        url: "{{ url('/api/cost') }}",
        type: "POST",
        data: { destination: $(this).val(), weight: $('#weight').val() },
        success: function(html){
            //BERSIHKAN AREA SELECT BOX
            $('#courier').empty()
            $('#courier').append('<option value="">Pilih Kurir</option>')
          
            //LOOPING DATA ONGKOS KIRIM
            $.each(html.data.results, function(key, item) {
                let courier = item.courier + ' - ' + item.service + ' (Rp '+ item.cost +')'
                let value = item.courier + '-' + item.service + '-'+ item.cost
                //DAN MASUKKAN KE DALAM OPTION SELECT BOX
                $('#courier').append('<option value="'+value+'">' + courier + '</option>')
            })
        }
    });
})

//JIKA KURIR DIPILIH
$('#courier').on('change', function() {
    //UPDATE INFORMASI BIAYA PENGIRIMAN
    let split = $(this).val().split('-')
    $('#ongkir').text('Rp ' + split[2])

    //UPDATE INFORMASI TOTAL (SUBTOTAL + ONGKIR)
    let subtotal = "{{ $subtotal }}"
    let total = parseInt(subtotal) + parseInt(split['2'])
    $('#total').text('Rp' + total)
})

Bagian berikutnya adalah meng-handle data ongkos kirim yang dipilih untuk kemudian disimpan ke database. Buat migration baru dengan command

php artisan make:migration add_field_shipping_to_orders_table

Buka file migration yang baru saja di-generate dan modifikasi menjadi

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddFieldShippingToOrdersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('orders', function (Blueprint $table) {
            $table->integer('cost')->after('subtotal')->default(0);
            $table->string('shipping')->after('cost')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('orders', function (Blueprint $table) {
            $table->dropColumn('cost');
            $table->dropColumn('shipping');
        });
    }
}

Eksekusi migration diatas dengan command php artisan migrate.

Saatnya untuk mengelola data ongkos kirim yang dipilih oleh pelangga, buka file Ecommerce/CartController.php dan modifikasi beberapa bagian berikut pada method processCheckout(). Bagian pertama adalah validasi di-ubah menjadi.

$this->validate($request, [
    'customer_name' => 'required|string|max:100',
    'customer_phone' => 'required',
    'email' => 'required|email',
    'customer_address' => 'required|string',
    'province_id' => 'required|exists:provinces,id',
    'city_id' => 'required|exists:cities,id',
    'district_id' => 'required|exists:districts,id',
    'courier' => 'required' //TAMBAHKAN VALIDASI KURIR
]);

Selanjutnya modifikasi query untuk menyimpan informasi pesanan menjadi

$shipping = explode('-', $request->courier); //EXPLODE DATA KURIR, KARENA FORMATNYA, NAMAKURIR-SERVICE-COST
$order = Order::create([
    'invoice' => Str::random(4) . '-' . time(),
    'customer_id' => $customer->id,
    'customer_name' => $customer->name,
    'customer_phone' => $request->customer_phone,
    'customer_address' => $request->customer_address,
    'district_id' => $request->district_id,
    'subtotal' => $subtotal,
    'cost' => $shipping[2], //SIMPAN INFORMASI BIAYA ONGKIRNYA PADA INDEX 2
    'shipping' => $shipping[0] . '-' . $shipping[1], //SIMPAN NAMA KURIR DAN SERVICE YANG DIGUNAKAN
    'ref' => $affiliate != '' && $explodeAffiliate[0] != auth()->guard('customer')->user()->id ? $affiliate:NULL
]);

Sampai pada tahap ini, proses integrasi berhasil dilakukan. Tapi sebelum melakukan proses uji coba, ada beberapa bagian yang perlu untuk dilakukan penyesuaian.

[BUG] Berat Produk Pesanan

Error pertama yang akan kita temukan adalah terkait berat pada produk yang dipilih atau yang dimasukkan ke dalam keranjang. Buka file Ecommerce/CartController.php dan modifikasi method checkout() menjadi

public function checkout()
{
    $provinces = Province::orderBy('created_at', 'DESC')->get();
    $carts = $this->getCarts();
    $subtotal = collect($carts)->sum(function($q) {
        return $q['qty'] * $q['product_price'];
    });
    //TAMBAHKAN FUNGSI UNTUK MENGHITUNG BERAT BARANG
    $weight = collect($carts)->sum(function($q) {
        return $q['qty'] * $q['weight'];
    });
    //JANGAN LUPA PASSING KE VIEW
    return view('ecommerce.checkout', compact('provinces', 'carts', 'subtotal', 'weight'));
}

Masalah berikutnya yang akan kita temukan adalah berat pesanan ini tidak masuk ke dalam cookie atau keranjang belanja. Jadi buka di dalam file yang sama, modifikasi method addToCart() menjadi

public function addToCart(Request $request)
{
    $this->validate($request, [
        'product_id' => 'required|exists:products,id',
        'qty' => 'required|integer'
    ]);

    $carts = $this->getCarts();
    if ($carts && array_key_exists($request->product_id, $carts)) {
        $carts[$request->product_id]['qty'] += $request->qty;
    } else {
        $product = Product::find($request->product_id);
        $carts[$request->product_id] = [
            'qty' => $request->qty,
            'product_id' => $product->id,
            'product_name' => $product->name,
            'product_price' => $product->price,
            'product_image' => $product->image,
            'weight' => $product->weight //TAMBAHKAN BERAT KE DALAM COOKIE
        ];
    }

    $cookie = cookie('dw-carts', json_encode($carts), 2880);
    //KITA JUGA MENAMBAHKAN FLASH MESSAGE UNTUK NOTIFIKASI PRODUK DIMASUKKAN KE KERANJANG
    return redirect()->back()->with(['success' => 'Produk Ditambahkan ke Keranjang'])->cookie($cookie);
}

[BUG] Notifikasi Add to Cart

Ada yang memberikan masukan terkait UI/UX, dimana sebelumnya kita tidak memberikan feedback kepada pelanggan bahwa produk sudah ditambahkan ke dalam keranjang. Adapun fungsi flash message-nya sudah kita tambahkan, sehingga pada bagian ini, kita hanya akan menampilkan flash message tersebut.

Buka file ecommerce/show.blade.php dan tambahkan tag berikut tepat di bawah tombol add to cart.

@if (session('success'))
<div class="alert alert-success mt-2">{{ session('success') }}</div>
@endif

Menampilkan Ongkos Kirim

Data ongkos kirim untuk setiap pesanan sudah tersedia, saatnya bagi kita untuk menyesuaikan pada beberapa bagian agar data tersebut ditampilkan. Buka file checkout_finish.blade.php dan modifikasi tag berikut

<li>
  <a href="#">
    <span>Subtotal</span> : Rp {{ number_format($order->subtotal) }}
  </a>
</li>
<li>
  <a href="#">
    <span>Ongkos Kirim</span> : Rp {{ number_format($order->cost) }}
  </a>
</li>
<li>
  <a href="#">
    <span>Total</span> : Rp {{ number_format($order->total) }}
  </a>
</li>

Note: Cukup tambahkan informasi ongkos kirim dan total.

Bagian selanjutnya adalah pada halaman list pesanan, buka file ecommerce/orders/index.blade.php dan modifikasi baris untuk menampilkan subtotal menjadi total.

<td>{{ number_format($row->total) }}</td>

Objek total merupakan sebuah Accessor, sehingga buka file app/Order.php dan tambahkan code berikut

public function getTotalAttribute()
{
    return $this->subtotal + $this->cost;
}

Jangan lupa pada bagian property $appends untuk menambahkan total

protected $appends = ['status_label', 'ref_status_label', 'commission', 'total'];

Baca Juga: Cara Membuat Sistem Komentar Dengan Laravel 7

Kesimpulan

Menambahkan fitur Ongkos kirim pada seri membuat aplikasi Ecommerce menggunakan Laravel 6, dimana kita membuat fitur integrasi data ongkos kirim dengan menggunakan API ongkos kirim dari RuangAPI.

Dokumentasi code dari materi ini bisa dilihat di Github.

Category:
Share:

Comments