Aplikasi E-Commerce Laravel 6 #15: Complaint & Return Order

Aplikasi E-Commerce Laravel 6 #15: Complaint & Return Order

Pendahuluan

Penanganan sebelum dan sesudah penjualan sangat penting dilakukan oleh bidang usaha yang bergerak pada jasa jual beli, maka diperlukan sebuah fitur dimana customer bisa dengan mudah untuk melakukan claim return order apabila pesanan yang diterimanya tidak sesuai dengan apa yang ditawarkan oleh penjual. Selain itu, fitur untuk menandai barang apabila sudah diterima oleh customer juga penting bagi pemilik usaha agar mengetahui layanan yang diberikannya sudah selesai.

Seri membuat aplikasi e-commerce laravel 6 kali ini akan membahas beberapa hal, diantaranya, memperbaiki error dari seri artikel sebelumnya, membuat fitur approve order untuk memastikan pesanan sudah selesai dan auto approve dalam waktu +15 hari setelah barang dikirim untuk menghindari jika customer lupa untuk melakukan konfirmasi, dan yang terakhir adalah fasilitas untuk complaint serta meminta return order dengan ketentuan customer mengirimkan alasan dilengkapi foto barang pesanan.

Baca Juga: Aplikasi E-Commerce Laravel 6 #14: Kelola Pesanan (Admin) & Broadcast Resi

[Issue] Checkout Page

Masalah yang dihadapi adalah pada seri sebelumnya kita membuat kolom input-an email otomatis terisi apabila customer sudah login, masalahnya adalah akan terjadi error ketika customer belum login, maka buka file ecommerce/checkout.blade.php dan modifikasi pada bagian kolom email.

<div class="col-md-6 form-group p_star">
    <label for="">Email</label>
    @if (auth()->guard('customer')->check())
    <input type="email" class="form-control" id="email" name="email" 
        value="{{ auth()->guard('customer')->user()->email }}" 
        required {{ auth()->guard('customer')->check() ? 'readonly':'' }}>
    @else
    <input type="email" class="form-control" id="email" name="email"
        required>
    @endif
    <p class="text-danger">{{ $errors->first('email') }}</p>
</div>

Approve Order By Customer

Ketika customer mengakses halaman untuk melihat seluruh list pesanan yang dimilikinya, maka sebuah tombol untuk menandai pesanan sudah diterima atau belum akan muncul disaat pesanan tersebut ber-status shippping (red: 3). Tahap pertama kita buat tombolnya terlebih dahulu, buka file ecommerce/orders/index.blade.php dan modifikasi tag yang ada di kolom button.

<form action="{{ route('customer.order_accept') }}" 
    class="form-inline"
    onsubmit="return confirm('Kamu Yakin?');" method="post">
    @csrf

    <!-- TOMBOL VIEW ORDER KITA BUNGKUS JG DENGAN FORM AGAR RAPI -->
    <a href="{{ route('customer.view_order', $row->invoice) }}" class="btn btn-primary btn-sm mr-1">Detail</a>
  
    <input type="hidden" name="order_id" value="{{ $row->id }}">
    @if ($row->status == 3)
        <button class="btn btn-success btn-sm">Terima</button>
        <!-- TOMBOL RETURN AKAN DITEMPATKAN DISINI PADA SUB-BAB SELANJUTNYA -->
    @endif
</form>

Penjelasan: Jadi kita menggunakan onsubmit pada form, dimana fungsi ini akan menampilkan popup konfirmasi sebelum mengirimkan form request. Kemudian data yang dikirimkan hanya order_id karena data berdasarkan id ini akan diubah status-nya menjadi 4 atau diterima.

Masih dengan file yang sama, tambahkan alert success berikut ini setelah alert danger di dalam class card-body.

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

Tugas selanjutnya adalah meng-handle request yang dikirimkan oleh customer, buka file Ecommerce/OrderController dan tambahkan method

public function acceptOrder(Request $request)
{
    //CARI DATA ORDER BERDASARKAN ID
    $order = Order::find($request->order_id);
    //VALIDASI KEPEMILIKAN
    if (!\Gate::forUser(auth()->guard('customer')->user())->allows('order-view', $order)) {
        return redirect()->back()->with(['error' => 'Bukan Pesanan Kamu']);
    }

    //UBAH STATUSNYA MENJADI 4
    $order->update(['status' => 4]);
    //REDIRECT KEMBALI DENGAN MENAMPILKAN ALERT SUCCESS
    return redirect()->back()->with(['success' => 'Pesanan Dikonfirmasi']);
}

