Berikut adalah langkah-langkah detail untuk menambahkan fitur ongkos kirim menggunakan API dari RajaOngkir ke dalam web e-commerce Laravel yang telah kita buat sebelumnya.

Langkah 1: Daftar dan Dapatkan API Key RajaOngkir

  1. Daftar akun di RajaOngkir.
  2. Pilih paket yang sesuai (Starter sudah cukup untuk testing).
  3. Salin API Key yang diberikan di dashboard RajaOngkir.

Langkah 2: Install Guzzle HTTP Client

RajaOngkir memerlukan HTTP request untuk mengambil data. Install Guzzle:

composer require guzzlehttp/guzzle

Langkah 3: Buat File Config untuk RajaOngkir

Buat file config di config/rajaongkir.php:

<?php

return [
    'api_key' => env('RAJAONGKIR_API_KEY'),
    'base_url' => env('RAJAONGKIR_BASE_URL', 'https://api.rajaongkir.com/starter/'),
];

Tambahkan API Key ke file .env:

RAJAONGKIR_API_KEY=your_api_key
RAJAONGKIR_BASE_URL=https://api.rajaongkir.com/starter/

Langkah 4: Tambahkan Service untuk RajaOngkir

Buat service di config/service.php dan tambahkan config berikut:

'ses' => [
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
    ],
        'rajaongkir' => [
        'api_key' => env('RAJAONGKIR_API_KEY'),
        'base_url' => 'https://api.rajaongkir.com/starter/',
    ],

Langkah 5: Buat Controller

Buat controller untuk menangani ongkos kirim:

php artisan make:controller ShippingController

