Skip to content

Commit

Permalink
Merge pull request #40 from phi-rakib/30-implement-crud-operations-fo…
Browse files Browse the repository at this point in the history
…r-adjustment

30 implement crud operations for adjustment
  • Loading branch information
phi-rakib authored Jun 5, 2024
2 parents 9777698 + ad92659 commit be5bb6a
Show file tree
Hide file tree
Showing 13 changed files with 670 additions and 0 deletions.
159 changes: 159 additions & 0 deletions app/Http/Controllers/AdjustmentController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreAdjustmentRequest;
use App\Models\Adjustment;
use App\Models\Product;
use App\Models\Warehouse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;

class AdjustmentController extends Controller
{
public function index()
{
Gate::authorize('viewAny', Adjustment::class);

return Adjustment::latest()->with(['warehouse', 'products'])->paginate(20);
}

public function show(Adjustment $adjustment)
{
Gate::authorize('view', $adjustment);

return $adjustment->load(['warehouse', 'products']);
}

public function store(StoreAdjustmentRequest $request)
{
Gate::authorize('create', Adjustment::class);

DB::transaction(function () use ($request) {

$warehouseId = $request->input('warehouse_id');
$adjustments = $request->input('adjustment_items');

// update product_warehouse
foreach ($adjustments as $adjustment) {
Product::find($adjustment['product_id'])
->warehouses()
->updateExistingPivot($warehouseId, [
'quantity' => Product::find($adjustment['product_id'])
->warehouses()
->where('warehouse_id', $warehouseId)
->first()
->pivot
->quantity + ($adjustment['type'] == 'addition' ? $adjustment['quantity'] : (-1) * $adjustment['quantity']),
]);
}

$items = [];
foreach ($adjustments as $adjustment) {
$items[$adjustment['product_id']] = [
'quantity' => $adjustment['quantity'],
'type' => $adjustment['type'],
];
}

// create adjustment
$adjustment = Adjustment::create([
'warehouse_id' => $warehouseId,
'reason' => $request->input('reason'),
'adjustment_date' => $request->input('adjustment_date'),
]);

// create adjustment_product
$adjustment->products()->attach($items);
});

return response()->json(['message' => 'Adjustment created successfully'], 201);
}

public function update(StoreAdjustmentRequest $request, Adjustment $adjustment)
{
Gate::authorize('update', $adjustment);

DB::transaction(function () use ($adjustment, $request) {

$warehouseId = $request->input('warehouse_id');
$adjustments = $request->input('adjustment_items');
$reason = $request->input('reason');
$adjustment_date = $request->input('adjustment_date');

$adjustmentProductItems = [];
foreach ($adjustments as $item) {
$adjustmentProductItems[$item['product_id']] = [
'quantity' => $item['quantity'],
'type' => $item['type'],
];
}

//update adjustment
$adjustment->update([
'warehouse_id' => $warehouseId,
'reason' => $reason,
'adjustment_date' => $adjustment_date,
]);

// update product_warehouse(rollback to previous state)
foreach ($adjustment->products as $item) {
Product::find($item->pivot->product_id)
->warehouses()
->updateExistingPivot($warehouseId, [
'quantity' => Product::find($item->pivot->product_id)
->warehouses()
->where('warehouse_id', $warehouseId)
->first()
->pivot
->quantity + ($item->pivot->type == 'addition' ? (-1) * $item->pivot->quantity : $item->pivot->quantity),
]);
}

// update product_warehouse
foreach ($adjustments as $item) {
Product::find($item['product_id'])
->warehouses()
->updateExistingPivot($warehouseId, [
'quantity' => Product::find($item['product_id'])
->warehouses()
->where('warehouse_id', $warehouseId)
->first()
->pivot
->quantity + ($item['type'] == 'addition' ? $item['quantity'] : (-1) * $item['quantity']),
]);
}

// update adjustment_product
$adjustment->products()->sync($adjustmentProductItems);
});

return response()->json(['message' => 'Adjustment updated successfully'], 200);
}

public function destroy(Adjustment $adjustment)
{
Gate::authorize('delete', $adjustment);

$warehouseId = $adjustment->warehouse_id;

foreach ($adjustment->products as $item) {
Product::find($item->pivot->product_id)
->warehouses()
->updateExistingPivot($warehouseId, [
'quantity' => Product::find($item->pivot->product_id)
->warehouses()
->where('warehouse_id', $warehouseId)
->first()
->pivot
->quantity + ($item->pivot->type == 'addition' ? (-1) * $item->pivot->quantity : $item->pivot->quantity),
]);
}

$adjustment->products()->detach();

$adjustment->delete();

return response()->json(['message' => 'Adjustment deleted successfully'], 204);
}
}
35 changes: 35 additions & 0 deletions app/Http/Requests/StoreAdjustmentRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;

class StoreAdjustmentRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Auth::check();
}

/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'warehouse_id' => 'required|integer|exists:warehouses,id',
'adjustment_date' => 'required|date',
'reason' => 'required',
'adjustment_items' => 'required|array',
'adjustment_items.*.product_id' => 'required|integer|exists:products,id',
'adjustment_items.*.quantity' => 'required|integer',
'adjustment_items.*.type' => 'required|string|in:addition,subtraction',
];
}
}
27 changes: 27 additions & 0 deletions app/Models/Adjustment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Adjustment extends Model
{
use HasFactory;

protected $fillable = [
'warehouse_id',
'adjustment_date',
'reason',
];

public function warehouse()
{
return $this->belongsTo(Warehouse::class);
}

public function products()
{
return $this->belongsToMany(Product::class, 'adjustment_product', 'adjustment_id', 'product_id')->withPivot(['quantity', 'type']);
}
}
5 changes: 5 additions & 0 deletions app/Models/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,9 @@ public function attributes()
{
return $this->belongsToMany(Attribute::class);
}

public function adjustments()
{
return $this->belongsToMany(Adjustment::class)->withPivot(['quantity', 'type']);
}
}
18 changes: 18 additions & 0 deletions app/Observers/AdjustmentObserver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace App\Observers;

use App\Models\Adjustment;

class AdjustmentObserver
{
public function creating(Adjustment $adjustment)
{
$adjustment->created_by = auth()->user()->id;
}

public function updating(Adjustment $adjustment)
{
$adjustment->updated_by = auth()->user()->id;
}
}
65 changes: 65 additions & 0 deletions app/Policies/AdjustmentPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace App\Policies;

use App\Models\Adjustment;
use App\Models\User;

class AdjustmentPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->can('adjustment-list');
}

/**
* Determine whether the user can view the model.
*/
public function view(User $user, Adjustment $adjustment): bool
{
return $user->can('adjustment-list');
}

/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->can('adjustment-create');
}

/**
* Determine whether the user can update the model.
*/
public function update(User $user, Adjustment $adjustment): bool
{
return $user->can('adjustment-edit');
}

/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Adjustment $adjustment): bool
{
return $user->can('adjustment-delete');
}

/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Adjustment $adjustment): bool
{
return $user->can('adjustment-restore');
}

/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Adjustment $adjustment): bool
{
return $user->can('adjustment-force-delete');
}
}
3 changes: 3 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Providers;

use App\Models\Account;
use App\Models\Adjustment;
use App\Models\Attribute;
use App\Models\AttributeValue;
use App\Models\Brand;
Expand All @@ -16,6 +17,7 @@
use App\Models\UnitType;
use App\Models\Warehouse;
use App\Observers\AccountObserver;
use App\Observers\AdjustmentObserver;
use App\Observers\AttributeObserver;
use App\Observers\AttributeValueObserver;
use App\Observers\BrandObserver;
Expand Down Expand Up @@ -58,5 +60,6 @@ public function boot(): void
AttributeValue::observe(AttributeValueObserver::class);
Product::observe(ProductObserver::class);
Warehouse::observe(WarehouseObserver::class);
Adjustment::observe(AdjustmentObserver::class);
}
}
55 changes: 55 additions & 0 deletions database/factories/AdjustmentFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Database\Factories;

use App\Models\Adjustment;
use App\Models\Product;
use App\Models\Warehouse;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Adjustment>
*/
class AdjustmentFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'warehouse_id' => Warehouse::factory(),
'adjustment_date' => fake()->date(),
'reason' => fake()->sentence(),
];
}

public function configure(): static
{
return $this->afterCreating(function (Adjustment $adjustment) {
$products = Product::factory(10)->create();

$products->each(function ($product) use ($adjustment) {
$product->warehouses()->attach($adjustment->warehouse_id, [
'quantity' => rand(1, 10),
]);
});

$warehouseProducts = Warehouse::with(['products'])->where('id', $adjustment->warehouse_id)->first()->products;

$adjustmentItems = $warehouseProducts->pluck('id')->map(function ($id) {
return [
'product_id' => $id,
'quantity' => rand(1, 10),
'type' => rand(0, 1) ? 'addition' : 'subtraction',
];
});

foreach ($adjustmentItems as $item) {
$adjustment->products()->attach($item['product_id'], $item);
}
});
}
}
Loading

0 comments on commit be5bb6a

Please sign in to comment.