Definisikan routing dari method di atas, buka file routes/web.php dan tambahkan baris berikut di dalam routing group yang menggunakan middleware customer

Route::post('orders/accept', 'OrderController@acceptOrder')->name('customer.order_accept');

Return Order

Skenario dari fitur ini adalah sebuah tombol return akan ditampilkan apabila status order sama dengan 3 atau shipping & belum pernah di-return sebelumnya, kemudian apabila tombol tersebut di-klik maka akan diarahkan ke halaman yang berisi sebuah form untuk memasukkan informasi terkait return dari produk tersebut.

Tahapan pertama adalah membuat tombolnya terlebih dahulu, buka file ecommerce/orders/index.blade.php dan modifikasi kembali kolom untuk menampilkan tombol menjadi

<form action="{{ route('customer.order_accept') }}" 
    class="form-inline"
    onsubmit="return confirm('Kamu Yakin?');" method="post">
    @csrf

    <a href="{{ route('customer.view_order', $row->invoice) }}" class="btn btn-primary btn-sm mr-1">Detail</a>
    <input type="hidden" name="order_id" value="{{ $row->id }}">

  	<!-- KONDISINYA DITAMBAHKAN, JIKA RETURN_COUNT = 0 -->
    @if ($row->status == 3 && $row->return_count == 0)
        <button class="btn btn-success btn-sm">Terima</button>
        <!-- TOMBOL UNTUK MENGARAH KE HALAMAN RETURN -->
        <a href="{{ route('customer.order_return', $row->invoice) }}" class="btn btn-danger btn-sm mt-1">Return</a>
    @endif
</form>

Mungkin ada pertanyaan, return_count di dapatkan dari mana? Dari code berikut yang akan kita lengkapi, dimana data tersebut adalah jumlah data yang berelasi dengan order terkait. Buat relasinya terlebih dahulu, buka file Order.php dan tambahkan method

public function return()
{
    return $this->hasOne(OrderReturn::class);
}

Untuk me-load relasi diatas, buka file Ecommerce/OrderController.php dan cari method index() lalu modifikasi menjadi

public function index()
{
    $orders = Order::withCount(['return'])->where('customer_id', auth()->guard('customer')->user()->id)
        ->orderBy('created_at', 'DESC')->paginate(10);
    return view('ecommerce.orders.index', compact('orders'));
}

Note: Ditambahkan withCount() untuk menghasilkan objek baru dengan format namarelasi_count.

Adapun untuk langkah selanjutnya adalah masih dengan file yang sama, tambahkan method berikut untuk me-load view form return.

public function returnForm($invoice)
{
    //LOAD DATA BERDASARKAN INVOICE
    $order = Order::where('invoice', $invoice)->first();
    //LOAD VIEW RETURN.BLADE.PHP DAN PASSING DATA ORDER
    return view('ecommerce.orders.return', compact('order'));
}

Buat file baru bernama return.blade.php di dalam folder ecommerce/orders dan tambahkan tag berikut

@extends('layouts.ecommerce')

@section('title')
    <title>Return {{ $order->invoice }} - DW Ecommerce</title>
@endsection

@section('content')
    <!--================Home Banner Area =================-->
	<section class="banner_area">
		<div class="banner_inner d-flex align-items-center">
			<div class="container">
				<div class="banner_content text-center">
					<h2>Return {{ $order->invoice }}</h2>
					<div class="page_link">
            <a href="{{ url('/') }}">Home</a>
            <a href="{{ route('customer.orders') }}">Return {{ $order->invoice }}</a>
					</div>
				</div>
			</div>
		</div>
	</section>
	<section class="login_box_area p_120">
		<div class="container">
			<div class="row">
				<div class="col-md-3">
					@include('layouts.ecommerce.module.sidebar')
				</div>
				<div class="col-md-9">
          <div class="card">
              <div class="card-body">
                  @if (session('success'))
                      <div class="alert alert-success">{{ session('success') }}</div>
                  @endif

                  @if (session('error'))
                      <div class="alert alert-danger">{{ session('error') }}</div>
                  @endif

                  <form action="{{ route('customer.return', $order->id) }}" method="post" enctype="multipart/form-data">
                      @csrf
                      <input type="hidden" name="_method" value="PUT">
                      <div class="form-group">
                          <label for="">Alasan Return</label>
                          <textarea name="reason" cols="5" rows="5" class="form-control" required></textarea>
                      </div>
                      <div class="form-group">
                          <label for="">Refund Transfer</label>
                          <input type="text" name="refund_transfer" class="form-control" required>
                      </div>
                      <div class="form-group">
                          <label for="">Foto</label>
                          <input type="file" name="photo" class="form-control" required>
                      </div>
                      <button class="btn btn-primary">Kirim</button>
                  </form>
              </div>
          </div>
				</div>
			</div>
		</div>
	</section>