Tambahkan ke ShippingController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class ShippingController extends Controller
{
    public function getProvinces()
    {
        try {
            $response = Http::withHeaders([
                'key' => config('services.rajaongkir.api_key'),
            ])->get(config('services.rajaongkir.base_url') . 'province');

            if ($response->successful()) {
                return response()->json($response->json()['rajaongkir']['results']);
            }

            return response()->json(['error' => $response->json()], $response->status());
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }

    public function getCities(Request $request)
    {
        $provinceId = $request->province_id;

        // Panggil API RajaOngkir untuk mendapatkan data kota
        $response = Http::withHeaders([
            'key' => config('services.rajaongkir.api_key'),
        ])->get(config('services.rajaongkir.base_url') . 'city', [
            'province' => $provinceId,
        ]);

        // Periksa jika response sukses
        if ($response->successful()) {
            return response()->json($response->json()['rajaongkir']['results']);
        } else {
            return response()->json(['error' => $response->json()], $response->status());
        }
    }

    public function getShippingCost(Request $request)
    {
        $total = $request->total; // Total produk dari frontend
        
        $validated = $request->validate([
            'city' => 'required|integer',
            'weight' => 'required|integer|min:1',
            'courier' => 'required|string',
        ]);

        try {
            // Panggil API RajaOngkir
            $response = Http::withHeaders([
                'key' => config('services.rajaongkir.api_key'),
            ])->post('https://api.rajaongkir.com/starter/cost', [
                'origin' => 114,
                'destination' => $validated['city'],
                'weight' => $validated['weight'],
                'courier' => $validated['courier'],
            ]);
        
            $data = $response->json();

            if (isset($data['rajaongkir']['results'][0]['costs'])) {
                $shippingCost = $response->json()['rajaongkir']['results'][0]['costs'][0]['cost'][0]['value']; // Ongkos kirim

                $grandTotal = $total + $shippingCost; // Total keseluruhan

                return response()->json([
                    'cost' => $data['rajaongkir']['results'][0]['costs'][0]['cost'][0]['value'],
                    'estimate' => $data['rajaongkir']['results'][0]['costs'][0]['cost'][0]['etd'],
                    'grandTotal' =>$grandTotal,
                ]);
            }else if ($response->failed()) {
                return response()->json([
                    'error' => 'Failed to calculate shipping cost: ' . $response->json()['rajaongkir']['status']['description'] ?? 'Unknown error'
                ], 400);
            }
        
            return response()->json(['error' => 'Failed to calculate shipping cost'], 400);
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }
}

Langkah 6: Tambahkan Routes

Tambahkan route di routes/web.php:

Route::get('/provinces', [ShippingController::class, 'getProvinces'])->name('provinces');
Route::get('/cities', [ShippingController::class, 'getCities'])->name('cities');
Route::post('/calculate-shipping', [ShippingController::class, 'getShippingCost'])->name('calculate.shipping');

Langkah 7: Update Halaman Checkout

Di resources/views/frontend/checkout.blade.php, tambahkan form untuk memilih provinsi, kota, dan kurir:

@extends('layouts.frontend')

@section('content')
<div class="container">
    <h2>Checkout</h2>
    <form action="{{ route('checkout.process') }}" method="POST" id="paymentForm">
         <!-- Address Fields -->
         <h4>Billing Address</h4>
        <div class="mb-3">
            <label for="address" class="form-label">Address</label>
            <textarea class="form-control" name="address" id="address" rows="3" required>{{ old('address') }}</textarea>
        </div>
        <div class="mb-3">
            <label for="province">Province</label>
            <select class="form-control" id="province" name="province" value="{{ old('state') }}" required>
                <option value="">Select Province</option>
            </select>
        </div>
        <div class="mb-3">
            <label for="city">City</label>
            <select class="form-control" id="city" name="city" value="{{ old('city') }}" required>
                <option value="">Select City</option>
            </select>
        </div>
        <div class="mb-3">
            <label for="zip" class="form-label">ZIP Code</label>
            <input type="text" class="form-control" name="zip" id="zip" value="{{ old('zip') }}" required>
        </div>
        <div class="mb-3">
            <label for="courier">Courier</label>
            <select class="form-control" id="courier" name="courier">
                <option value="jne">JNE</option>
                <option value="pos">POS</option>
                <option value="tiki">TIKI</option>
            </select>
        </div>
        <div class="mb-3">
            <label for="weight">Weight (gram)</label>
            <input class="form-control" type="number" id="weight" name="weight" value="1000">
        </div>
        
        <div id="shippingResult"></div>
        <input class="form-control" type="hidden" id="total" name="total" value="{{ $total }}">

        <h4>Order Summary</h4>
        <ul>
            @foreach ($cart as $item)
            <li>{{ $item['name'] }} - {{ $item['quantity'] }} x ${{ $item['price'] }}</li>
            @endforeach
        </ul>
        <div id="grandtotal"><strong>Total: </strong> ${{ number_format($total, 2) }}</div>
        <button type="submit" class="btn btn-primary btn-space">Place Order</button>
    </form>
</div>
@endsection
@section('script')
<script src="https://code.jquery.com/jquery-3.7.1.js" integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
<script>
 document.addEventListener('DOMContentLoaded', function () {
        const provinceDropdown = document.getElementById('province');
        const cityDropdown = document.getElementById('city');

        // Fetch provinces
        fetch('{{ route('provinces') }}')
            .then(response => response.json())
            .then(data => {
                data.forEach(province => {
                    const option = document.createElement('option');
                    option.value = province.province_id;
                    option.textContent = province.province;
                    provinceDropdown.appendChild(option);
                });
            });

            $('#province').change(function () {
            let provinceId = $(this).val();

            if (provinceId) {
                $.ajax({
                    url: '/cities',
                    type: 'GET',
                    data: { province_id: provinceId },
                    dataType: 'json',
                    success: function (data) {
                        let cityDropdown = $('#city');
                        cityDropdown.empty();
                        cityDropdown.append('<option value="">Select City</option>');

                        $.each(data, function (key, city) {
                            cityDropdown.append(`<option value="${city.city_id}">${city.city_name}</option>`);
                        });
                    },
                    error: function (xhr) {
                        alert('Error fetching city data');
                    },
                });
            }
        });
    });
</script>

<script>
    $(document).ready(function () {
    // Setup CSRF token for AJAX requests
    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
        },
    });

    // Event listener untuk city
    $(document).on('change', '#city', function () {
        let city = $(this).val();
        console.log('Selected city:', city); // Debugging
        let weight = $('#weight').val();
        let courier = $('#courier').val();
        let total = $('#total').val();
       
        if (city && weight && courier) {
            calculateShipping(city, weight, courier, total);
        }
    });

    // Function untuk menghitung ongkir
    function calculateShipping(city, weight, courier, total) {
        let token = $("meta[name='csrf-token']").attr("content");
        
        $.ajax({
            url: '/calculate-shipping',
            type: 'POST',
            data: {
                city: city,
                weight: weight,
                courier: courier,
                _token: token,
                total: total,
            },
            success: function (response) {
                $('#shippingResult').html(`
                    <p>Shipping Cost: ${response.cost}</p>
                    <p>Estimated Delivery Time: ${response.estimate}</p>
                    <p>Grand Total: ${response.grandTotal}</p>
                `);
                $('#grandtotal').html(`Total:
                    ${response.grandTotal}
                `);
            },
            error: function (xhr, status, error) {
                alert('Error calculating shipping cost: ' + xhr.responseText);
            },
        });
    }
});
    </script>
@endsection('script')

Langkah 8: Uji Fitur Ongkos Kirim

Silahkan check out salah satu produk.  Kemudian jika berhasil, untuk Provinsi dan City otomatis ketika diklik akan memanggil API Rajaongkir untuk get province dan city. Dan ketika province dipilih, akan memunculkan dropdown bertingkat untuk city sebagai berikut:

Auto isi API Province dan city

Lalu otomatis akan menghitung biaya ongkos kirim seperti berikut:

Calculate shipping rajaongkir

Selamat mencoba!!! Silahkan tinggalkan komentar jika belum berhasil