diff --git a/app/Http/Controllers/ProductsController.php b/app/Http/Controllers/ProductsController.php
new file mode 100644
index 0000000..df075fc
--- /dev/null
+++ b/app/Http/Controllers/ProductsController.php
@@ -0,0 +1,73 @@
+get('q');
+ $products = Product::where(function($query) use ($q) {
+ if ($q) {
+ $query->where('name', 'like', '%' . $q . '%');
+ }
+ })
+ ->orderBy('name')->paginate(25);
+
+ if (in_array($request->get('action'), ['edit','delete']) && $request->has('id'))
+ $editableProduct = Product::find($request->get('id'));
+
+ return view('products.index', compact('products','editableProduct'));
+ }
+
+ public function store(Request $request)
+ {
+ $this->validate($request, [
+ 'name' => 'required|max:20',
+ 'cash_price' => 'required|numeric',
+ 'credit_price' => 'nullable|numeric',
+ ]);
+
+ Product::create($request->only('name','cash_price','credit_price'));
+
+ flash(trans('product.created'), 'success');
+
+ return redirect()->route('products.index');
+ }
+
+ public function update(Request $request, $productId)
+ {
+ $this->validate($request, [
+ 'name' => 'required|max:20',
+ 'cash_price' => 'required|numeric',
+ 'credit_price' => 'nullable|numeric',
+ ]);
+
+ $routeParam = $request->only('q');
+
+ $product = Product::findOrFail($productId)->update($request->only('name','cash_price','credit_price'));
+
+ flash(trans('product.updated'), 'success');
+
+ return redirect()->route('products.index', $routeParam);
+ }
+
+ public function destroy(Request $request, $productId)
+ {
+ $this->validate($request, [
+ 'product_id' => 'required|exists:products,id',
+ ]);
+
+ if ($request->get('product_id') == $productId && Product::findOrFail($productId)->delete()) {
+ flash(trans('product.deleted'), 'success');
+ return redirect()->route('products.index');
+ }
+
+ flash(trans('product.undeleted'), 'error');
+ return back();
+ }
+}
diff --git a/app/Product.php b/app/Product.php
index e588cf3..27a9ef1 100644
--- a/app/Product.php
+++ b/app/Product.php
@@ -6,10 +6,11 @@ use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
- protected $fillable = ['cash_price', 'credit_price'];
+ protected $fillable = ['name','cash_price','credit_price'];
public function getPrice($type = 'cash')
{
+ // TODO: if there is no credit_price then return cash_price
if ($type == 'credit') {
return $this->credit_price;
}
diff --git a/database/migrations/2017_04_09_013901_create_products_table.php b/database/migrations/2017_04_09_013901_create_products_table.php
index 360433f..a10ac6d 100644
--- a/database/migrations/2017_04_09_013901_create_products_table.php
+++ b/database/migrations/2017_04_09_013901_create_products_table.php
@@ -17,7 +17,7 @@ class CreateProductsTable extends Migration
$table->increments('id');
$table->string('name');
$table->unsignedInteger('cash_price');
- $table->unsignedInteger('credit_price');
+ $table->unsignedInteger('credit_price')->nullable();
$table->timestamps();
});
}
diff --git a/resources/lang/id/master.php b/resources/lang/id/master.php
new file mode 100644
index 0000000..1a924e9
--- /dev/null
+++ b/resources/lang/id/master.php
@@ -0,0 +1,28 @@
+ 'Master',
+ 'list' => 'Daftar Master',
+ 'search' => 'Cari Master',
+ 'not_found' => 'Master tidak ditemukan',
+ 'empty' => 'Belum ada Master',
+ 'back_to_index' => 'Kembali ke daftar Master',
+
+ // Actions
+ 'create' => 'Input Master Baru',
+ 'created' => 'Input Master baru telah berhasil.',
+ 'show' => 'Detail Master',
+ 'edit' => 'Edit Master',
+ 'update' => 'Update Master',
+ 'updated' => 'Update data Master telah berhasil.',
+ 'delete' => 'Hapus Master',
+ 'delete_confirm' => 'Anda yakin akan menghapus Master ini?',
+ 'deleted' => 'Hapus data Master telah berhasil.',
+ 'undeleted' => 'Data Master gagal dihapus.',
+ 'undeleteable' => 'Data Master tidak dapat dihapus.',
+
+ // Attributes
+ 'name' => 'Nama Master',
+ 'description' => 'Deskripsi Master',
+];
\ No newline at end of file
diff --git a/resources/lang/id/product.php b/resources/lang/id/product.php
new file mode 100644
index 0000000..9fd4eca
--- /dev/null
+++ b/resources/lang/id/product.php
@@ -0,0 +1,30 @@
+ 'Produk',
+ 'list' => 'Daftar Produk',
+ 'search' => 'Cari Produk',
+ 'not_found' => 'Produk tidak ditemukan',
+ 'empty' => 'Belum ada Produk',
+ 'price' => 'Harga',
+ 'back_to_index' => 'Kembali ke daftar Produk',
+
+ // Actions
+ 'create' => 'Input Produk Baru',
+ 'created' => 'Input Produk baru telah berhasil.',
+ 'show' => 'Detail Produk',
+ 'edit' => 'Edit Produk',
+ 'update' => 'Update Produk',
+ 'updated' => 'Update data Produk telah berhasil.',
+ 'delete' => 'Hapus Produk',
+ 'delete_confirm' => 'Anda yakin akan menghapus Produk ini?',
+ 'deleted' => 'Hapus data Produk telah berhasil.',
+ 'undeleted' => 'Data Produk gagal dihapus.',
+ 'undeleteable' => 'Data Produk tidak dapat dihapus.',
+
+ // Attributes
+ 'name' => 'Nama Produk',
+ 'cash_price' => 'Harga Tunai',
+ 'credit_price' => 'Harga Kredit',
+];
\ No newline at end of file
diff --git a/resources/views/layouts/partials/top-nav.blade.php b/resources/views/layouts/partials/top-nav.blade.php
index 7fee250..019adf6 100644
--- a/resources/views/layouts/partials/top-nav.blade.php
+++ b/resources/views/layouts/partials/top-nav.blade.php
@@ -22,12 +22,15 @@
@if (Auth::check())
-
+
+ {{ link_to_route('products.index', trans('product.list')) }}
+
{{ Auth::user()->name }}
diff --git a/resources/views/products/index.blade.php b/resources/views/products/index.blade.php
new file mode 100644
index 0000000..11f3f47
--- /dev/null
+++ b/resources/views/products/index.blade.php
@@ -0,0 +1,50 @@
+@extends('layouts.app')
+
+@section('title', trans('product.list'))
+
+@section('content')
+
+
+
+
+
+
+ {{ Form::open(['method' => 'get','class' => 'form-inline']) }}
+ {!! FormField::text('q', ['value' => request('q'), 'label' => trans('product.search'), 'class' => 'input-sm']) !!}
+ {{ Form::submit(trans('product.search'), ['class' => 'btn btn-sm']) }}
+ {{ link_to_route('products.index', trans('app.reset')) }}
+ {{ Form::close() }}
+
+
+
+
+ | {{ trans('app.table_no') }} |
+ {{ trans('product.name') }} |
+ {{ trans('product.cash_price') }} |
+ {{ trans('product.credit_price') }} |
+ {{ trans('app.action') }} |
+
+
+
+
+ @foreach($products as $key => $product)
+
+ | {{ $products->firstItem() + $key }} |
+ {{ $product->name }} |
+ {{ formatRp($product->cash_price) }} |
+ {{ formatRp($product->credit_price) }} |
+
+ {!! link_to_route('products.index', trans('app.edit'), ['action' => 'edit', 'id' => $product->id] + Request::only('q'), ['id' => 'edit-product-' . $product->id]) !!} |
+ {!! link_to_route('products.index', trans('app.delete'), ['action' => 'delete', 'id' => $product->id] + Request::only('q'), ['id' => 'del-product-' . $product->id]) !!}
+ |
+
+ @endforeach
+
+
+
+
+
+ @include('products.partials.forms')
+
+
+@endsection
\ No newline at end of file
diff --git a/resources/views/products/partials/forms.blade.php b/resources/views/products/partials/forms.blade.php
new file mode 100644
index 0000000..6dc149b
--- /dev/null
+++ b/resources/views/products/partials/forms.blade.php
@@ -0,0 +1,47 @@
+@if (! Request::has('action'))
+{{ link_to_route('products.index', trans('product.create'), ['action' => 'create'], ['class' => 'btn btn-success pull-right']) }}
+@endif
+@if (Request::get('action') == 'create')
+ {!! Form::open(['route' => 'products.store']) !!}
+ {!! FormField::text('name', ['label' => trans('product.name'), 'required' => true]) !!}
+
+
{!! FormField::price('cash_price', ['label' => trans('product.cash_price'), 'required' => true]) !!}
+
{!! FormField::price('credit_price', ['label' => trans('product.credit_price')]) !!}
+
+ {!! Form::submit(trans('product.create'), ['class' => 'btn btn-success']) !!}
+ {!! Form::hidden('cat', 'product') !!}
+ {{ link_to_route('products.index', trans('app.cancel'), [], ['class' => 'btn btn-default']) }}
+ {!! Form::close() !!}
+@endif
+@if (Request::get('action') == 'edit' && $editableProduct)
+ {!! Form::model($editableProduct, ['route' => ['products.update', $editableProduct->id],'method' => 'patch']) !!}
+ {!! FormField::text('name', ['label' => trans('product.name'), 'required' => true]) !!}
+
+
{!! FormField::price('cash_price', ['label' => trans('product.cash_price'), 'required' => true]) !!}
+
{!! FormField::price('credit_price', ['label' => trans('product.credit_price')]) !!}
+
+ {{ Form::hidden('q', request('q')) }}
+ {!! Form::submit(trans('product.update'), ['class' => 'btn btn-success']) !!}
+ {{ link_to_route('products.index', trans('app.cancel'), Request::only('q'), ['class' => 'btn btn-default']) }}
+ {!! Form::close() !!}
+@endif
+@if (Request::get('action') == 'delete' && $editableProduct)
+
+
{{ trans('product.delete') }}
+
+
+
+ | {{ trans('product.name') }} | {{ $editableProduct->name }} |
+ | {{ trans('product.cash_price') }} | {{ formatRp($editableProduct->cash_price) }} |
+ | {{ trans('product.credit_price') }} | {{ formatRp($editableProduct->credit_price) }} |
+
+
+
+ {{ trans('product.delete_confirm') }}
+
+
+
+@endif
diff --git a/routes/web.php b/routes/web.php
index cb21749..6505f66 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -17,8 +17,15 @@ Route::get('/', function () {
Auth::routes();
-Route::get('/home', 'CartController@index')->name('home');
Route::group(['middleware' => 'auth'], function () {
+ /**
+ * Pages Routes
+ */
+ Route::get('/home', 'CartController@index')->name('home');
+
+ /**
+ * Cart / Trasanction Draft Routes
+ */
Route::get('drafts', 'CartController@index')->name('cart.index');
Route::get('drafts/{draftKey}', 'CartController@show')->name('cart.show');
Route::post('drafts/{draftKey}', 'CartController@store')->name('cart.store');
@@ -30,4 +37,9 @@ Route::group(['middleware' => 'auth'], function () {
Route::delete('cart/empty/{draftKey}', 'CartController@empty')->name('cart.empty');
Route::delete('cart/remove', 'CartController@remove')->name('cart.remove');
Route::delete('cart/destroy', 'CartController@destroy')->name('cart.destroy');
+
+ /**
+ * Products Routes
+ */
+ Route::resource('products', 'ProductsController');
});
diff --git a/tests/Feature/ManageProductsTest.php b/tests/Feature/ManageProductsTest.php
new file mode 100644
index 0000000..1801e91
--- /dev/null
+++ b/tests/Feature/ManageProductsTest.php
@@ -0,0 +1,154 @@
+create(['name' => 'Testing 123']);
+ $product2 = factory(Product::class)->create(['name' => 'Testing 456']);
+
+ $this->loginAsUser();
+ $this->visit(route('products.index'));
+ $this->see($product1->name);
+ $this->see($product2->name);
+ }
+
+ /** @test */
+ public function user_can_search_product_by_keyword()
+ {
+ $this->loginAsUser();
+ $product1 = factory(Product::class)->create(['name' => 'Testing 123']);
+ $product2 = factory(Product::class)->create(['name' => 'Testing 456']);
+
+ $this->visit(route('products.index'));
+ $this->submitForm(trans('product.search'), ['q' => '123']);
+ $this->seePageIs(route('products.index', ['q' => 123]));
+
+ $this->see($product1->name);
+ $this->dontSee($product2->name);
+ }
+
+ /** @test */
+ public function user_can_create_a_product()
+ {
+ $this->loginAsUser();
+ $this->visit(route('products.index'));
+
+ $this->click(trans('product.create'));
+ $this->seePageIs(route('products.index', ['action' => 'create']));
+
+ $this->type('Product 1', 'name');
+ $this->type('1000', 'cash_price');
+ $this->type('1200', 'credit_price');
+ $this->press(trans('product.create'));
+
+ $this->seePageIs(route('products.index'));
+ $this->see(trans('product.created'));
+
+ $this->seeInDatabase('products', [
+ 'name' => 'Product 1',
+ 'cash_price' => 1000,
+ 'credit_price' => 1200,
+ ]);
+ }
+
+ /** @test */
+ public function user_can_edit_a_product_within_search_query()
+ {
+ $this->loginAsUser();
+ $product = factory(Product::class)->create(['name' => 'Testing 123']);
+
+ $this->visit(route('products.index', ['q' => '123']));
+ $this->click('edit-product-' . $product->id);
+ $this->seePageIs(route('products.index', ['action' => 'edit','id' => $product->id, 'q' => '123']));
+
+ $this->type('Product 1', 'name');
+ $this->type('1000', 'cash_price');
+ $this->type('1200', 'credit_price');
+ $this->press(trans('product.update'));
+
+ $this->seePageIs(route('products.index', ['q' => '123']));
+
+ $this->seeInDatabase('products', [
+ 'name' => 'Product 1',
+ 'cash_price' => 1000,
+ 'credit_price' => 1200,
+ ]);
+ }
+
+ /** @test */
+ public function user_can_create_a_product_with_only_cash_price()
+ {
+ $this->loginAsUser();
+ $this->visit(route('products.index'));
+
+ $this->click(trans('product.create'));
+ $this->seePageIs(route('products.index', ['action' => 'create']));
+
+ $this->type('Product 1', 'name');
+ $this->type('1000', 'cash_price');
+ $this->type('', 'credit_price');
+ $this->press(trans('product.create'));
+
+ $this->seePageIs(route('products.index'));
+ $this->see(trans('product.created'));
+
+ $this->seeInDatabase('products', [
+ 'name' => 'Product 1',
+ 'cash_price' => 1000,
+ 'credit_price' => null,
+ ]);
+ }
+
+ /** @test */
+ public function user_can_edit_a_product()
+ {
+ $this->loginAsUser();
+ $product = factory(Product::class)->create();
+
+ $this->visit(route('products.index'));
+ $this->click('edit-product-' . $product->id);
+ $this->seePageIs(route('products.index', ['action' => 'edit','id' => $product->id]));
+
+ $this->type('Product 1', 'name');
+ $this->type('1000', 'cash_price');
+ $this->type('1200', 'credit_price');
+ $this->press(trans('product.update'));
+
+ $this->seeInDatabase('products', [
+ 'name' => 'Product 1',
+ 'cash_price' => 1000,
+ 'credit_price' => 1200,
+ ]);
+ }
+
+ /** @test */
+ public function user_can_delete_a_product()
+ {
+ $this->loginAsUser();
+ $product = factory(Product::class)->create();
+
+ $this->visit(route('products.index'));
+ $this->click('del-product-' . $product->id);
+ $this->seePageIs(route('products.index', ['action' => 'delete','id' => $product->id]));
+
+ $this->seeInDatabase('products', [
+ 'id' => $product->id
+ ]);
+
+ $this->press(trans('app.delete_confirm_button'));
+
+ $this->dontSeeInDatabase('products', [
+ 'id' => $product->id
+ ]);
+ }
+}