@endsection

Penjelasan: Jadi code di atas adalah tag untuk menampilkan form inputan yang terdiri dari alasan complaint, tujuan pengembalian dana apabila return disetujui, dan yang terakhir adalah foto barang yang di-complaint.

Saatnya untuk meng-handle permintaan yang dikirimkan, adapun routing-nya akan dibuat bersamaan dengan routing proses complaint agar tidak bolak-balik membuka file routing. Di dalam file Ecommerce/OrderController.php tambahkan method

public function processReturn(Request $request, $id)
{
    //LAKUKAN VALIDASI DATA
    $this->validate($request, [
        'reason' => 'required|string',
        'refund_transfer' => 'required|string',
        'photo' => 'required|image|mimes:jpg,png,jpeg'
    ]);

    //CARI DATA RETURN BERDASARKAN order_id YANG ADA DITABLE ORDER_RETURNS NANTINYA
    $return = OrderReturn::where('order_id', $id)->first();
    //JIKA DITEMUKAN, MAKA TAMPILKAN NOTIFIKASI ERROR
    if ($return) return redirect()->back()->with(['error' => 'Permintaan Refund Dalam Proses']);

    //JIKA TIDAK, LAKUKAN PENGECEKAN UNTUK MEMASTIKAN FILE FOTO DIKIRIMKAN
    if ($request->hasFile('photo')) {
        //GET FILE
        $file = $request->file('photo');
        //GENERATE NAMA FILE BERDASARKAN TIME DAN STRING RANDOM
        $filename = time() . Str::random(5) . '.' . $file->getClientOriginalExtension();
        //KEMUDIAN UPLOAD KE DALAM FOLDER STORAGE/APP/PUBLIC/RETURN
        $file->storeAs('public/return', $filename);

        //DAN SIMPAN INFORMASINYA KE DALAM TABLE ORDER_RETURNS
        OrderReturn::create([
            'order_id' => $id,
            'photo' => $filename,
            'reason' => $request->reason,
            'refund_transfer' => $request->refund_transfer,
            'status' => 0
        ]);
        //LALU TAMPILKAN NOTIFIKASI SUKSES
        return redirect()->back()->with(['success' => 'Permintaan Refund Dikirim']);
    }
}

Jangan lupa untuk menambahkan use statement

use App\OrderReturn;
use Illuminate\Support\Str;

Dua langkah terakhir, kita definisikan routing-nya dengan menambahkan baris route berikut di dalam routes/web.php

Route::get('orders/return/{invoice}', 'OrderController@returnForm')->name('customer.order_return');
Route::put('orders/return/{invoice}', 'OrderController@processReturn')->name('customer.return');

Dan bagian terakhir adalah men-generate table-nya, pada command line, jalankan command

php artisan make:model OrderReturn -m

Kemudian 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 CreateOrderReturnsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('order_returns', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('order_id');
            $table->string('photo');
            $table->text('reason');
            $table->string('refund_transfer');
            $table->char('status', 1)->default(0)->comment('0: pending, 1: approve, 2: cancel');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('order_returns');
    }
}

Lalu di dalam file OrderReturn.php juga modifikasi dengan menambahkan sebaris code berikut untuk mengizinkan mass assignment menambahkan record baru.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class OrderReturn extends Model
{
    protected $guarded = [];
}

aplikasi ecommerce laravel 6 - return order

Baca Juga: Aplikasi E-Commerce Laravel 6 #13: Membuat Faktur PDF

Kesimpulan

Seluruh proses yang dibutuhkan dari sisi customer sudah dipenuhi, sehingga proses verifikasi return order akan dikerjakan dari sisi administrator dan fitur ini akan dikerjakan pada artikel berikutnya. Sepanjang artikel ini kita sudah belajar bagaimana menciptakan alur baru yang tidak ada di-schema database pada seri pertama dimana pesannya adalah bahwa keadaan apapun mungkin terjadi sesuai dengan perkembangan bisnis, maka sebagai seorang programmer kita harus bisa memahami kemana alur bisnis berjalan dan menerjemahkannya ke dalam code agar dapat diwujudkan dalam bentuk aplikasi.

Adapun dokumentasi code dari artikel di atas bisa dilihat di Github.

Category:
Share:

Comments