diff --git a/app/Http/Controllers/ProductsController.php b/app/Http/Controllers/ProductsController.php
index a23d1a4..fbd2104 100644
--- a/app/Http/Controllers/ProductsController.php
+++ b/app/Http/Controllers/ProductsController.php
@@ -30,9 +30,10 @@ class ProductsController extends Controller
'name' => 'required|max:20',
'cash_price' => 'required|numeric',
'credit_price' => 'nullable|numeric',
+ 'unit_id' => 'required|numeric',
]);
- Product::create($request->only('name','cash_price','credit_price'));
+ Product::create($request->only('name','cash_price','credit_price','unit_id'));
flash(trans('product.created'), 'success');
@@ -49,7 +50,7 @@ class ProductsController extends Controller
$routeParam = $request->only('q');
- $product = Product::findOrFail($productId)->update($request->only('name','cash_price','credit_price'));
+ $product = Product::findOrFail($productId)->update($request->only('name','cash_price','credit_price','unit_id'));
flash(trans('product.updated'), 'success');
diff --git a/app/Http/Controllers/UnitsController.php b/app/Http/Controllers/UnitsController.php
new file mode 100644
index 0000000..7c34245
--- /dev/null
+++ b/app/Http/Controllers/UnitsController.php
@@ -0,0 +1,63 @@
+get('action'), ['edit','delete']) && $request->has('id'))
+ $editableUnit = Unit::find($request->get('id'));
+
+ return view('units.index', compact('units','editableUnit'));
+ }
+
+ public function store(Request $request)
+ {
+ $this->validate($request, [
+ 'name' => 'required|max:20',
+ ]);
+
+ Unit::create($request->only('name'));
+
+ flash(trans('unit.created'), 'success');
+
+ return redirect()->route('units.index');
+ }
+
+ public function update(Request $request, $unitId)
+ {
+ $this->validate($request, [
+ 'name' => 'required|max:20',
+ ]);
+
+ $unit = Unit::findOrFail($unitId)->update($request->only('name'));
+
+ flash(trans('unit.updated'), 'success');
+
+ return redirect()->route('units.index');
+ }
+
+ public function destroy(Request $request, Unit $unit)
+ {
+ $this->validate($request, [
+ 'unit_id' => 'required|exists:product_units,id|not_exists:products,unit_id',
+ ], [
+ 'unit_id.not_exists' => trans('unit.undeleted')
+ ]);
+
+ if ($request->get('unit_id') == $unit->id && $unit->delete()) {
+ flash(trans('unit.deleted'), 'success');
+ return redirect()->route('units.index');
+ }
+
+ flash(trans('unit.undeleted'), 'error');
+ return back();
+ }
+}
diff --git a/app/Product.php b/app/Product.php
index 27a9ef1..b85d0e3 100644
--- a/app/Product.php
+++ b/app/Product.php
@@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
- protected $fillable = ['name','cash_price','credit_price'];
+ protected $fillable = ['name','cash_price','credit_price','unit_id'];
public function getPrice($type = 'cash')
{
@@ -17,4 +17,9 @@ class Product extends Model
return $this->cash_price;
}
+
+ public function unit()
+ {
+ return $this->belongsTo(Unit::class);
+ }
}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 9d001f6..332188f 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -14,6 +14,12 @@ class AppServiceProvider extends ServiceProvider
public function boot()
{
require_once app_path().'/Helpers/helpers.php';
+ \Validator::extend('not_exists', function($attribute, $value, $parameters)
+ {
+ return \DB::table($parameters[0])
+ ->where($parameters[1], $value)
+ ->count() < 1;
+ });
}
/**
diff --git a/app/Unit.php b/app/Unit.php
new file mode 100644
index 0000000..8d98a37
--- /dev/null
+++ b/app/Unit.php
@@ -0,0 +1,11 @@
+define(App\User::class, function (Faker\Generator $faker) {
return [
@@ -25,7 +14,17 @@ $factory->define(App\User::class, function (Faker\Generator $faker) {
$factory->define(App\Product::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
+ 'unit_id' => function() {
+ return factory(App\Unit::class)->create()->id;
+ },
'cash_price' => 2000,
'credit_price' => 1000,
];
});
+
+/* @var \Illuminate\Database\Eloquent\Factory $factory */
+$factory->define(App\Unit::class, function (Faker\Generator $faker) {
+ return [
+ 'name' => $faker->name,
+ ];
+});
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 a10ac6d..fe2aad4 100644
--- a/database/migrations/2017_04_09_013901_create_products_table.php
+++ b/database/migrations/2017_04_09_013901_create_products_table.php
@@ -15,7 +15,8 @@ class CreateProductsTable extends Migration
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
- $table->string('name');
+ $table->string('name', 60);
+ $table->unsignedInteger('unit_id');
$table->unsignedInteger('cash_price');
$table->unsignedInteger('credit_price')->nullable();
$table->timestamps();
diff --git a/database/migrations/2017_05_02_211915_create_product_units_table.php b/database/migrations/2017_05_02_211915_create_product_units_table.php
new file mode 100644
index 0000000..ff7747c
--- /dev/null
+++ b/database/migrations/2017_05_02_211915_create_product_units_table.php
@@ -0,0 +1,32 @@
+increments('id');
+ $table->string('name', 20);
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('product_units');
+ }
+}
diff --git a/resources/views/layouts/partials/top-nav.blade.php b/resources/views/layouts/partials/top-nav.blade.php
index 019adf6..526b462 100644
--- a/resources/views/layouts/partials/top-nav.blade.php
+++ b/resources/views/layouts/partials/top-nav.blade.php
@@ -28,9 +28,8 @@
-
- {{ link_to_route('products.index', trans('product.list')) }}
-
+ {{ link_to_route('products.index', trans('product.list')) }}
+ {{ link_to_route('units.index', trans('unit.list')) }}
{{ Auth::user()->name }}
diff --git a/resources/views/products/partials/forms.blade.php b/resources/views/products/partials/forms.blade.php
index 0f295ba..683320d 100644
--- a/resources/views/products/partials/forms.blade.php
+++ b/resources/views/products/partials/forms.blade.php
@@ -1,3 +1,4 @@
+@inject('unit', 'App\Unit')
@if (! Request::has('action'))
{{ link_to_route('products.index', trans('product.create'), ['action' => 'create'], ['class' => 'btn btn-success pull-right']) }}
@endif
@@ -8,6 +9,7 @@
{!! FormField::price('cash_price', ['label' => trans('product.cash_price'), 'required' => true]) !!}
{!! FormField::price('credit_price', ['label' => trans('product.credit_price')]) !!}
+ {!! FormField::select('unit_id', $unit->pluck('name','id'), ['label' => trans('product.unit'), 'required' => true]) !!}
{!! 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']) }}
@@ -20,6 +22,7 @@
{!! FormField::price('cash_price', ['label' => trans('product.cash_price'), 'required' => true]) !!}
{!! FormField::price('credit_price', ['label' => trans('product.credit_price')]) !!}
+ {!! FormField::select('unit_id', $unit->pluck('name','id'), ['label' => trans('product.unit'), 'required' => true]) !!}
@if (request('q'))
{{ Form::hidden('q', request('q')) }}
@endif
@@ -34,6 +37,7 @@
| {{ trans('product.name') }} | {{ $editableProduct->name }} |
+ | {{ trans('product.unit') }} | {{ $editableProduct->unit->name }} |
| {{ trans('product.cash_price') }} | {{ formatRp($editableProduct->cash_price) }} |
| {{ trans('product.credit_price') }} | {{ formatRp($editableProduct->credit_price) }} |
diff --git a/resources/views/units/index.blade.php b/resources/views/units/index.blade.php
new file mode 100644
index 0000000..f4a5413
--- /dev/null
+++ b/resources/views/units/index.blade.php
@@ -0,0 +1,35 @@
+@extends('layouts.app')
+
+@section('title', trans('unit.list'))
+
+@section('content')
+
+
+
+
+
+
+
+ | {{ trans('app.table_no') }} |
+ {{ trans('unit.name') }} |
+ {{ trans('app.action') }} |
+
+
+
+ @foreach($units as $key => $unit)
+
+ | {{ 1 + $key }} |
+ {{ $unit->name }} |
+
+ {!! link_to_route('units.index', trans('app.edit'), ['action' => 'edit', 'id' => $unit->id], ['id' => 'edit-unit-' . $unit->id]) !!} |
+ {!! link_to_route('units.index', trans('app.delete'), ['action' => 'delete', 'id' => $unit->id], ['id' => 'del-unit-' . $unit->id]) !!}
+ |
+
+ @endforeach
+
+
+
+
+
@include('units.partials.forms')
+
+@endsection
\ No newline at end of file
diff --git a/resources/views/units/partials/forms.blade.php b/resources/views/units/partials/forms.blade.php
new file mode 100644
index 0000000..f4e2668
--- /dev/null
+++ b/resources/views/units/partials/forms.blade.php
@@ -0,0 +1,33 @@
+@if (! Request::has('action'))
+{{ link_to_route('units.index', trans('unit.create'), ['action' => 'create'], ['class' => 'btn btn-success pull-right']) }}
+@endif
+@if (Request::get('action') == 'create')
+ {!! Form::open(['route' => 'units.store']) !!}
+ {!! FormField::text('name') !!}
+ {!! Form::submit(trans('unit.create'), ['class' => 'btn btn-success']) !!}
+ {{ link_to_route('units.index', trans('app.cancel'), [], ['class' => 'btn btn-default']) }}
+ {!! Form::close() !!}
+@endif
+@if (Request::get('action') == 'edit' && $editableUnit)
+ {!! Form::model($editableUnit, ['route' => ['units.update', $editableUnit->id],'method' => 'patch']) !!}
+ {!! FormField::text('name') !!}
+ {!! Form::submit(trans('unit.update'), ['class' => 'btn btn-success']) !!}
+ {{ link_to_route('units.index', trans('app.cancel'), [], ['class' => 'btn btn-default']) }}
+ {!! Form::close() !!}
+@endif
+@if (Request::get('action') == 'delete' && $editableUnit)
+
+
{{ trans('unit.delete') }}
+
+
+
{{ $editableUnit->name }}
+ {!! $errors->first('unit_id', '
:message') !!}
+
+
+
{{ trans('app.delete_confirm') }}
+
+
+@endif
\ No newline at end of file
diff --git a/routes/web.php b/routes/web.php
index 6505f66..a747ce9 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -41,5 +41,10 @@ Route::group(['middleware' => 'auth'], function () {
/**
* Products Routes
*/
- Route::resource('products', 'ProductsController');
+ Route::resource('products', 'ProductsController', ['except' => ['create','show','edit']]);
+
+ /**
+ * Units Routes
+ */
+ Route::resource('units', 'UnitsController', ['except' => ['create','show','edit']]);
});
diff --git a/tests/Feature/ManageProductsTest.php b/tests/Feature/ManageProductsTest.php
index a4ff7b8..e606be4 100644
--- a/tests/Feature/ManageProductsTest.php
+++ b/tests/Feature/ManageProductsTest.php
@@ -3,6 +3,7 @@
namespace Tests\Feature;
use App\Product;
+use App\Unit;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Tests\BrowserKitTestCase;
@@ -40,6 +41,7 @@ class ManageProductsTest extends BrowserKitTestCase
/** @test */
public function user_can_create_a_product()
{
+ $unit = factory(Unit::class)->create(['name' => 'Testing 123']);
$this->loginAsUser();
$this->visit(route('products.index'));
@@ -49,6 +51,7 @@ class ManageProductsTest extends BrowserKitTestCase
$this->type('Product 1', 'name');
$this->type('1000', 'cash_price');
$this->type('1200', 'credit_price');
+ $this->type($unit->id, 'unit_id');
$this->press(trans('product.create'));
$this->seePageIs(route('products.index'));
@@ -64,6 +67,7 @@ class ManageProductsTest extends BrowserKitTestCase
/** @test */
public function user_can_edit_a_product_within_search_query()
{
+ $unit = factory(Unit::class)->create(['name' => 'Testing 123']);
$this->loginAsUser();
$product = factory(Product::class)->create(['name' => 'Testing 123']);
@@ -74,6 +78,7 @@ class ManageProductsTest extends BrowserKitTestCase
$this->type('Product 1', 'name');
$this->type('1000', 'cash_price');
$this->type('1200', 'credit_price');
+ $this->type($unit->id, 'unit_id');
$this->press(trans('product.update'));
$this->seePageIs(route('products.index', ['q' => '123']));
@@ -88,6 +93,7 @@ class ManageProductsTest extends BrowserKitTestCase
/** @test */
public function user_can_create_a_product_with_only_cash_price()
{
+ $unit = factory(Unit::class)->create(['name' => 'Testing 123']);
$this->loginAsUser();
$this->visit(route('products.index'));
@@ -97,6 +103,7 @@ class ManageProductsTest extends BrowserKitTestCase
$this->type('Product 1', 'name');
$this->type('1000', 'cash_price');
$this->type('', 'credit_price');
+ $this->type($unit->id, 'unit_id');
$this->press(trans('product.create'));
$this->seePageIs(route('products.index'));
@@ -112,6 +119,7 @@ class ManageProductsTest extends BrowserKitTestCase
/** @test */
public function user_can_edit_a_product()
{
+ $unit = factory(Unit::class)->create(['name' => 'Testing 123']);
$this->loginAsUser();
$product = factory(Product::class)->create();
@@ -122,6 +130,7 @@ class ManageProductsTest extends BrowserKitTestCase
$this->type('Product 1', 'name');
$this->type('1000', 'cash_price');
$this->type('1200', 'credit_price');
+ $this->type($unit->id, 'unit_id');
$this->press(trans('product.update'));
$this->seeInDatabase('products', [
diff --git a/tests/Feature/ManageUnitsTest.php b/tests/Feature/ManageUnitsTest.php
new file mode 100644
index 0000000..c7a142e
--- /dev/null
+++ b/tests/Feature/ManageUnitsTest.php
@@ -0,0 +1,108 @@
+create(['name' => 'Testing 123']);
+ $unit2 = factory(Unit::class)->create(['name' => 'Testing 456']);
+
+ $this->loginAsUser();
+ $this->visit(route('units.index'));
+ $this->see($unit1->name);
+ $this->see($unit2->name);
+ }
+
+ /** @test */
+ public function user_can_create_a_unit()
+ {
+ $this->loginAsUser();
+ $this->visit(route('units.index'));
+
+ $this->click(trans('unit.create'));
+ $this->seePageIs(route('units.index', ['action' => 'create']));
+
+ $this->type('Unit 1', 'name');
+ $this->press(trans('unit.create'));
+
+ $this->seePageIs(route('units.index'));
+ $this->see(trans('unit.created'));
+
+ $this->seeInDatabase('product_units', [
+ 'name' => 'Unit 1',
+ ]);
+ }
+
+ /** @test */
+ public function user_can_edit_a_unit()
+ {
+ $this->loginAsUser();
+ $unit = factory(Unit::class)->create();
+
+ $this->visit(route('units.index'));
+ $this->click('edit-unit-' . $unit->id);
+ $this->seePageIs(route('units.index', ['action' => 'edit','id' => $unit->id]));
+
+ $this->type('Unit 1', 'name');
+ $this->press(trans('unit.update'));
+
+ $this->see(trans('unit.updated'));
+ $this->seePageIs(route('units.index'));
+
+ $this->seeInDatabase('product_units', [
+ 'name' => 'Unit 1',
+ ]);
+ }
+
+ /** @test */
+ public function user_can_delete_a_unit()
+ {
+ $this->loginAsUser();
+ $unit = factory(Unit::class)->create();
+
+ $this->visit(route('units.index'));
+ $this->click('del-unit-' . $unit->id);
+ $this->seePageIs(route('units.index', ['action' => 'delete','id' => $unit->id]));
+
+ $this->seeInDatabase('product_units', [
+ 'id' => $unit->id
+ ]);
+
+ $this->press(trans('app.delete_confirm_button'));
+
+ $this->dontSeeInDatabase('product_units', [
+ 'id' => $unit->id
+ ]);
+ }
+
+ /** @test */
+ public function user_can_not_delete_a_unit_that_has_product()
+ {
+ $this->loginAsUser();
+ $product = factory(Product::class)->create();
+ $unitId = $product->unit_id;
+
+ $this->visit(route('units.index'));
+ $this->click('del-unit-' . $unitId);
+ $this->seePageIs(route('units.index', ['action' => 'delete','id' => $unitId]));
+
+ $this->press(trans('app.delete_confirm_button'));
+
+ $this->see(trans('unit.undeleted'));
+ $this->seePageIs(route('units.index', ['action' => 'delete','id' => $unitId]));
+
+ $this->seeInDatabase('product_units', [
+ 'id' => $unitId
+ ]);
+ }
+}