partial update create mutations
This commit is contained in:
56
.env.backup.20250611_220739
Normal file
56
.env.backup.20250611_220739
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
APP_NAME="CKB Application"
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=base64:3XK9+3S0lhXOPnlBjPxik2Ru1oARb8REF5b/pfaHLKM=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost:8000
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
# Database Configuration for Docker
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=db
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=ckb_db
|
||||||
|
DB_USERNAME=laravel
|
||||||
|
DB_PASSWORD=password
|
||||||
|
DB_ROOT_PASSWORD=root
|
||||||
|
|
||||||
|
# Redis Configuration for Docker
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
# Cache Configuration
|
||||||
|
CACHE_DRIVER=redis
|
||||||
|
QUEUE_CONNECTION=redis
|
||||||
|
SESSION_DRIVER=redis
|
||||||
|
|
||||||
|
# Mail Configuration (using MailHog for development)
|
||||||
|
MAIL_MAILER=smtp
|
||||||
|
MAIL_HOST=mailhog
|
||||||
|
MAIL_PORT=1025
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDRESS=noreply@ckb.local
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
# Broadcasting
|
||||||
|
BROADCAST_DRIVER=log
|
||||||
|
|
||||||
|
# AWS (if needed)
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
|
# Pusher (if needed)
|
||||||
|
PUSHER_APP_ID=
|
||||||
|
PUSHER_APP_KEY=
|
||||||
|
PUSHER_APP_SECRET=
|
||||||
|
PUSHER_APP_CLUSTER=mt1
|
||||||
|
|
||||||
|
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||||
|
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
112
app/Console/Commands/ClearMutationsCommand.php
Normal file
112
app/Console/Commands/ClearMutationsCommand.php
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use App\Models\Mutation;
|
||||||
|
use App\Models\MutationDetail;
|
||||||
|
|
||||||
|
class ClearMutationsCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'mutations:clear {--force : Force the operation without confirmation}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Clear all mutations and mutation details, then reset auto increment IDs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
// Show warning
|
||||||
|
$this->warn('⚠️ WARNING: This will permanently delete ALL mutations and mutation details!');
|
||||||
|
$this->warn('⚠️ This action cannot be undone!');
|
||||||
|
|
||||||
|
// Check for force flag
|
||||||
|
if (!$this->option('force')) {
|
||||||
|
if (!$this->confirm('Are you sure you want to continue?')) {
|
||||||
|
$this->info('Operation cancelled.');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show current counts
|
||||||
|
$mutationCount = Mutation::count();
|
||||||
|
$detailCount = MutationDetail::count();
|
||||||
|
$trashedMutationCount = Mutation::onlyTrashed()->count();
|
||||||
|
|
||||||
|
$this->info("Current data:");
|
||||||
|
$this->info("- Mutations: {$mutationCount}");
|
||||||
|
$this->info("- Mutation Details: {$detailCount}");
|
||||||
|
if ($trashedMutationCount > 0) {
|
||||||
|
$this->info("- Soft Deleted Mutations: {$trashedMutationCount}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mutationCount === 0 && $detailCount === 0 && $trashedMutationCount === 0) {
|
||||||
|
$this->info('No data to clear.');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Starting cleanup process...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Delete data within transaction
|
||||||
|
DB::beginTransaction();
|
||||||
|
|
||||||
|
// Delete mutation details first (foreign key constraint)
|
||||||
|
$this->info('🗑️ Deleting mutation details...');
|
||||||
|
MutationDetail::query()->delete();
|
||||||
|
|
||||||
|
// Delete mutations (including soft deleted ones)
|
||||||
|
$this->info('🗑️ Deleting mutations...');
|
||||||
|
Mutation::query()->delete();
|
||||||
|
|
||||||
|
// Force delete soft deleted mutations
|
||||||
|
$this->info('🗑️ Force deleting soft deleted mutations...');
|
||||||
|
Mutation::onlyTrashed()->forceDelete();
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
|
||||||
|
// Reset auto increment outside transaction (DDL operations auto-commit)
|
||||||
|
$this->info('🔄 Resetting mutation_details auto increment...');
|
||||||
|
DB::statement('ALTER TABLE mutation_details AUTO_INCREMENT = 1');
|
||||||
|
|
||||||
|
$this->info('🔄 Resetting mutations auto increment...');
|
||||||
|
DB::statement('ALTER TABLE mutations AUTO_INCREMENT = 1');
|
||||||
|
|
||||||
|
$this->info('✅ Successfully cleared all mutations and reset auto increment!');
|
||||||
|
$this->info('📊 Final counts:');
|
||||||
|
$this->info('- Mutations: ' . Mutation::count());
|
||||||
|
$this->info('- Mutation Details: ' . MutationDetail::count());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if (DB::transactionLevel() > 0) {
|
||||||
|
DB::rollback();
|
||||||
|
}
|
||||||
|
$this->error('❌ Failed to clear mutations: ' . $e->getMessage());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
app/Enums/MutationStatus.php
Normal file
40
app/Enums/MutationStatus.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum MutationStatus: string
|
||||||
|
{
|
||||||
|
case PENDING = 'pending';
|
||||||
|
case SENT = 'sent';
|
||||||
|
case RECEIVED = 'received';
|
||||||
|
case APPROVED = 'approved';
|
||||||
|
case REJECTED = 'rejected';
|
||||||
|
case COMPLETED = 'completed';
|
||||||
|
case CANCELLED = 'cancelled';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::PENDING => 'Menunggu Konfirmasi',
|
||||||
|
self::SENT => 'Terkirim ke Dealer',
|
||||||
|
self::RECEIVED => 'Diterima Dealer',
|
||||||
|
self::APPROVED => 'Disetujui',
|
||||||
|
self::REJECTED => 'Ditolak',
|
||||||
|
self::COMPLETED => 'Selesai',
|
||||||
|
self::CANCELLED => 'Dibatalkan',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function color(): string
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::PENDING => 'warning',
|
||||||
|
self::SENT => 'primary',
|
||||||
|
self::RECEIVED => 'info',
|
||||||
|
self::APPROVED => 'brand',
|
||||||
|
self::REJECTED => 'danger',
|
||||||
|
self::COMPLETED => 'success',
|
||||||
|
self::CANCELLED => 'secondary',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
278
app/Http/Controllers/WarehouseManagement/MutationsController.php
Normal file
278
app/Http/Controllers/WarehouseManagement/MutationsController.php
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\WarehouseManagement;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Mutation;
|
||||||
|
use App\Models\MutationDetail;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\Dealer;
|
||||||
|
use App\Enums\MutationStatus;
|
||||||
|
use App\Models\Menu;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Yajra\DataTables\DataTables;
|
||||||
|
|
||||||
|
class MutationsController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$menu = Menu::where('link','mutations.index')->first();
|
||||||
|
|
||||||
|
if ($request->ajax()) {
|
||||||
|
$data = Mutation::with(['fromDealer', 'toDealer', 'requestedBy', 'approvedBy', 'receivedBy'])
|
||||||
|
->select('mutations.*');
|
||||||
|
|
||||||
|
// Filter berdasarkan dealer jika user bukan admin
|
||||||
|
if (auth()->user()->dealer_id) {
|
||||||
|
$data->where(function($query) {
|
||||||
|
$query->where('from_dealer_id', auth()->user()->dealer_id)
|
||||||
|
->orWhere('to_dealer_id', auth()->user()->dealer_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return DataTables::of($data)
|
||||||
|
->addIndexColumn()
|
||||||
|
->addColumn('mutation_number', function($row) {
|
||||||
|
return $row->mutation_number;
|
||||||
|
})
|
||||||
|
->addColumn('from_dealer', function($row) {
|
||||||
|
return $row->fromDealer->name ?? '-';
|
||||||
|
})
|
||||||
|
->addColumn('to_dealer', function($row) {
|
||||||
|
return $row->toDealer->name ?? '-';
|
||||||
|
})
|
||||||
|
->addColumn('requested_by', function($row) {
|
||||||
|
return $row->requestedBy->name ?? '-';
|
||||||
|
})
|
||||||
|
->addColumn('status', function($row) {
|
||||||
|
$statusColor = $row->status_color;
|
||||||
|
$statusLabel = $row->status_label;
|
||||||
|
return "<span class=\"kt-badge kt-badge--{$statusColor} kt-badge--dot\"></span> <span class=\"kt-font-bold kt-font-{$statusColor}\">{$statusLabel}</span>";
|
||||||
|
})
|
||||||
|
->addColumn('total_items', function($row) {
|
||||||
|
return number_format($row->total_items, 0);
|
||||||
|
})
|
||||||
|
->addColumn('created_at', function($row) {
|
||||||
|
return $row->created_at->format('d/m/Y H:i');
|
||||||
|
})
|
||||||
|
->addColumn('action', function($row) {
|
||||||
|
return view('warehouse_management.mutations._action', compact('row'))->render();
|
||||||
|
})
|
||||||
|
->rawColumns(['status', 'action'])
|
||||||
|
->make(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('warehouse_management.mutations.index', compact('menu'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$menu = Menu::where('link','mutations.create')->first();
|
||||||
|
$dealers = Dealer::all();
|
||||||
|
$products = Product::with('stocks')->get();
|
||||||
|
|
||||||
|
return view('warehouse_management.mutations.create', compact('menu', 'dealers', 'products'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'from_dealer_id' => 'required|exists:dealers,id',
|
||||||
|
'to_dealer_id' => 'required|exists:dealers,id|different:from_dealer_id',
|
||||||
|
'notes' => 'nullable|string',
|
||||||
|
'products' => 'required|array|min:1',
|
||||||
|
'products.*.product_id' => 'required|exists:products,id',
|
||||||
|
'products.*.quantity_requested' => 'required|numeric|min:0.01'
|
||||||
|
]);
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
try {
|
||||||
|
// Buat mutation record dengan status SENT (langsung terkirim ke dealer tujuan)
|
||||||
|
$mutation = Mutation::create([
|
||||||
|
'from_dealer_id' => $request->from_dealer_id,
|
||||||
|
'to_dealer_id' => $request->to_dealer_id,
|
||||||
|
'status' => 'sent',
|
||||||
|
'requested_by' => auth()->id(),
|
||||||
|
'notes' => $request->notes
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Buat mutation details
|
||||||
|
foreach ($request->products as $productData) {
|
||||||
|
MutationDetail::create([
|
||||||
|
'mutation_id' => $mutation->id,
|
||||||
|
'product_id' => $productData['product_id'],
|
||||||
|
'quantity_requested' => $productData['quantity_requested'],
|
||||||
|
'notes' => $productData['notes'] ?? null
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
return redirect()->route('mutations.index')
|
||||||
|
->with('success', 'Mutasi berhasil dibuat dan terkirim ke dealer tujuan');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollback();
|
||||||
|
return back()->withErrors(['error' => 'Gagal membuat mutasi: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Mutation $mutation)
|
||||||
|
{
|
||||||
|
$mutation->load(['fromDealer', 'toDealer', 'requestedBy', 'approvedBy', 'receivedBy', 'mutationDetails.product']);
|
||||||
|
|
||||||
|
return view('warehouse_management.mutations.show', compact('mutation'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function receive(Mutation $mutation)
|
||||||
|
{
|
||||||
|
if (!$mutation->canBeReceived()) {
|
||||||
|
return back()->withErrors(['error' => 'Mutasi tidak dapat diterima dalam status saat ini']);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mutation->receive(auth()->id());
|
||||||
|
|
||||||
|
return redirect()->route('mutations.index')
|
||||||
|
->with('success', 'Mutasi berhasil diterima dan menunggu persetujuan pengirim');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return back()->withErrors(['error' => 'Gagal menerima mutasi: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function approve(Request $request, Mutation $mutation)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'notes' => 'nullable|string',
|
||||||
|
'details' => 'required|array',
|
||||||
|
'details.*.quantity_approved' => 'required|numeric|min:0'
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!$mutation->canBeApproved()) {
|
||||||
|
return back()->withErrors(['error' => 'Mutasi tidak dapat disetujui dalam status saat ini']);
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
try {
|
||||||
|
// Update mutation details dengan quantity approved
|
||||||
|
foreach ($request->details as $detailId => $detailData) {
|
||||||
|
$mutationDetail = MutationDetail::findOrFail($detailId);
|
||||||
|
$mutationDetail->update([
|
||||||
|
'quantity_approved' => $detailData['quantity_approved']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Approve mutation
|
||||||
|
$mutation->approve(auth()->id(), $request->notes);
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
return redirect()->route('mutations.index')
|
||||||
|
->with('success', 'Mutasi berhasil disetujui');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollback();
|
||||||
|
return back()->withErrors(['error' => 'Gagal menyetujui mutasi: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reject(Request $request, Mutation $mutation)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'rejection_reason' => 'required|string'
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!$mutation->canBeApproved()) {
|
||||||
|
return back()->withErrors(['error' => 'Mutasi tidak dapat ditolak dalam status saat ini']);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mutation->reject(auth()->id(), $request->rejection_reason);
|
||||||
|
|
||||||
|
return redirect()->route('mutations.index')
|
||||||
|
->with('success', 'Mutasi berhasil ditolak');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return back()->withErrors(['error' => 'Gagal menolak mutasi: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function complete(Mutation $mutation)
|
||||||
|
{
|
||||||
|
if (!$mutation->canBeCompleted()) {
|
||||||
|
return back()->withErrors(['error' => 'Mutasi tidak dapat diselesaikan dalam status saat ini']);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mutation->complete();
|
||||||
|
|
||||||
|
return redirect()->route('mutations.index')
|
||||||
|
->with('success', 'Mutasi berhasil diselesaikan dan stock telah dipindahkan');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return back()->withErrors(['error' => 'Gagal menyelesaikan mutasi: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancel(Mutation $mutation)
|
||||||
|
{
|
||||||
|
if (!$mutation->canBeCancelled()) {
|
||||||
|
return back()->withErrors(['error' => 'Mutasi tidak dapat dibatalkan dalam status saat ini']);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mutation->update(['status' => MutationStatus::CANCELLED]);
|
||||||
|
|
||||||
|
return redirect()->route('mutations.index')
|
||||||
|
->with('success', 'Mutasi berhasil dibatalkan');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return back()->withErrors(['error' => 'Gagal membatalkan mutasi: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API untuk mendapatkan detail mutasi untuk approval
|
||||||
|
public function getDetails(Mutation $mutation)
|
||||||
|
{
|
||||||
|
$mutation->load(['mutationDetails.product', 'fromDealer']);
|
||||||
|
|
||||||
|
$details = $mutation->mutationDetails->map(function($detail) use ($mutation) {
|
||||||
|
$availableStock = $detail->product->getStockByDealer($mutation->from_dealer_id);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => $detail->id,
|
||||||
|
'product' => [
|
||||||
|
'id' => $detail->product->id,
|
||||||
|
'name' => $detail->product->name
|
||||||
|
],
|
||||||
|
'quantity_requested' => $detail->quantity_requested,
|
||||||
|
'quantity_approved' => $detail->quantity_approved,
|
||||||
|
'available_stock' => $availableStock
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'mutation' => [
|
||||||
|
'id' => $mutation->id,
|
||||||
|
'mutation_number' => $mutation->mutation_number,
|
||||||
|
'from_dealer' => $mutation->fromDealer->name,
|
||||||
|
'to_dealer' => $mutation->toDealer->name
|
||||||
|
],
|
||||||
|
'details' => $details
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// API untuk mendapatkan stock produk di dealer tertentu
|
||||||
|
public function getProductStock(Request $request)
|
||||||
|
{
|
||||||
|
$dealerId = $request->dealer_id;
|
||||||
|
$productId = $request->product_id;
|
||||||
|
|
||||||
|
$product = Product::findOrFail($productId);
|
||||||
|
$stock = $product->getStockByDealer($dealerId);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'product_name' => $product->name,
|
||||||
|
'current_stock' => $stock
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,13 +41,11 @@ class ProductsController extends Controller
|
|||||||
|
|
||||||
if (Gate::allows('update', $menu)) {
|
if (Gate::allows('update', $menu)) {
|
||||||
$btn .= '<a href="' . route('products.edit', $row->id) . '" class="btn btn-warning btn-sm" style="margin-right: 8px;">Edit</a>';
|
$btn .= '<a href="' . route('products.edit', $row->id) . '" class="btn btn-warning btn-sm" style="margin-right: 8px;">Edit</a>';
|
||||||
|
$btn .= '<button class="btn btn-sm btn-toggle-active '
|
||||||
|
. ($row->active ? 'btn-danger' : 'btn-success') . '"
|
||||||
|
data-url="' . route('products.toggleActive', $row->id) . '" data-active="'.$row->active.'" style="margin-right: 8px;">'
|
||||||
|
. ($row->active ? 'Nonaktifkan' : 'Aktifkan') . '</button>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$btn .= '<button class="btn btn-sm btn-toggle-active '
|
|
||||||
. ($row->active ? 'btn-danger' : 'btn-success') . '"
|
|
||||||
data-url="' . route('products.toggleActive', $row->id) . '" data-active="'.$row->active.'" style="margin-right: 8px;">'
|
|
||||||
. ($row->active ? 'Nonaktifkan' : 'Aktifkan') . '</button>';
|
|
||||||
|
|
||||||
$btn .= '<button class="btn btn-sm btn-secondary btn-product-stock-dealers"
|
$btn .= '<button class="btn btn-sm btn-secondary btn-product-stock-dealers"
|
||||||
data-id="'.$row->id.'"
|
data-id="'.$row->id.'"
|
||||||
data-url="'.route('products.dealers_stock').'"
|
data-url="'.route('products.dealers_stock').'"
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\WarehouseManagement;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\Dealer;
|
|
||||||
use App\Models\Product;
|
|
||||||
use App\Models\Stock;
|
|
||||||
use App\Models\StockLog;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class StocksController extends Controller
|
|
||||||
{
|
|
||||||
public function index(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->ajax()) {
|
|
||||||
$query = Stock::with(['dealer', 'product'])
|
|
||||||
->when($request->dealer_id, function($q) use ($request) {
|
|
||||||
return $q->where('dealer_id', $request->dealer_id);
|
|
||||||
})
|
|
||||||
->when($request->product_id, function($q) use ($request) {
|
|
||||||
return $q->where('product_id', $request->product_id);
|
|
||||||
});
|
|
||||||
|
|
||||||
return datatables()->of($query)
|
|
||||||
->addColumn('dealer_name', function($stock) {
|
|
||||||
return $stock->dealer->name;
|
|
||||||
})
|
|
||||||
->addColumn('product_name', function($stock) {
|
|
||||||
return $stock->product->name;
|
|
||||||
})
|
|
||||||
->addColumn('action', function($stock) {
|
|
||||||
return view('warehouse_management.stocks._action', compact('stock'));
|
|
||||||
})
|
|
||||||
->toJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
$dealers = Dealer::all();
|
|
||||||
$products = Product::where('active', true)->get();
|
|
||||||
|
|
||||||
return view('warehouse_management.stocks.index', compact('dealers', 'products'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function adjust(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'stock_id' => 'required|exists:stocks,id',
|
|
||||||
'type' => 'required|in:add,reduce',
|
|
||||||
'quantity' => 'required|numeric|min:0.01',
|
|
||||||
'note' => 'required|string|max:255'
|
|
||||||
]);
|
|
||||||
|
|
||||||
try {
|
|
||||||
DB::beginTransaction();
|
|
||||||
|
|
||||||
$stock = Stock::findOrFail($request->stock_id);
|
|
||||||
$oldQuantity = $stock->quantity;
|
|
||||||
|
|
||||||
// Calculate new quantity
|
|
||||||
$change = $request->type === 'add' ? $request->quantity : -$request->quantity;
|
|
||||||
$newQuantity = $oldQuantity + $change;
|
|
||||||
|
|
||||||
// Update stock
|
|
||||||
$stock->update(['quantity' => $newQuantity]);
|
|
||||||
|
|
||||||
// Log the change
|
|
||||||
StockLog::create([
|
|
||||||
'stock_id' => $stock->id,
|
|
||||||
'user_id' => Auth::id(),
|
|
||||||
'old_quantity' => $oldQuantity,
|
|
||||||
'new_quantity' => $newQuantity,
|
|
||||||
'change' => $change,
|
|
||||||
'note' => $request->note,
|
|
||||||
'reference_type' => 'manual_adjustment'
|
|
||||||
]);
|
|
||||||
|
|
||||||
DB::commit();
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'success' => true,
|
|
||||||
'message' => 'Stok berhasil diadjust'
|
|
||||||
]);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
DB::rollBack();
|
|
||||||
return response()->json([
|
|
||||||
'success' => false,
|
|
||||||
'message' => 'Gagal mengadjust stok: ' . $e->getMessage()
|
|
||||||
], 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function history(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'stock_id' => 'required|exists:stocks,id'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$logs = StockLog::with('user')
|
|
||||||
->where('stock_id', $request->stock_id)
|
|
||||||
->orderBy('created_at', 'desc')
|
|
||||||
->get()
|
|
||||||
->map(function($log) {
|
|
||||||
return [
|
|
||||||
'date' => $log->created_at->format('d/m/Y H:i'),
|
|
||||||
'user' => $log->user->name,
|
|
||||||
'change' => $log->change > 0 ? '+' . $log->change : $log->change,
|
|
||||||
'old_quantity' => $log->old_quantity,
|
|
||||||
'new_quantity' => $log->new_quantity,
|
|
||||||
'note' => $log->note
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
return response()->json(['logs' => $logs]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,4 +26,19 @@ class Dealer extends Model
|
|||||||
public function opnames(){
|
public function opnames(){
|
||||||
return $this->hasMany(Opname::class);
|
return $this->hasMany(Opname::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function outgoingMutations()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Mutation::class, 'from_dealer_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function incomingMutations()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Mutation::class, 'to_dealer_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stocks()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Stock::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
262
app/Models/Mutation.php
Normal file
262
app/Models/Mutation.php
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\MutationStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class Mutation extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'mutation_number',
|
||||||
|
'from_dealer_id',
|
||||||
|
'to_dealer_id',
|
||||||
|
'status',
|
||||||
|
'requested_by',
|
||||||
|
'approved_by',
|
||||||
|
'approved_at',
|
||||||
|
'received_by',
|
||||||
|
'received_at',
|
||||||
|
'notes',
|
||||||
|
'rejection_reason'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'status' => MutationStatus::class,
|
||||||
|
'approved_at' => 'datetime',
|
||||||
|
'received_at' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected static function booted()
|
||||||
|
{
|
||||||
|
static::creating(function ($mutation) {
|
||||||
|
if (empty($mutation->mutation_number)) {
|
||||||
|
$mutation->mutation_number = $mutation->generateMutationNumber();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fromDealer()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dealer::class, 'from_dealer_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDealer()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dealer::class, 'to_dealer_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requestedBy()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'requested_by');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function approvedBy()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'approved_by');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function receivedBy()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'received_by');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mutationDetails()
|
||||||
|
{
|
||||||
|
return $this->hasMany(MutationDetail::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stockLogs()
|
||||||
|
{
|
||||||
|
return $this->morphMany(StockLog::class, 'source');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper methods
|
||||||
|
public function getStatusLabelAttribute()
|
||||||
|
{
|
||||||
|
return $this->status->label();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusColorAttribute()
|
||||||
|
{
|
||||||
|
return $this->status->color();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTotalItemsAttribute()
|
||||||
|
{
|
||||||
|
return $this->mutationDetails()->sum('quantity_requested');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTotalApprovedItemsAttribute()
|
||||||
|
{
|
||||||
|
return $this->mutationDetails()->sum('quantity_approved');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canBeSent()
|
||||||
|
{
|
||||||
|
return $this->status === MutationStatus::PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canBeReceived()
|
||||||
|
{
|
||||||
|
return $this->status === MutationStatus::SENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canBeApproved()
|
||||||
|
{
|
||||||
|
return $this->status === MutationStatus::RECEIVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canBeCompleted()
|
||||||
|
{
|
||||||
|
return $this->status === MutationStatus::APPROVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canBeCancelled()
|
||||||
|
{
|
||||||
|
return in_array($this->status, [MutationStatus::PENDING, MutationStatus::SENT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send mutation to destination dealer
|
||||||
|
public function send($userId)
|
||||||
|
{
|
||||||
|
if (!$this->canBeSent()) {
|
||||||
|
throw new \Exception('Mutasi tidak dapat dikirim dalam status saat ini');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->update([
|
||||||
|
'status' => MutationStatus::SENT
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive mutation by destination dealer
|
||||||
|
public function receive($userId)
|
||||||
|
{
|
||||||
|
if (!$this->canBeReceived()) {
|
||||||
|
throw new \Exception('Mutasi tidak dapat diterima dalam status saat ini');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->update([
|
||||||
|
'status' => MutationStatus::RECEIVED,
|
||||||
|
'received_by' => $userId,
|
||||||
|
'received_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Approve mutation
|
||||||
|
public function approve($userId, $notes = null)
|
||||||
|
{
|
||||||
|
if (!$this->canBeApproved()) {
|
||||||
|
throw new \Exception('Mutasi tidak dapat disetujui dalam status saat ini');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->update([
|
||||||
|
'status' => MutationStatus::APPROVED,
|
||||||
|
'approved_by' => $userId,
|
||||||
|
'approved_at' => now(),
|
||||||
|
'notes' => $notes
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject mutation
|
||||||
|
public function reject($userId, $rejectionReason)
|
||||||
|
{
|
||||||
|
if (!$this->canBeApproved()) {
|
||||||
|
throw new \Exception('Mutasi tidak dapat ditolak dalam status saat ini');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->update([
|
||||||
|
'status' => MutationStatus::REJECTED,
|
||||||
|
'approved_by' => $userId,
|
||||||
|
'approved_at' => now(),
|
||||||
|
'rejection_reason' => $rejectionReason
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete mutation (actually move the stock)
|
||||||
|
public function complete()
|
||||||
|
{
|
||||||
|
if (!$this->canBeCompleted()) {
|
||||||
|
throw new \Exception('Mutasi tidak dapat diselesaikan dalam status saat ini');
|
||||||
|
}
|
||||||
|
|
||||||
|
\DB::beginTransaction();
|
||||||
|
try {
|
||||||
|
foreach ($this->mutationDetails as $detail) {
|
||||||
|
if ($detail->quantity_approved > 0) {
|
||||||
|
$this->processStockMovement($detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->update(['status' => MutationStatus::COMPLETED]);
|
||||||
|
\DB::commit();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\DB::rollback();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processStockMovement(MutationDetail $detail)
|
||||||
|
{
|
||||||
|
// Kurangi stock dari dealer asal
|
||||||
|
$fromStock = Stock::firstOrCreate([
|
||||||
|
'product_id' => $detail->product_id,
|
||||||
|
'dealer_id' => $this->from_dealer_id
|
||||||
|
], ['quantity' => 0]);
|
||||||
|
|
||||||
|
if ($fromStock->quantity < $detail->quantity_approved) {
|
||||||
|
throw new \Exception("Stock tidak mencukupi untuk produk {$detail->product->name} di {$this->fromDealer->name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$fromStock->updateStock(
|
||||||
|
$fromStock->quantity - $detail->quantity_approved,
|
||||||
|
$this,
|
||||||
|
"Mutasi keluar ke {$this->toDealer->name} - {$this->mutation_number}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tambah stock ke dealer tujuan
|
||||||
|
$toStock = Stock::firstOrCreate([
|
||||||
|
'product_id' => $detail->product_id,
|
||||||
|
'dealer_id' => $this->to_dealer_id
|
||||||
|
], ['quantity' => 0]);
|
||||||
|
|
||||||
|
$toStock->updateStock(
|
||||||
|
$toStock->quantity + $detail->quantity_approved,
|
||||||
|
$this,
|
||||||
|
"Mutasi masuk dari {$this->fromDealer->name} - {$this->mutation_number}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateMutationNumber()
|
||||||
|
{
|
||||||
|
$prefix = 'MUT';
|
||||||
|
$date = now()->format('Ymd');
|
||||||
|
$lastNumber = static::whereDate('created_at', today())
|
||||||
|
->whereNotNull('mutation_number')
|
||||||
|
->latest('id')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($lastNumber) {
|
||||||
|
$lastSequence = (int) substr($lastNumber->mutation_number, -4);
|
||||||
|
$sequence = str_pad($lastSequence + 1, 4, '0', STR_PAD_LEFT);
|
||||||
|
} else {
|
||||||
|
$sequence = '0001';
|
||||||
|
}
|
||||||
|
|
||||||
|
return "{$prefix}{$date}{$sequence}";
|
||||||
|
}
|
||||||
|
}
|
||||||
98
app/Models/MutationDetail.php
Normal file
98
app/Models/MutationDetail.php
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class MutationDetail extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'mutation_id',
|
||||||
|
'product_id',
|
||||||
|
'quantity_requested',
|
||||||
|
'quantity_approved',
|
||||||
|
'notes'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'quantity_requested' => 'decimal:2',
|
||||||
|
'quantity_approved' => 'decimal:2'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function mutation()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Mutation::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function product()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Product::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper methods
|
||||||
|
public function getQuantityDifferenceAttribute()
|
||||||
|
{
|
||||||
|
return $this->quantity_approved - $this->quantity_requested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isFullyApproved()
|
||||||
|
{
|
||||||
|
return $this->quantity_approved == $this->quantity_requested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isPartiallyApproved()
|
||||||
|
{
|
||||||
|
return $this->quantity_approved > 0 && $this->quantity_approved < $this->quantity_requested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isRejected()
|
||||||
|
{
|
||||||
|
return $this->quantity_approved == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApprovalStatusAttribute()
|
||||||
|
{
|
||||||
|
if ($this->isFullyApproved()) {
|
||||||
|
return 'Disetujui Penuh';
|
||||||
|
} elseif ($this->isPartiallyApproved()) {
|
||||||
|
return 'Disetujui Sebagian';
|
||||||
|
} elseif ($this->isRejected()) {
|
||||||
|
return 'Ditolak';
|
||||||
|
} else {
|
||||||
|
return 'Menunggu';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApprovalStatusColorAttribute()
|
||||||
|
{
|
||||||
|
if ($this->isFullyApproved()) {
|
||||||
|
return 'success';
|
||||||
|
} elseif ($this->isPartiallyApproved()) {
|
||||||
|
return 'warning';
|
||||||
|
} elseif ($this->isRejected()) {
|
||||||
|
return 'danger';
|
||||||
|
} else {
|
||||||
|
return 'info';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scope untuk filter berdasarkan status approval
|
||||||
|
public function scopeFullyApproved($query)
|
||||||
|
{
|
||||||
|
return $query->whereColumn('quantity_approved', '=', 'quantity_requested');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopePartiallyApproved($query)
|
||||||
|
{
|
||||||
|
return $query->where('quantity_approved', '>', 0)
|
||||||
|
->whereColumn('quantity_approved', '<', 'quantity_requested');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeRejected($query)
|
||||||
|
{
|
||||||
|
return $query->where('quantity_approved', '=', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,9 +24,20 @@ class Product extends Model
|
|||||||
return $this->hasMany(Stock::class);
|
return $this->hasMany(Stock::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function mutationDetails()
|
||||||
|
{
|
||||||
|
return $this->hasMany(MutationDetail::class);
|
||||||
|
}
|
||||||
|
|
||||||
// Helper method untuk mendapatkan total stock saat ini
|
// Helper method untuk mendapatkan total stock saat ini
|
||||||
public function getCurrentTotalStockAttribute()
|
public function getCurrentTotalStockAttribute()
|
||||||
{
|
{
|
||||||
return $this->stocks()->sum('quantity');
|
return $this->stocks()->sum('quantity');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper method untuk mendapatkan stock di dealer tertentu
|
||||||
|
public function getStockByDealer($dealerId)
|
||||||
|
{
|
||||||
|
return $this->stocks()->where('dealer_id', $dealerId)->first()?->quantity ?? 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
343
ckb.sql
343
ckb.sql
@@ -1,13 +1,14 @@
|
|||||||
-- MySQL dump 10.13 Distrib 8.0.42, for Linux (x86_64)
|
/*M!999999\- enable the sandbox mode */
|
||||||
|
-- MariaDB dump 10.19 Distrib 10.6.22-MariaDB, for debian-linux-gnu (x86_64)
|
||||||
--
|
--
|
||||||
-- Host: localhost Database: ckb
|
-- Host: localhost Database: ckb_db
|
||||||
-- ------------------------------------------------------
|
-- ------------------------------------------------------
|
||||||
-- Server version 8.0.42-0ubuntu0.22.04.1
|
-- Server version 10.6.22-MariaDB-ubu2004-log
|
||||||
|
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
/*!50503 SET NAMES utf8mb4 */;
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||||
@@ -21,13 +22,13 @@
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `categories`;
|
DROP TABLE IF EXISTS `categories`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `categories` (
|
CREATE TABLE `categories` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
`form` enum('work','wash') COLLATE utf8mb4_unicode_ci NOT NULL,
|
`form` enum('work','wash') NOT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
@@ -49,15 +50,15 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `dealers`;
|
DROP TABLE IF EXISTS `dealers`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `dealers` (
|
CREATE TABLE `dealers` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`dealer_code` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`dealer_code` varchar(255) NOT NULL,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`address` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
`address` text NOT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
`pic` bigint unsigned DEFAULT NULL,
|
`pic` bigint(20) unsigned DEFAULT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `dealers_dealer_code_unique` (`dealer_code`),
|
UNIQUE KEY `dealers_dealer_code_unique` (`dealer_code`),
|
||||||
@@ -82,15 +83,15 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `failed_jobs`;
|
DROP TABLE IF EXISTS `failed_jobs`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `failed_jobs` (
|
CREATE TABLE `failed_jobs` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`uuid` varchar(255) NOT NULL,
|
||||||
`connection` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
`connection` text NOT NULL,
|
||||||
`queue` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
`queue` text NOT NULL,
|
||||||
`payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
`payload` longtext NOT NULL,
|
||||||
`exception` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
`exception` longtext NOT NULL,
|
||||||
`failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`failed_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`)
|
UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
@@ -111,11 +112,11 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `menus`;
|
DROP TABLE IF EXISTS `menus`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `menus` (
|
CREATE TABLE `menus` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`link` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`link` varchar(255) NOT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
@@ -138,13 +139,13 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `migrations`;
|
DROP TABLE IF EXISTS `migrations`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `migrations` (
|
CREATE TABLE `migrations` (
|
||||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`migration` varchar(255) NOT NULL,
|
||||||
`batch` int NOT NULL,
|
`batch` int(11) NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=78 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -153,25 +154,107 @@ CREATE TABLE `migrations` (
|
|||||||
|
|
||||||
LOCK TABLES `migrations` WRITE;
|
LOCK TABLES `migrations` WRITE;
|
||||||
/*!40000 ALTER TABLE `migrations` DISABLE KEYS */;
|
/*!40000 ALTER TABLE `migrations` DISABLE KEYS */;
|
||||||
INSERT INTO `migrations` VALUES (1,'2014_10_12_100000_create_password_resets_table',1),(2,'2019_08_19_000000_create_failed_jobs_table',1),(3,'2019_12_14_000001_create_personal_access_tokens_table',1),(4,'2022_05_20_100209_create_dealers_table',1),(5,'2022_05_20_100326_create_categories_table',1),(6,'2022_05_20_100335_create_works_table',1),(7,'2022_05_20_100340_create_users_table',1),(8,'2022_05_20_100410_create_transactions_table',1),(9,'2022_05_25_024641_update_works_table',2),(10,'2022_05_25_103839_update_categories_table',3),(13,'2022_05_25_144502_update_transaction_table',4),(18,'2022_05_29_211410_update_table_works_add_shortname_field',5),(20,'2022_05_29_211531_update_dealers_table_add_pic_field',6),(21,'2022_05_29_220642_update_transactions_table_add_status_column',7),(22,'2022_05_31_003725_update_transaction_table_add_dealer_id',8),(23,'2022_06_23_215115_add_deleted_at_at_users_table',9),(24,'2022_06_23_215243_add_deleted_at_at_dealers_table',9),(25,'2022_06_23_215321_add_deleted_at_at_categories_table',9),(26,'2022_06_23_215341_add_deleted_at_at_works_table',9),(27,'2022_06_23_215404_add_deleted_at_at_transactions_table',9),(28,'2023_08_11_140743_create_roles_table',10),(29,'2023_08_11_140957_create_privileges_table',10),(30,'2023_08_11_141029_add_role_id_into_users_table',10),(31,'2023_08_11_144823_create_menus_table',10),(32,'2023_08_11_144857_add_menu_id_in_privileges_table',10),(33,'2023_08_11_145537_remove_name_in_privileges_table',10),(55,'2025_05_28_113228_create_product_categories_table',11),(56,'2025_05_28_113324_create_products_table',11),(59,'2025_06_04_101915_create_opnames_table',12),(60,'2025_06_04_103359_create_opname_details_table',12),(66,'2025_06_10_135321_create_stocks_table',13),(67,'2025_06_10_135341_create_stock_logs_table',14),(68,'2025_06_10_135417_add_approval_columns_to_opnames_table',14),(69,'2025_06_10_140540_change_stock_columns_to_decimal_in_opname_details',14);
|
INSERT INTO `migrations` VALUES (1,'2014_10_12_100000_create_password_resets_table',1),(2,'2019_08_19_000000_create_failed_jobs_table',1),(3,'2019_12_14_000001_create_personal_access_tokens_table',1),(4,'2022_05_20_100209_create_dealers_table',1),(5,'2022_05_20_100326_create_categories_table',1),(6,'2022_05_20_100335_create_works_table',1),(7,'2022_05_20_100340_create_users_table',1),(8,'2022_05_20_100410_create_transactions_table',1),(9,'2022_05_25_024641_update_works_table',2),(10,'2022_05_25_103839_update_categories_table',3),(13,'2022_05_25_144502_update_transaction_table',4),(18,'2022_05_29_211410_update_table_works_add_shortname_field',5),(20,'2022_05_29_211531_update_dealers_table_add_pic_field',6),(21,'2022_05_29_220642_update_transactions_table_add_status_column',7),(22,'2022_05_31_003725_update_transaction_table_add_dealer_id',8),(23,'2022_06_23_215115_add_deleted_at_at_users_table',9),(24,'2022_06_23_215243_add_deleted_at_at_dealers_table',9),(25,'2022_06_23_215321_add_deleted_at_at_categories_table',9),(26,'2022_06_23_215341_add_deleted_at_at_works_table',9),(27,'2022_06_23_215404_add_deleted_at_at_transactions_table',9),(28,'2023_08_11_140743_create_roles_table',10),(29,'2023_08_11_140957_create_privileges_table',10),(30,'2023_08_11_141029_add_role_id_into_users_table',10),(31,'2023_08_11_144823_create_menus_table',10),(32,'2023_08_11_144857_add_menu_id_in_privileges_table',10),(33,'2023_08_11_145537_remove_name_in_privileges_table',10),(55,'2025_05_28_113228_create_product_categories_table',11),(56,'2025_05_28_113324_create_products_table',11),(59,'2025_06_04_101915_create_opnames_table',12),(60,'2025_06_04_103359_create_opname_details_table',12),(66,'2025_06_10_135321_create_stocks_table',13),(67,'2025_06_10_135341_create_stock_logs_table',14),(68,'2025_06_10_135417_add_approval_columns_to_opnames_table',14),(69,'2025_06_10_140540_change_stock_columns_to_decimal_in_opname_details',14),(76,'2025_06_12_002513_create_mutations_table',15),(77,'2025_06_12_002623_create_mutation_details_table',15);
|
||||||
/*!40000 ALTER TABLE `migrations` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `migrations` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `mutation_details`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `mutation_details`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `mutation_details` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`mutation_id` bigint(20) unsigned NOT NULL,
|
||||||
|
`product_id` bigint(20) unsigned NOT NULL,
|
||||||
|
`quantity_requested` decimal(15,2) NOT NULL,
|
||||||
|
`quantity_approved` decimal(15,2) NOT NULL DEFAULT 0.00,
|
||||||
|
`notes` text DEFAULT NULL,
|
||||||
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `mutation_details_product_id_foreign` (`product_id`),
|
||||||
|
KEY `mutation_details_mutation_id_product_id_index` (`mutation_id`,`product_id`),
|
||||||
|
CONSTRAINT `mutation_details_mutation_id_foreign` FOREIGN KEY (`mutation_id`) REFERENCES `mutations` (`id`) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `mutation_details_product_id_foreign` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `mutation_details`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `mutation_details` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `mutation_details` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `mutation_details` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `mutations`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `mutations`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `mutations` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`mutation_number` varchar(255) NOT NULL,
|
||||||
|
`from_dealer_id` bigint(20) unsigned NOT NULL,
|
||||||
|
`to_dealer_id` bigint(20) unsigned NOT NULL,
|
||||||
|
`status` enum('pending','sent','received','approved','rejected','completed','cancelled') NOT NULL DEFAULT 'sent',
|
||||||
|
`requested_by` bigint(20) unsigned NOT NULL,
|
||||||
|
`approved_by` bigint(20) unsigned DEFAULT NULL,
|
||||||
|
`approved_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`received_by` bigint(20) unsigned DEFAULT NULL,
|
||||||
|
`received_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`notes` text DEFAULT NULL,
|
||||||
|
`rejection_reason` text DEFAULT NULL,
|
||||||
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `mutations_mutation_number_unique` (`mutation_number`),
|
||||||
|
KEY `mutations_requested_by_foreign` (`requested_by`),
|
||||||
|
KEY `mutations_approved_by_foreign` (`approved_by`),
|
||||||
|
KEY `mutations_received_by_foreign` (`received_by`),
|
||||||
|
KEY `mutations_from_dealer_id_status_index` (`from_dealer_id`,`status`),
|
||||||
|
KEY `mutations_to_dealer_id_status_index` (`to_dealer_id`,`status`),
|
||||||
|
KEY `mutations_status_created_at_index` (`status`,`created_at`),
|
||||||
|
KEY `mutations_mutation_number_index` (`mutation_number`),
|
||||||
|
CONSTRAINT `mutations_approved_by_foreign` FOREIGN KEY (`approved_by`) REFERENCES `users` (`id`),
|
||||||
|
CONSTRAINT `mutations_from_dealer_id_foreign` FOREIGN KEY (`from_dealer_id`) REFERENCES `dealers` (`id`),
|
||||||
|
CONSTRAINT `mutations_received_by_foreign` FOREIGN KEY (`received_by`) REFERENCES `users` (`id`),
|
||||||
|
CONSTRAINT `mutations_requested_by_foreign` FOREIGN KEY (`requested_by`) REFERENCES `users` (`id`),
|
||||||
|
CONSTRAINT `mutations_to_dealer_id_foreign` FOREIGN KEY (`to_dealer_id`) REFERENCES `dealers` (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `mutations`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `mutations` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `mutations` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `mutations` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `opname_details`
|
-- Table structure for table `opname_details`
|
||||||
--
|
--
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `opname_details`;
|
DROP TABLE IF EXISTS `opname_details`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `opname_details` (
|
CREATE TABLE `opname_details` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`opname_id` bigint unsigned NOT NULL,
|
`opname_id` bigint(20) unsigned NOT NULL,
|
||||||
`product_id` bigint unsigned NOT NULL,
|
`product_id` bigint(20) unsigned NOT NULL,
|
||||||
`system_stock` decimal(10,2) NOT NULL,
|
`system_stock` decimal(10,2) NOT NULL,
|
||||||
`physical_stock` decimal(10,2) NOT NULL,
|
`physical_stock` decimal(10,2) NOT NULL,
|
||||||
`difference` decimal(10,2) NOT NULL DEFAULT '0.00',
|
`difference` decimal(10,2) NOT NULL DEFAULT 0.00,
|
||||||
`note` text COLLATE utf8mb4_unicode_ci,
|
`note` text DEFAULT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
@@ -180,7 +263,7 @@ CREATE TABLE `opname_details` (
|
|||||||
KEY `opname_details_product_id_foreign` (`product_id`),
|
KEY `opname_details_product_id_foreign` (`product_id`),
|
||||||
CONSTRAINT `opname_details_opname_id_foreign` FOREIGN KEY (`opname_id`) REFERENCES `opnames` (`id`) ON DELETE CASCADE,
|
CONSTRAINT `opname_details_opname_id_foreign` FOREIGN KEY (`opname_id`) REFERENCES `opnames` (`id`) ON DELETE CASCADE,
|
||||||
CONSTRAINT `opname_details_product_id_foreign` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE
|
CONSTRAINT `opname_details_product_id_foreign` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -189,7 +272,7 @@ CREATE TABLE `opname_details` (
|
|||||||
|
|
||||||
LOCK TABLES `opname_details` WRITE;
|
LOCK TABLES `opname_details` WRITE;
|
||||||
/*!40000 ALTER TABLE `opname_details` DISABLE KEYS */;
|
/*!40000 ALTER TABLE `opname_details` DISABLE KEYS */;
|
||||||
INSERT INTO `opname_details` VALUES (1,1,1,0.00,10.00,10.00,'tambah produk baru',NULL,'2025-06-10 10:26:24','2025-06-10 10:26:24'),(2,2,1,0.00,30.00,30.00,'tambah baru',NULL,'2025-06-10 10:27:30','2025-06-10 10:27:30');
|
INSERT INTO `opname_details` VALUES (1,1,1,0.00,10.00,10.00,'tambah produk baru',NULL,'2025-06-10 10:26:24','2025-06-10 10:26:24'),(2,2,1,0.00,30.00,30.00,'tambah baru',NULL,'2025-06-10 10:27:30','2025-06-10 10:27:30'),(3,3,1,10.00,0.00,-10.00,NULL,NULL,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(4,3,2,0.00,0.00,0.00,NULL,NULL,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(5,3,3,0.00,0.00,0.00,NULL,NULL,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(6,3,4,0.00,0.00,0.00,NULL,NULL,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(7,3,5,0.00,0.00,0.00,NULL,NULL,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(8,3,6,0.00,0.00,0.00,NULL,NULL,'2025-06-11 22:21:32','2025-06-11 22:21:32');
|
||||||
/*!40000 ALTER TABLE `opname_details` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `opname_details` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
@@ -199,20 +282,20 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `opnames`;
|
DROP TABLE IF EXISTS `opnames`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `opnames` (
|
CREATE TABLE `opnames` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`dealer_id` bigint unsigned NOT NULL,
|
`dealer_id` bigint(20) unsigned NOT NULL,
|
||||||
`opname_date` date NOT NULL,
|
`opname_date` date NOT NULL,
|
||||||
`user_id` bigint unsigned NOT NULL,
|
`user_id` bigint(20) unsigned NOT NULL,
|
||||||
`note` text COLLATE utf8mb4_unicode_ci,
|
`note` text DEFAULT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
`status` enum('draft','pending','approved','rejected') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'draft',
|
`status` enum('draft','pending','approved','rejected') NOT NULL DEFAULT 'draft',
|
||||||
`approved_by` bigint unsigned DEFAULT NULL,
|
`approved_by` bigint(20) unsigned DEFAULT NULL,
|
||||||
`approved_at` timestamp NULL DEFAULT NULL,
|
`approved_at` timestamp NULL DEFAULT NULL,
|
||||||
`rejection_note` text COLLATE utf8mb4_unicode_ci,
|
`rejection_note` text DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `opnames_dealer_id_foreign` (`dealer_id`),
|
KEY `opnames_dealer_id_foreign` (`dealer_id`),
|
||||||
KEY `opnames_user_id_foreign` (`user_id`),
|
KEY `opnames_user_id_foreign` (`user_id`),
|
||||||
@@ -220,7 +303,7 @@ CREATE TABLE `opnames` (
|
|||||||
CONSTRAINT `opnames_approved_by_foreign` FOREIGN KEY (`approved_by`) REFERENCES `users` (`id`),
|
CONSTRAINT `opnames_approved_by_foreign` FOREIGN KEY (`approved_by`) REFERENCES `users` (`id`),
|
||||||
CONSTRAINT `opnames_dealer_id_foreign` FOREIGN KEY (`dealer_id`) REFERENCES `dealers` (`id`) ON DELETE CASCADE,
|
CONSTRAINT `opnames_dealer_id_foreign` FOREIGN KEY (`dealer_id`) REFERENCES `dealers` (`id`) ON DELETE CASCADE,
|
||||||
CONSTRAINT `opnames_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
CONSTRAINT `opnames_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -229,7 +312,7 @@ CREATE TABLE `opnames` (
|
|||||||
|
|
||||||
LOCK TABLES `opnames` WRITE;
|
LOCK TABLES `opnames` WRITE;
|
||||||
/*!40000 ALTER TABLE `opnames` DISABLE KEYS */;
|
/*!40000 ALTER TABLE `opnames` DISABLE KEYS */;
|
||||||
INSERT INTO `opnames` VALUES (1,20,'2025-06-10',8,'test tambah product by opname',NULL,'2025-06-10 10:26:24','2025-06-10 10:26:24','approved',8,'2025-06-10 10:26:24',NULL),(2,24,'2025-06-10',8,'test tambah produk by opname',NULL,'2025-06-10 10:27:30','2025-06-10 10:27:30','approved',8,'2025-06-10 10:27:30',NULL);
|
INSERT INTO `opnames` VALUES (1,20,'2025-06-10',8,'test tambah product by opname',NULL,'2025-06-10 10:26:24','2025-06-10 10:26:24','approved',8,'2025-06-10 10:26:24',NULL),(2,24,'2025-06-10',8,'test tambah produk by opname',NULL,'2025-06-10 10:27:30','2025-06-10 10:27:30','approved',8,'2025-06-10 10:27:30',NULL),(3,20,'2025-06-11',8,NULL,NULL,'2025-06-11 22:21:32','2025-06-11 22:21:32','approved',8,'2025-06-11 22:21:32',NULL);
|
||||||
/*!40000 ALTER TABLE `opnames` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `opnames` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
@@ -239,10 +322,10 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `password_resets`;
|
DROP TABLE IF EXISTS `password_resets`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `password_resets` (
|
CREATE TABLE `password_resets` (
|
||||||
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`email` varchar(255) NOT NULL,
|
||||||
`token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`token` varchar(255) NOT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
KEY `password_resets_email_index` (`email`)
|
KEY `password_resets_email_index` (`email`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
@@ -263,14 +346,14 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `personal_access_tokens`;
|
DROP TABLE IF EXISTS `personal_access_tokens`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `personal_access_tokens` (
|
CREATE TABLE `personal_access_tokens` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`tokenable_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`tokenable_type` varchar(255) NOT NULL,
|
||||||
`tokenable_id` bigint unsigned NOT NULL,
|
`tokenable_id` bigint(20) unsigned NOT NULL,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`token` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`token` varchar(64) NOT NULL,
|
||||||
`abilities` text COLLATE utf8mb4_unicode_ci,
|
`abilities` text DEFAULT NULL,
|
||||||
`last_used_at` timestamp NULL DEFAULT NULL,
|
`last_used_at` timestamp NULL DEFAULT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
@@ -296,18 +379,18 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `privileges`;
|
DROP TABLE IF EXISTS `privileges`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `privileges` (
|
CREATE TABLE `privileges` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`role_id` bigint unsigned NOT NULL,
|
`role_id` bigint(20) unsigned NOT NULL,
|
||||||
`create` tinyint NOT NULL,
|
`create` tinyint(4) NOT NULL,
|
||||||
`update` tinyint NOT NULL,
|
`update` tinyint(4) NOT NULL,
|
||||||
`delete` tinyint NOT NULL,
|
`delete` tinyint(4) NOT NULL,
|
||||||
`view` tinyint NOT NULL,
|
`view` tinyint(4) NOT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
`menu_id` bigint unsigned NOT NULL,
|
`menu_id` bigint(20) unsigned NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `privileges_role_id_foreign` (`role_id`),
|
KEY `privileges_role_id_foreign` (`role_id`),
|
||||||
KEY `privileges_menu_id_foreign` (`menu_id`),
|
KEY `privileges_menu_id_foreign` (`menu_id`),
|
||||||
@@ -332,11 +415,11 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `product_categories`;
|
DROP TABLE IF EXISTS `product_categories`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `product_categories` (
|
CREATE TABLE `product_categories` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`parent_id` bigint unsigned DEFAULT NULL,
|
`parent_id` bigint(20) unsigned DEFAULT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
@@ -362,15 +445,15 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `products`;
|
DROP TABLE IF EXISTS `products`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `products` (
|
CREATE TABLE `products` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`code` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`code` varchar(255) NOT NULL,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`active` tinyint(1) NOT NULL DEFAULT '1',
|
`active` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
`unit` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
`unit` varchar(255) DEFAULT NULL,
|
||||||
`description` text COLLATE utf8mb4_unicode_ci,
|
`description` text DEFAULT NULL,
|
||||||
`product_category_id` bigint unsigned NOT NULL,
|
`product_category_id` bigint(20) unsigned NOT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
@@ -397,10 +480,10 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `roles`;
|
DROP TABLE IF EXISTS `roles`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `roles` (
|
CREATE TABLE `roles` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
@@ -424,18 +507,18 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `stock_logs`;
|
DROP TABLE IF EXISTS `stock_logs`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `stock_logs` (
|
CREATE TABLE `stock_logs` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`stock_id` bigint unsigned NOT NULL,
|
`stock_id` bigint(20) unsigned NOT NULL,
|
||||||
`source_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`source_type` varchar(255) NOT NULL,
|
||||||
`source_id` bigint unsigned NOT NULL,
|
`source_id` bigint(20) unsigned NOT NULL,
|
||||||
`previous_quantity` decimal(10,2) NOT NULL,
|
`previous_quantity` decimal(10,2) NOT NULL,
|
||||||
`new_quantity` decimal(10,2) NOT NULL,
|
`new_quantity` decimal(10,2) NOT NULL,
|
||||||
`quantity_change` decimal(10,2) NOT NULL,
|
`quantity_change` decimal(10,2) NOT NULL,
|
||||||
`change_type` enum('increase','decrease','adjustment','no_change') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'no_change',
|
`change_type` enum('increase','decrease','adjustment','no_change') NOT NULL DEFAULT 'no_change',
|
||||||
`description` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
`description` varchar(255) DEFAULT NULL,
|
||||||
`user_id` bigint unsigned NOT NULL,
|
`user_id` bigint(20) unsigned NOT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
@@ -444,7 +527,7 @@ CREATE TABLE `stock_logs` (
|
|||||||
KEY `stock_logs_source_type_source_id_index` (`source_type`,`source_id`),
|
KEY `stock_logs_source_type_source_id_index` (`source_type`,`source_id`),
|
||||||
CONSTRAINT `stock_logs_stock_id_foreign` FOREIGN KEY (`stock_id`) REFERENCES `stocks` (`id`) ON DELETE CASCADE,
|
CONSTRAINT `stock_logs_stock_id_foreign` FOREIGN KEY (`stock_id`) REFERENCES `stocks` (`id`) ON DELETE CASCADE,
|
||||||
CONSTRAINT `stock_logs_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
CONSTRAINT `stock_logs_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -453,7 +536,7 @@ CREATE TABLE `stock_logs` (
|
|||||||
|
|
||||||
LOCK TABLES `stock_logs` WRITE;
|
LOCK TABLES `stock_logs` WRITE;
|
||||||
/*!40000 ALTER TABLE `stock_logs` DISABLE KEYS */;
|
/*!40000 ALTER TABLE `stock_logs` DISABLE KEYS */;
|
||||||
INSERT INTO `stock_logs` VALUES (1,1,'App\\Models\\Opname',1,0.00,10.00,10.00,'increase','Stock adjustment from auto-approved opname #1',8,'2025-06-10 10:26:24','2025-06-10 10:26:24'),(2,2,'App\\Models\\Opname',2,0.00,30.00,30.00,'increase','Stock adjustment from auto-approved opname #2',8,'2025-06-10 10:27:30','2025-06-10 10:27:30');
|
INSERT INTO `stock_logs` VALUES (1,1,'App\\Models\\Opname',1,0.00,10.00,10.00,'increase','Stock adjustment from auto-approved opname #1',8,'2025-06-10 10:26:24','2025-06-10 10:26:24'),(2,2,'App\\Models\\Opname',2,0.00,30.00,30.00,'increase','Stock adjustment from auto-approved opname #2',8,'2025-06-10 10:27:30','2025-06-10 10:27:30'),(3,1,'App\\Models\\Opname',3,10.00,0.00,-10.00,'decrease','Stock adjustment from auto-approved opname #3',8,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(4,3,'App\\Models\\Opname',3,0.00,0.00,0.00,'no_change','Stock adjustment from auto-approved opname #3',8,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(5,4,'App\\Models\\Opname',3,0.00,0.00,0.00,'no_change','Stock adjustment from auto-approved opname #3',8,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(6,5,'App\\Models\\Opname',3,0.00,0.00,0.00,'no_change','Stock adjustment from auto-approved opname #3',8,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(7,6,'App\\Models\\Opname',3,0.00,0.00,0.00,'no_change','Stock adjustment from auto-approved opname #3',8,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(8,7,'App\\Models\\Opname',3,0.00,0.00,0.00,'no_change','Stock adjustment from auto-approved opname #3',8,'2025-06-11 22:21:32','2025-06-11 22:21:32');
|
||||||
/*!40000 ALTER TABLE `stock_logs` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `stock_logs` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
@@ -463,12 +546,12 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `stocks`;
|
DROP TABLE IF EXISTS `stocks`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `stocks` (
|
CREATE TABLE `stocks` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`product_id` bigint unsigned NOT NULL,
|
`product_id` bigint(20) unsigned NOT NULL,
|
||||||
`dealer_id` bigint unsigned NOT NULL,
|
`dealer_id` bigint(20) unsigned NOT NULL,
|
||||||
`quantity` decimal(10,2) NOT NULL DEFAULT '0.00',
|
`quantity` decimal(10,2) NOT NULL DEFAULT 0.00,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
@@ -476,7 +559,7 @@ CREATE TABLE `stocks` (
|
|||||||
KEY `stocks_dealer_id_foreign` (`dealer_id`),
|
KEY `stocks_dealer_id_foreign` (`dealer_id`),
|
||||||
CONSTRAINT `stocks_dealer_id_foreign` FOREIGN KEY (`dealer_id`) REFERENCES `dealers` (`id`) ON DELETE CASCADE,
|
CONSTRAINT `stocks_dealer_id_foreign` FOREIGN KEY (`dealer_id`) REFERENCES `dealers` (`id`) ON DELETE CASCADE,
|
||||||
CONSTRAINT `stocks_product_id_foreign` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE
|
CONSTRAINT `stocks_product_id_foreign` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -485,7 +568,7 @@ CREATE TABLE `stocks` (
|
|||||||
|
|
||||||
LOCK TABLES `stocks` WRITE;
|
LOCK TABLES `stocks` WRITE;
|
||||||
/*!40000 ALTER TABLE `stocks` DISABLE KEYS */;
|
/*!40000 ALTER TABLE `stocks` DISABLE KEYS */;
|
||||||
INSERT INTO `stocks` VALUES (1,1,20,10.00,'2025-06-10 10:26:24','2025-06-10 10:26:24'),(2,1,24,30.00,'2025-06-10 10:27:30','2025-06-10 10:27:30');
|
INSERT INTO `stocks` VALUES (1,1,20,0.00,'2025-06-10 10:26:24','2025-06-11 22:21:32'),(2,1,24,30.00,'2025-06-10 10:27:30','2025-06-10 10:27:30'),(3,2,20,0.00,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(4,3,20,0.00,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(5,4,20,0.00,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(6,5,20,0.00,'2025-06-11 22:21:32','2025-06-11 22:21:32'),(7,6,20,0.00,'2025-06-11 22:21:32','2025-06-11 22:21:32');
|
||||||
/*!40000 ALTER TABLE `stocks` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `stocks` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
@@ -495,22 +578,22 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `transactions`;
|
DROP TABLE IF EXISTS `transactions`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `transactions` (
|
CREATE TABLE `transactions` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`user_id` bigint unsigned NOT NULL,
|
`user_id` bigint(20) unsigned NOT NULL,
|
||||||
`user_sa_id` bigint unsigned NOT NULL,
|
`user_sa_id` bigint(20) unsigned NOT NULL,
|
||||||
`work_id` bigint unsigned NOT NULL,
|
`work_id` bigint(20) unsigned NOT NULL,
|
||||||
`spk` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`spk` varchar(255) NOT NULL,
|
||||||
`police_number` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`police_number` varchar(255) NOT NULL,
|
||||||
`warranty` tinyint NOT NULL,
|
`warranty` tinyint(4) NOT NULL,
|
||||||
`date` datetime NOT NULL,
|
`date` datetime NOT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
`form` enum('work','wash') COLLATE utf8mb4_unicode_ci NOT NULL,
|
`form` enum('work','wash') NOT NULL,
|
||||||
`qty` bigint unsigned NOT NULL,
|
`qty` bigint(20) unsigned NOT NULL,
|
||||||
`status` tinyint NOT NULL DEFAULT '0',
|
`status` tinyint(4) NOT NULL DEFAULT 0,
|
||||||
`dealer_id` bigint unsigned NOT NULL,
|
`dealer_id` bigint(20) unsigned NOT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `transactions_user_id_foreign` (`user_id`),
|
KEY `transactions_user_id_foreign` (`user_id`),
|
||||||
@@ -574,20 +657,20 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `users`;
|
DROP TABLE IF EXISTS `users`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `users` (
|
CREATE TABLE `users` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`dealer_id` bigint unsigned NOT NULL,
|
`dealer_id` bigint(20) unsigned NOT NULL,
|
||||||
`role` enum('admin','sa','mechanic') COLLATE utf8mb4_unicode_ci NOT NULL,
|
`role` enum('admin','sa','mechanic') NOT NULL,
|
||||||
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`email` varchar(255) NOT NULL,
|
||||||
`email_verified_at` timestamp NULL DEFAULT NULL,
|
`email_verified_at` timestamp NULL DEFAULT NULL,
|
||||||
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`password` varchar(255) NOT NULL,
|
||||||
`remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
`remember_token` varchar(100) DEFAULT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
`role_id` bigint unsigned NOT NULL,
|
`role_id` bigint(20) unsigned NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `users_email_unique` (`email`),
|
UNIQUE KEY `users_email_unique` (`email`),
|
||||||
KEY `users_dealer_id_foreign` (`dealer_id`),
|
KEY `users_dealer_id_foreign` (`dealer_id`),
|
||||||
@@ -611,15 +694,15 @@ UNLOCK TABLES;
|
|||||||
|
|
||||||
DROP TABLE IF EXISTS `works`;
|
DROP TABLE IF EXISTS `works`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!50503 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `works` (
|
CREATE TABLE `works` (
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
`desc` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
`desc` text NOT NULL,
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
`category_id` bigint unsigned NOT NULL,
|
`category_id` bigint(20) unsigned NOT NULL,
|
||||||
`shortname` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`shortname` varchar(255) NOT NULL,
|
||||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `works_category_id_foreign` (`category_id`),
|
KEY `works_category_id_foreign` (`category_id`),
|
||||||
@@ -636,6 +719,10 @@ LOCK TABLES `works` WRITE;
|
|||||||
INSERT INTO `works` VALUES (1,'CUCI','-',NULL,'2022-06-09 08:06:59',1,'Cuci',NULL),(6,'SPOORING','-',NULL,'2022-06-09 08:34:27',3,'SP',NULL),(7,'SPOORING TRUK','-',NULL,'2022-06-09 08:34:38',3,'SP TRUCK',NULL),(8,'SPOORING + BAUT CAMBER','-',NULL,'2022-06-09 08:34:56',3,'SP + BC',NULL),(9,'BALANCING','-',NULL,'2022-06-09 08:35:08',3,'BL',NULL),(10,'BALANCING R < 15','-',NULL,'2022-06-09 08:35:26',3,'BL R<15',NULL),(11,'BALANCING R > 15','-',NULL,'2022-06-09 08:35:43',3,'BL R>15',NULL),(12,'NITROGEN FULL','-',NULL,'2022-06-09 08:36:32',3,'N2',NULL),(13,'NITROGEN TAMBAH','-',NULL,'2022-06-09 08:41:19',3,'N+',NULL),(14,'BAUT CAMBER ','-',NULL,NULL,3,'BC',NULL),(15,'AC CLEANER SINGLE BLOWER','-',NULL,'2022-06-09 08:41:36',3,'SB',NULL),(16,'AC CLEANER DOUBLE BLOWER','-',NULL,'2022-06-09 08:41:45',3,'DB',NULL),(17,'FOGGING','-',NULL,'2022-06-09 08:42:29',3,'FOG',NULL),(18,'GLASS POLISH ','-',NULL,NULL,3,'GP',NULL),(19,'ENGINE DRESSING ','-',NULL,NULL,3,'ED',NULL),(20,'ENGINE CARE ','-',NULL,NULL,3,'EC',NULL),(21,'ENGINE CLEANING UAP ','-',NULL,NULL,3,'ECU',NULL),(22,'BUBUT DISC BRAKE','-',NULL,'2022-06-09 08:44:00',3,'DL',NULL),(23,'TIRE CHANGER ','-',NULL,NULL,3,'TC',NULL),(24,'CHAMBER CLEANER ','-',NULL,NULL,3,'CC',NULL),(25,'DIESEL PURGING ','-',NULL,NULL,3,'DP',NULL),(26,'FUEL INJECTOR CLEANER','-',NULL,'2022-06-09 08:48:35',3,'IC',NULL),(27,'TURBO CLEANER','-',NULL,'2022-06-09 08:45:19',3,'TCC',NULL),(28,'CATALYTIC CLEANER','-',NULL,NULL,3,'CTC',NULL),(29,'INTERIOR CLEANING UAP ','-',NULL,NULL,3,'ICU',NULL),(30,'HHO ','-',NULL,NULL,3,'HHO',NULL),(31,'engine flush','-','2023-06-02 03:35:58','2023-06-02 03:35:58',3,'EF',NULL),(32,'ISI FREON SINGLE BLOWER','-','2023-11-02 04:08:57','2023-11-02 04:08:57',3,'FR SB 1',NULL),(33,'ISI FREON DOUBLE BLOWER','-','2023-11-02 04:09:25','2023-11-02 04:09:25',3,'FR DB 2',NULL),(34,'Oil lining performance','jasa oil lining','2023-12-05 10:26:43','2023-12-05 10:28:49',3,'OLP',NULL),(35,'engine oil performance b1','jasa ganti oli','2023-12-05 10:27:36','2023-12-05 10:28:59',3,'B1',NULL),(36,'engine oil performance b2','jasa ganti oli b2','2023-12-05 10:28:03','2023-12-05 10:29:09',3,'B2',NULL),(37,'Oil lining performance non engine flush','jasa oil lining tanpa engine flush','2024-03-08 06:41:41','2024-03-08 06:42:53',3,'OLP NON EF',NULL),(38,'AC FRESH SERVICE','parfurmed ac','2024-03-13 05:08:15','2024-03-13 05:08:15',3,'AC FRESH',NULL),(39,'AC LIGHT SERVICE - SINGLE BLOWER','penggantian dryer, oli komprespor, dan refrigant','2024-03-13 05:12:47','2024-03-13 05:12:47',3,'AC LIGHT - SB',NULL),(40,'AC LIGHT SERVICE - DOUBLE BLOWER','penggantian dryer, oli komprespor, dan refrigant','2024-03-13 05:13:39','2024-03-13 05:14:18',3,'AC LIGHT - DB',NULL),(41,'AC HEAVY SERVICE - SINGLE BLOWER','penggantian dryer, oli komprespor, dan refrigant (cek kebocoran EVAP)','2024-03-13 05:15:29','2024-03-13 05:15:29',3,'AC HEAVY - SB',NULL),(42,'AC HEAVY SERVICE - DOUBLE BLOWER','penggantian dryer, oli komprespor, dan refrigant (cek kebocoran EVAP)','2024-03-13 05:16:05','2024-03-13 05:16:05',3,'AC HEAVY - DB',NULL),(43,'AC CLEAN SERVICE','pembersihan saluran ac dan evap','2024-04-24 09:49:02','2024-04-24 09:49:02',3,'ACCS',NULL),(44,'COOLANT CHANGER & COOLING SYSTEM CLEANER','kuras radiator dan penggantian coolant','2024-07-08 10:58:52','2024-07-08 10:58:52',3,'C3SC',NULL),(45,'AT CVT FLUSHING','pembersihan transmisi matic cvt','2024-09-18 09:33:09','2024-09-18 09:33:09',3,'AT CVT FLUSHING',NULL),(46,'CUCI SNOW','cuci snow','2024-09-19 08:20:30','2024-09-19 08:20:30',1,'CUCI SNOW',NULL);
|
INSERT INTO `works` VALUES (1,'CUCI','-',NULL,'2022-06-09 08:06:59',1,'Cuci',NULL),(6,'SPOORING','-',NULL,'2022-06-09 08:34:27',3,'SP',NULL),(7,'SPOORING TRUK','-',NULL,'2022-06-09 08:34:38',3,'SP TRUCK',NULL),(8,'SPOORING + BAUT CAMBER','-',NULL,'2022-06-09 08:34:56',3,'SP + BC',NULL),(9,'BALANCING','-',NULL,'2022-06-09 08:35:08',3,'BL',NULL),(10,'BALANCING R < 15','-',NULL,'2022-06-09 08:35:26',3,'BL R<15',NULL),(11,'BALANCING R > 15','-',NULL,'2022-06-09 08:35:43',3,'BL R>15',NULL),(12,'NITROGEN FULL','-',NULL,'2022-06-09 08:36:32',3,'N2',NULL),(13,'NITROGEN TAMBAH','-',NULL,'2022-06-09 08:41:19',3,'N+',NULL),(14,'BAUT CAMBER ','-',NULL,NULL,3,'BC',NULL),(15,'AC CLEANER SINGLE BLOWER','-',NULL,'2022-06-09 08:41:36',3,'SB',NULL),(16,'AC CLEANER DOUBLE BLOWER','-',NULL,'2022-06-09 08:41:45',3,'DB',NULL),(17,'FOGGING','-',NULL,'2022-06-09 08:42:29',3,'FOG',NULL),(18,'GLASS POLISH ','-',NULL,NULL,3,'GP',NULL),(19,'ENGINE DRESSING ','-',NULL,NULL,3,'ED',NULL),(20,'ENGINE CARE ','-',NULL,NULL,3,'EC',NULL),(21,'ENGINE CLEANING UAP ','-',NULL,NULL,3,'ECU',NULL),(22,'BUBUT DISC BRAKE','-',NULL,'2022-06-09 08:44:00',3,'DL',NULL),(23,'TIRE CHANGER ','-',NULL,NULL,3,'TC',NULL),(24,'CHAMBER CLEANER ','-',NULL,NULL,3,'CC',NULL),(25,'DIESEL PURGING ','-',NULL,NULL,3,'DP',NULL),(26,'FUEL INJECTOR CLEANER','-',NULL,'2022-06-09 08:48:35',3,'IC',NULL),(27,'TURBO CLEANER','-',NULL,'2022-06-09 08:45:19',3,'TCC',NULL),(28,'CATALYTIC CLEANER','-',NULL,NULL,3,'CTC',NULL),(29,'INTERIOR CLEANING UAP ','-',NULL,NULL,3,'ICU',NULL),(30,'HHO ','-',NULL,NULL,3,'HHO',NULL),(31,'engine flush','-','2023-06-02 03:35:58','2023-06-02 03:35:58',3,'EF',NULL),(32,'ISI FREON SINGLE BLOWER','-','2023-11-02 04:08:57','2023-11-02 04:08:57',3,'FR SB 1',NULL),(33,'ISI FREON DOUBLE BLOWER','-','2023-11-02 04:09:25','2023-11-02 04:09:25',3,'FR DB 2',NULL),(34,'Oil lining performance','jasa oil lining','2023-12-05 10:26:43','2023-12-05 10:28:49',3,'OLP',NULL),(35,'engine oil performance b1','jasa ganti oli','2023-12-05 10:27:36','2023-12-05 10:28:59',3,'B1',NULL),(36,'engine oil performance b2','jasa ganti oli b2','2023-12-05 10:28:03','2023-12-05 10:29:09',3,'B2',NULL),(37,'Oil lining performance non engine flush','jasa oil lining tanpa engine flush','2024-03-08 06:41:41','2024-03-08 06:42:53',3,'OLP NON EF',NULL),(38,'AC FRESH SERVICE','parfurmed ac','2024-03-13 05:08:15','2024-03-13 05:08:15',3,'AC FRESH',NULL),(39,'AC LIGHT SERVICE - SINGLE BLOWER','penggantian dryer, oli komprespor, dan refrigant','2024-03-13 05:12:47','2024-03-13 05:12:47',3,'AC LIGHT - SB',NULL),(40,'AC LIGHT SERVICE - DOUBLE BLOWER','penggantian dryer, oli komprespor, dan refrigant','2024-03-13 05:13:39','2024-03-13 05:14:18',3,'AC LIGHT - DB',NULL),(41,'AC HEAVY SERVICE - SINGLE BLOWER','penggantian dryer, oli komprespor, dan refrigant (cek kebocoran EVAP)','2024-03-13 05:15:29','2024-03-13 05:15:29',3,'AC HEAVY - SB',NULL),(42,'AC HEAVY SERVICE - DOUBLE BLOWER','penggantian dryer, oli komprespor, dan refrigant (cek kebocoran EVAP)','2024-03-13 05:16:05','2024-03-13 05:16:05',3,'AC HEAVY - DB',NULL),(43,'AC CLEAN SERVICE','pembersihan saluran ac dan evap','2024-04-24 09:49:02','2024-04-24 09:49:02',3,'ACCS',NULL),(44,'COOLANT CHANGER & COOLING SYSTEM CLEANER','kuras radiator dan penggantian coolant','2024-07-08 10:58:52','2024-07-08 10:58:52',3,'C3SC',NULL),(45,'AT CVT FLUSHING','pembersihan transmisi matic cvt','2024-09-18 09:33:09','2024-09-18 09:33:09',3,'AT CVT FLUSHING',NULL),(46,'CUCI SNOW','cuci snow','2024-09-19 08:20:30','2024-09-19 08:20:30',1,'CUCI SNOW',NULL);
|
||||||
/*!40000 ALTER TABLE `works` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `works` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping routines for database 'ckb_db'
|
||||||
|
--
|
||||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||||
|
|
||||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||||
@@ -646,4 +733,4 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
-- Dump completed on 2025-06-10 18:16:53
|
-- Dump completed on 2025-06-11 17:30:35
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"laravel/ui": "^3.4",
|
"laravel/ui": "^3.4",
|
||||||
"maatwebsite/excel": "^3.1",
|
"maatwebsite/excel": "^3.1",
|
||||||
"nesbot/carbon": "^2.73",
|
"nesbot/carbon": "^2.73",
|
||||||
"yajra/laravel-datatables-oracle": "^9.20"
|
"yajra/laravel-datatables-oracle": "^9.21"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"facade/ignition": "^2.5",
|
"facade/ignition": "^2.5",
|
||||||
|
|||||||
28
composer.lock
generated
28
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "3e3b47389d4bce664f705134cae65b49",
|
"content-hash": "a73100beed847d2c43aca4cca10a0d86",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "asm89/stack-cors",
|
"name": "asm89/stack-cors",
|
||||||
@@ -6450,16 +6450,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "yajra/laravel-datatables-oracle",
|
"name": "yajra/laravel-datatables-oracle",
|
||||||
"version": "v9.20.0",
|
"version": "v9.21.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/yajra/laravel-datatables.git",
|
"url": "https://github.com/yajra/laravel-datatables.git",
|
||||||
"reference": "4c22b09c8c664df5aad9f17d99c3823c0f2d84e2"
|
"reference": "a7fd01f06282923e9c63fa27fe6b391e21dc321a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/yajra/laravel-datatables/zipball/4c22b09c8c664df5aad9f17d99c3823c0f2d84e2",
|
"url": "https://api.github.com/repos/yajra/laravel-datatables/zipball/a7fd01f06282923e9c63fa27fe6b391e21dc321a",
|
||||||
"reference": "4c22b09c8c664df5aad9f17d99c3823c0f2d84e2",
|
"reference": "a7fd01f06282923e9c63fa27fe6b391e21dc321a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6481,16 +6481,16 @@
|
|||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "9.0-dev"
|
|
||||||
},
|
|
||||||
"laravel": {
|
"laravel": {
|
||||||
"providers": [
|
|
||||||
"Yajra\\DataTables\\DataTablesServiceProvider"
|
|
||||||
],
|
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"DataTables": "Yajra\\DataTables\\Facades\\DataTables"
|
"DataTables": "Yajra\\DataTables\\Facades\\DataTables"
|
||||||
}
|
},
|
||||||
|
"providers": [
|
||||||
|
"Yajra\\DataTables\\DataTablesServiceProvider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "9.0-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -6519,7 +6519,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/yajra/laravel-datatables/issues",
|
"issues": "https://github.com/yajra/laravel-datatables/issues",
|
||||||
"source": "https://github.com/yajra/laravel-datatables/tree/v9.20.0"
|
"source": "https://github.com/yajra/laravel-datatables/tree/v9.21.2"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -6531,7 +6531,7 @@
|
|||||||
"type": "patreon"
|
"type": "patreon"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-05-08T16:04:16+00:00"
|
"time": "2022-07-12T04:48:03+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('mutations', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('mutation_number')->unique();
|
||||||
|
$table->foreignId('from_dealer_id')->constrained('dealers');
|
||||||
|
$table->foreignId('to_dealer_id')->constrained('dealers');
|
||||||
|
$table->enum('status', ['pending', 'sent', 'received', 'approved', 'rejected', 'completed', 'cancelled'])
|
||||||
|
->default('sent');
|
||||||
|
$table->foreignId('requested_by')->constrained('users');
|
||||||
|
$table->foreignId('approved_by')->nullable()->constrained('users');
|
||||||
|
$table->timestamp('approved_at')->nullable();
|
||||||
|
$table->foreignId('received_by')->nullable()->constrained('users');
|
||||||
|
$table->timestamp('received_at')->nullable();
|
||||||
|
$table->text('notes')->nullable();
|
||||||
|
$table->text('rejection_reason')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
|
||||||
|
// Indexes untuk performa
|
||||||
|
$table->index(['from_dealer_id', 'status']);
|
||||||
|
$table->index(['to_dealer_id', 'status']);
|
||||||
|
$table->index(['status', 'created_at']);
|
||||||
|
$table->index('mutation_number');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('mutations');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('mutation_details', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('mutation_id')->constrained('mutations')->onDelete('cascade');
|
||||||
|
$table->foreignId('product_id')->constrained('products');
|
||||||
|
$table->decimal('quantity_requested', 15, 2);
|
||||||
|
$table->decimal('quantity_approved', 15, 2)->default(0);
|
||||||
|
$table->text('notes')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
// Indexes untuk performa
|
||||||
|
$table->index(['mutation_id', 'product_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('mutation_details');
|
||||||
|
}
|
||||||
|
};
|
||||||
159
database/seeders/MutationTestSeeder.php
Normal file
159
database/seeders/MutationTestSeeder.php
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use App\Models\Mutation;
|
||||||
|
use App\Models\MutationDetail;
|
||||||
|
use App\Models\Dealer;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Enums\MutationStatus;
|
||||||
|
|
||||||
|
class MutationTestSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
// Pastikan ada dealer dan produk
|
||||||
|
$dealers = Dealer::take(3)->get();
|
||||||
|
$products = Product::take(5)->get();
|
||||||
|
$users = User::take(3)->get();
|
||||||
|
|
||||||
|
$this->command->info('Dealers found: ' . $dealers->count());
|
||||||
|
$this->command->info('Products found: ' . $products->count());
|
||||||
|
$this->command->info('Users found: ' . $users->count());
|
||||||
|
|
||||||
|
if ($dealers->count() < 2 || $products->count() < 2 || $users->count() < 1) {
|
||||||
|
$this->command->error('Tidak cukup data dealer, produk, atau user untuk membuat test mutation');
|
||||||
|
$this->command->error("Need at least 2 dealers, 2 products, 1 user");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Mutation dengan status SENT (baru terkirim, menunggu diterima dealer tujuan)
|
||||||
|
$this->command->info('Creating SENT mutation...');
|
||||||
|
$mutation1 = Mutation::create([
|
||||||
|
'from_dealer_id' => $dealers[0]->id,
|
||||||
|
'to_dealer_id' => $dealers[1]->id,
|
||||||
|
'status' => MutationStatus::SENT,
|
||||||
|
'requested_by' => $users[0]->id,
|
||||||
|
'notes' => 'Mutasi test - status SENT (menunggu diterima)'
|
||||||
|
]);
|
||||||
|
|
||||||
|
MutationDetail::create([
|
||||||
|
'mutation_id' => $mutation1->id,
|
||||||
|
'product_id' => $products[0]->id,
|
||||||
|
'quantity_requested' => 10.00,
|
||||||
|
'notes' => 'Produk test 1'
|
||||||
|
]);
|
||||||
|
|
||||||
|
MutationDetail::create([
|
||||||
|
'mutation_id' => $mutation1->id,
|
||||||
|
'product_id' => $products[1]->id,
|
||||||
|
'quantity_requested' => 5.00,
|
||||||
|
'notes' => 'Produk test 2'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 2. Mutation dengan status RECEIVED (sudah diterima, menunggu approval pengirim)
|
||||||
|
$this->command->info('Creating RECEIVED mutation...');
|
||||||
|
$mutation2 = Mutation::create([
|
||||||
|
'from_dealer_id' => $dealers[0]->id,
|
||||||
|
'to_dealer_id' => $dealers[1]->id,
|
||||||
|
'status' => MutationStatus::RECEIVED,
|
||||||
|
'requested_by' => $users[0]->id,
|
||||||
|
'received_by' => $users[1]->id ?? $users[0]->id,
|
||||||
|
'received_at' => now()->subHours(2),
|
||||||
|
'notes' => 'Mutasi test - status RECEIVED (menunggu approval)'
|
||||||
|
]);
|
||||||
|
|
||||||
|
MutationDetail::create([
|
||||||
|
'mutation_id' => $mutation2->id,
|
||||||
|
'product_id' => $products[0]->id,
|
||||||
|
'quantity_requested' => 8.00,
|
||||||
|
'notes' => 'Produk untuk approval'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 3. Mutation dengan status APPROVED (sudah diapprove, siap dikompletkan)
|
||||||
|
$this->command->info('Creating APPROVED mutation...');
|
||||||
|
$mutation3 = Mutation::create([
|
||||||
|
'from_dealer_id' => $dealers[0]->id,
|
||||||
|
'to_dealer_id' => $dealers[1]->id,
|
||||||
|
'status' => MutationStatus::APPROVED,
|
||||||
|
'requested_by' => $users[0]->id,
|
||||||
|
'received_by' => $users[1]->id ?? $users[0]->id,
|
||||||
|
'received_at' => now()->subHours(4),
|
||||||
|
'approved_by' => $users[0]->id,
|
||||||
|
'approved_at' => now()->subHours(1),
|
||||||
|
'notes' => 'Mutasi test - status APPROVED (siap dikompletkan)'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$mutation3Detail = MutationDetail::create([
|
||||||
|
'mutation_id' => $mutation3->id,
|
||||||
|
'product_id' => $products[0]->id,
|
||||||
|
'quantity_requested' => 12.00,
|
||||||
|
'quantity_approved' => 10.00, // Approved dengan jumlah berbeda
|
||||||
|
'notes' => 'Produk approved parsial'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 4. Mutation dengan status COMPLETED (selesai)
|
||||||
|
$this->command->info('Creating COMPLETED mutation...');
|
||||||
|
$mutation4 = Mutation::create([
|
||||||
|
'from_dealer_id' => $dealers[0]->id,
|
||||||
|
'to_dealer_id' => $dealers[1]->id,
|
||||||
|
'status' => MutationStatus::COMPLETED,
|
||||||
|
'requested_by' => $users[0]->id,
|
||||||
|
'received_by' => $users[1]->id ?? $users[0]->id,
|
||||||
|
'received_at' => now()->subDay(),
|
||||||
|
'approved_by' => $users[0]->id,
|
||||||
|
'approved_at' => now()->subHours(6),
|
||||||
|
'notes' => 'Mutasi test - status COMPLETED'
|
||||||
|
]);
|
||||||
|
|
||||||
|
MutationDetail::create([
|
||||||
|
'mutation_id' => $mutation4->id,
|
||||||
|
'product_id' => $products[1]->id,
|
||||||
|
'quantity_requested' => 6.00,
|
||||||
|
'quantity_approved' => 6.00,
|
||||||
|
'notes' => 'Produk completed'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 5. Mutation dengan status REJECTED
|
||||||
|
$this->command->info('Creating REJECTED mutation...');
|
||||||
|
$mutation5 = Mutation::create([
|
||||||
|
'from_dealer_id' => $dealers[0]->id,
|
||||||
|
'to_dealer_id' => $dealers[1]->id,
|
||||||
|
'status' => MutationStatus::REJECTED,
|
||||||
|
'requested_by' => $users[0]->id,
|
||||||
|
'received_by' => $users[1]->id ?? $users[0]->id,
|
||||||
|
'received_at' => now()->subHours(8),
|
||||||
|
'approved_by' => $users[0]->id,
|
||||||
|
'approved_at' => now()->subHours(3),
|
||||||
|
'rejection_reason' => 'Stock tidak mencukupi untuk produk yang diminta',
|
||||||
|
'notes' => 'Mutasi test - status REJECTED'
|
||||||
|
]);
|
||||||
|
|
||||||
|
MutationDetail::create([
|
||||||
|
'mutation_id' => $mutation5->id,
|
||||||
|
'product_id' => $products[2]->id,
|
||||||
|
'quantity_requested' => 20.00,
|
||||||
|
'quantity_approved' => 0,
|
||||||
|
'notes' => 'Produk rejected'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->command->info('Test mutations created successfully!');
|
||||||
|
$this->command->info('- Mutation SENT: ' . $mutation1->mutation_number);
|
||||||
|
$this->command->info('- Mutation RECEIVED: ' . $mutation2->mutation_number);
|
||||||
|
$this->command->info('- Mutation APPROVED: ' . $mutation3->mutation_number);
|
||||||
|
$this->command->info('- Mutation COMPLETED: ' . $mutation4->mutation_number);
|
||||||
|
$this->command->info('- Mutation REJECTED: ' . $mutation5->mutation_number);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->command->error('Error creating test mutations: ' . $e->getMessage());
|
||||||
|
$this->command->error('Stack trace: ' . $e->getTraceAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
package-lock.json
generated
62
package-lock.json
generated
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "ckb",
|
"name": "html",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
@@ -12664,19 +12664,22 @@
|
|||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz",
|
||||||
"integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==",
|
"integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@webpack-cli/info": {
|
"@webpack-cli/info": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz",
|
||||||
"integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==",
|
"integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@webpack-cli/serve": {
|
"@webpack-cli/serve": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz",
|
||||||
"integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==",
|
"integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@xtuc/ieee754": {
|
"@xtuc/ieee754": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@@ -12761,7 +12764,8 @@
|
|||||||
"version": "3.5.2",
|
"version": "3.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"ansi-html-community": {
|
"ansi-html-community": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
@@ -13055,7 +13059,8 @@
|
|||||||
"version": "5.1.3",
|
"version": "5.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz",
|
||||||
"integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==",
|
"integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
@@ -14026,7 +14031,8 @@
|
|||||||
"version": "6.2.2",
|
"version": "6.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz",
|
||||||
"integrity": "sha512-Ufadglr88ZLsrvS11gjeu/40Lw74D9Am/Jpr3LlYm5Q4ZP5KdlUhG+6u2EjyXeZcxmZ2h1ebCKngDjolpeLHpg==",
|
"integrity": "sha512-Ufadglr88ZLsrvS11gjeu/40Lw74D9Am/Jpr3LlYm5Q4ZP5KdlUhG+6u2EjyXeZcxmZ2h1ebCKngDjolpeLHpg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"css-loader": {
|
"css-loader": {
|
||||||
"version": "5.2.7",
|
"version": "5.2.7",
|
||||||
@@ -14157,7 +14163,8 @@
|
|||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz",
|
||||||
"integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==",
|
"integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"csso": {
|
"csso": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
@@ -14469,7 +14476,8 @@
|
|||||||
"version": "8.17.1",
|
"version": "8.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -14490,7 +14498,8 @@
|
|||||||
"version": "8.17.1",
|
"version": "8.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -15337,7 +15346,8 @@
|
|||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
|
||||||
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
|
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"ieee754": {
|
"ieee754": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
@@ -15719,7 +15729,8 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
|
||||||
"integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
|
"integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@webpack-cli/info": {
|
"@webpack-cli/info": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
@@ -15734,7 +15745,8 @@
|
|||||||
"version": "1.7.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
|
||||||
"integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
|
"integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"interpret": {
|
"interpret": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
@@ -16617,25 +16629,29 @@
|
|||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz",
|
||||||
"integrity": "sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ==",
|
"integrity": "sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"postcss-discard-duplicates": {
|
"postcss-discard-duplicates": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz",
|
||||||
"integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==",
|
"integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"postcss-discard-empty": {
|
"postcss-discard-empty": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz",
|
||||||
"integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==",
|
"integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"postcss-discard-overridden": {
|
"postcss-discard-overridden": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz",
|
||||||
"integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==",
|
"integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"postcss-load-config": {
|
"postcss-load-config": {
|
||||||
"version": "3.1.4",
|
"version": "3.1.4",
|
||||||
@@ -16724,7 +16740,8 @@
|
|||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
|
||||||
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
|
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"postcss-modules-local-by-default": {
|
"postcss-modules-local-by-default": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
@@ -16759,7 +16776,8 @@
|
|||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz",
|
||||||
"integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==",
|
"integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"postcss-normalize-display-values": {
|
"postcss-normalize-display-values": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
@@ -17674,7 +17692,8 @@
|
|||||||
"version": "8.17.1",
|
"version": "8.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -18630,7 +18649,8 @@
|
|||||||
"version": "8.18.2",
|
"version": "8.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
|
||||||
"integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
|
"integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"xmlhttprequest-ssl": {
|
"xmlhttprequest-ssl": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
|
|||||||
32
public/js/warehouse_management/mutations/create.js
Normal file
32
public/js/warehouse_management/mutations/create.js
Normal file
File diff suppressed because one or more lines are too long
32
public/js/warehouse_management/mutations/index.js
Normal file
32
public/js/warehouse_management/mutations/index.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,5 +5,7 @@
|
|||||||
"/js/warehouse_management/opnames/index.js": "/js/warehouse_management/opnames/index.js",
|
"/js/warehouse_management/opnames/index.js": "/js/warehouse_management/opnames/index.js",
|
||||||
"/js/warehouse_management/opnames/create.js": "/js/warehouse_management/opnames/create.js",
|
"/js/warehouse_management/opnames/create.js": "/js/warehouse_management/opnames/create.js",
|
||||||
"/js/warehouse_management/opnames/detail.js": "/js/warehouse_management/opnames/detail.js",
|
"/js/warehouse_management/opnames/detail.js": "/js/warehouse_management/opnames/detail.js",
|
||||||
|
"/js/warehouse_management/mutations/index.js": "/js/warehouse_management/mutations/index.js",
|
||||||
|
"/js/warehouse_management/mutations/create.js": "/js/warehouse_management/mutations/create.js",
|
||||||
"/css/app.css": "/css/app.css"
|
"/css/app.css": "/css/app.css"
|
||||||
}
|
}
|
||||||
|
|||||||
262
resources/js/warehouse_management/mutations/create.js
Normal file
262
resources/js/warehouse_management/mutations/create.js
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
$(document).ready(function () {
|
||||||
|
let productIndex = 1;
|
||||||
|
|
||||||
|
// Initialize Select2
|
||||||
|
$(".select2").select2({
|
||||||
|
placeholder: "Pilih...",
|
||||||
|
allowClear: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Prevent same dealer selection
|
||||||
|
$("#from_dealer_id, #to_dealer_id").on("change", function () {
|
||||||
|
const fromDealerId = $("#from_dealer_id").val();
|
||||||
|
const toDealerId = $("#to_dealer_id").val();
|
||||||
|
|
||||||
|
if (fromDealerId && toDealerId && fromDealerId === toDealerId) {
|
||||||
|
$(this).val("").trigger("change");
|
||||||
|
alert("Dealer asal dan tujuan tidak boleh sama!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update available stock when dealer changes
|
||||||
|
updateAllAvailableStock();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add new product row
|
||||||
|
$("#add-product").on("click", function () {
|
||||||
|
const newRow = createProductRow(productIndex);
|
||||||
|
$("#products-tbody").append(newRow);
|
||||||
|
|
||||||
|
// Initialize Select2 for new row
|
||||||
|
const newSelect = $(
|
||||||
|
`#products-tbody tr[data-index="${productIndex}"] .product-select`
|
||||||
|
);
|
||||||
|
newSelect.select2({
|
||||||
|
placeholder: "Pilih Produk...",
|
||||||
|
allowClear: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
productIndex++;
|
||||||
|
updateRemoveButtons();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove product row
|
||||||
|
$(document).on("click", ".remove-product", function () {
|
||||||
|
$(this).closest("tr").remove();
|
||||||
|
updateRemoveButtons();
|
||||||
|
reindexRows();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle product selection change
|
||||||
|
$(document).on("change", ".product-select", function () {
|
||||||
|
const row = $(this).closest("tr");
|
||||||
|
const productId = $(this).val();
|
||||||
|
const fromDealerId = $("#from_dealer_id").val();
|
||||||
|
|
||||||
|
if (productId && fromDealerId) {
|
||||||
|
getAvailableStock(productId, fromDealerId, row);
|
||||||
|
} else {
|
||||||
|
row.find(".available-stock").text("-");
|
||||||
|
row.find(".quantity-input").attr("max", "");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Validate quantity input
|
||||||
|
$(document).on("input", ".quantity-input", function () {
|
||||||
|
const maxValue = parseFloat($(this).attr("max"));
|
||||||
|
const currentValue = parseFloat($(this).val());
|
||||||
|
|
||||||
|
if (maxValue && currentValue > maxValue) {
|
||||||
|
$(this).val(maxValue);
|
||||||
|
$(this).addClass("is-invalid");
|
||||||
|
|
||||||
|
if (!$(this).siblings(".invalid-feedback").length) {
|
||||||
|
$(this).after(
|
||||||
|
'<div class="invalid-feedback">Quantity melebihi stock yang tersedia</div>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$(this).removeClass("is-invalid");
|
||||||
|
$(this).siblings(".invalid-feedback").remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Form submission
|
||||||
|
$("#mutation-form").on("submit", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!validateForm()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitBtn = $("#submit-btn");
|
||||||
|
const originalText = submitBtn.html();
|
||||||
|
|
||||||
|
submitBtn
|
||||||
|
.prop("disabled", true)
|
||||||
|
.html('<i class="la la-spinner la-spin"></i> Menyimpan...');
|
||||||
|
|
||||||
|
// Submit form
|
||||||
|
this.submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
function createProductRow(index) {
|
||||||
|
// Get product options from the existing select
|
||||||
|
const existingSelect = $(".product-select").first();
|
||||||
|
const productOptions = existingSelect.html();
|
||||||
|
|
||||||
|
return `
|
||||||
|
<tr class="product-row" data-index="${index}">
|
||||||
|
<td>
|
||||||
|
<select name="products[${index}][product_id]" class="form-control select2 product-select" required>
|
||||||
|
${productOptions}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="available-stock text-muted">-</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="number"
|
||||||
|
name="products[${index}][quantity_requested]"
|
||||||
|
class="form-control quantity-input"
|
||||||
|
min="0.01"
|
||||||
|
step="0.01"
|
||||||
|
placeholder="0"
|
||||||
|
required>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text"
|
||||||
|
name="products[${index}][notes]"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Catatan produk (opsional)">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm remove-product">
|
||||||
|
<i class="la la-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRemoveButtons() {
|
||||||
|
const rows = $(".product-row");
|
||||||
|
$(".remove-product").prop("disabled", rows.length <= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reindexRows() {
|
||||||
|
$(".product-row").each(function (index) {
|
||||||
|
$(this).attr("data-index", index);
|
||||||
|
$(this)
|
||||||
|
.find('select[name*="product_id"]')
|
||||||
|
.attr("name", `products[${index}][product_id]`);
|
||||||
|
$(this)
|
||||||
|
.find('input[name*="quantity_requested"]')
|
||||||
|
.attr("name", `products[${index}][quantity_requested]`);
|
||||||
|
$(this)
|
||||||
|
.find('input[name*="notes"]')
|
||||||
|
.attr("name", `products[${index}][notes]`);
|
||||||
|
});
|
||||||
|
productIndex = $(".product-row").length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAvailableStock(productId, dealerId, row) {
|
||||||
|
$.ajax({
|
||||||
|
url: "/warehouse/mutations/get-product-stock",
|
||||||
|
method: "GET",
|
||||||
|
data: {
|
||||||
|
product_id: productId,
|
||||||
|
dealer_id: dealerId,
|
||||||
|
},
|
||||||
|
beforeSend: function () {
|
||||||
|
row.find(".available-stock").html(
|
||||||
|
'<i class="la la-spinner la-spin"></i>'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
success: function (response) {
|
||||||
|
const stock = parseFloat(response.current_stock);
|
||||||
|
row.find(".available-stock").text(stock.toLocaleString());
|
||||||
|
row.find(".quantity-input").attr("max", stock);
|
||||||
|
|
||||||
|
// Set max value message
|
||||||
|
if (stock <= 0) {
|
||||||
|
row.find(".available-stock")
|
||||||
|
.addClass("text-danger")
|
||||||
|
.removeClass("text-muted");
|
||||||
|
row.find(".quantity-input").attr("readonly", true).val("");
|
||||||
|
} else {
|
||||||
|
row.find(".available-stock")
|
||||||
|
.removeClass("text-danger")
|
||||||
|
.addClass("text-muted");
|
||||||
|
row.find(".quantity-input").attr("readonly", false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
row.find(".available-stock")
|
||||||
|
.text("Error")
|
||||||
|
.addClass("text-danger");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAllAvailableStock() {
|
||||||
|
const fromDealerId = $("#from_dealer_id").val();
|
||||||
|
|
||||||
|
$(".product-row").each(function () {
|
||||||
|
const row = $(this);
|
||||||
|
const productId = row.find(".product-select").val();
|
||||||
|
|
||||||
|
if (productId && fromDealerId) {
|
||||||
|
getAvailableStock(productId, fromDealerId, row);
|
||||||
|
} else {
|
||||||
|
row.find(".available-stock").text("-");
|
||||||
|
row.find(".quantity-input").attr("max", "");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateForm() {
|
||||||
|
let isValid = true;
|
||||||
|
const fromDealerId = $("#from_dealer_id").val();
|
||||||
|
const toDealerId = $("#to_dealer_id").val();
|
||||||
|
|
||||||
|
// Check dealers
|
||||||
|
if (!fromDealerId) {
|
||||||
|
alert("Pilih dealer asal");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!toDealerId) {
|
||||||
|
alert("Pilih dealer tujuan");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromDealerId === toDealerId) {
|
||||||
|
alert("Dealer asal dan tujuan tidak boleh sama");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check products
|
||||||
|
const productRows = $(".product-row");
|
||||||
|
if (productRows.length === 0) {
|
||||||
|
alert("Tambahkan minimal satu produk");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasValidProduct = false;
|
||||||
|
productRows.each(function () {
|
||||||
|
const productId = $(this).find(".product-select").val();
|
||||||
|
const quantity = $(this).find(".quantity-input").val();
|
||||||
|
|
||||||
|
if (productId && quantity && parseFloat(quantity) > 0) {
|
||||||
|
hasValidProduct = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasValidProduct) {
|
||||||
|
alert("Pilih minimal satu produk dengan quantity yang valid");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
});
|
||||||
261
resources/js/warehouse_management/mutations/index.js
Normal file
261
resources/js/warehouse_management/mutations/index.js
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
$(document).ready(function () {
|
||||||
|
// Initialize DataTable
|
||||||
|
var table = $("#mutations-table").DataTable({
|
||||||
|
processing: true,
|
||||||
|
serverSide: true,
|
||||||
|
ajax: {
|
||||||
|
url: $("#mutations-table").data("url"),
|
||||||
|
type: "GET",
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
data: "DT_RowIndex",
|
||||||
|
name: "DT_RowIndex",
|
||||||
|
orderable: false,
|
||||||
|
searchable: false,
|
||||||
|
width: "5%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "mutation_number",
|
||||||
|
name: "mutation_number",
|
||||||
|
width: "12%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "created_at",
|
||||||
|
name: "created_at",
|
||||||
|
width: "12%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "from_dealer",
|
||||||
|
name: "fromDealer.name",
|
||||||
|
width: "15%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "to_dealer",
|
||||||
|
name: "toDealer.name",
|
||||||
|
width: "15%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "requested_by",
|
||||||
|
name: "requestedBy.name",
|
||||||
|
width: "12%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "total_items",
|
||||||
|
name: "total_items",
|
||||||
|
width: "8%",
|
||||||
|
className: "text-center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "status",
|
||||||
|
name: "status",
|
||||||
|
width: "12%",
|
||||||
|
className: "text-center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "action",
|
||||||
|
name: "action",
|
||||||
|
orderable: false,
|
||||||
|
searchable: false,
|
||||||
|
width: "15%",
|
||||||
|
className: "text-center",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
order: [[2, "desc"]], // Order by created_at desc
|
||||||
|
pageLength: 10,
|
||||||
|
responsive: true,
|
||||||
|
language: {
|
||||||
|
processing: "Memuat data...",
|
||||||
|
lengthMenu: "Tampilkan _MENU_ data per halaman",
|
||||||
|
zeroRecords: "Data tidak ditemukan",
|
||||||
|
info: "Menampilkan _START_ sampai _END_ dari _TOTAL_ data",
|
||||||
|
infoEmpty: "Menampilkan 0 sampai 0 dari 0 data",
|
||||||
|
infoFiltered: "(difilter dari _MAX_ total data)",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle Receive Button Click
|
||||||
|
$(document).on("click", ".btn-receive", function () {
|
||||||
|
var mutationId = $(this).data("id");
|
||||||
|
$("#receiveModal" + mutationId).modal("show");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle Approve Button Click
|
||||||
|
$(document).on("click", ".btn-approve", function () {
|
||||||
|
var mutationId = $(this).data("id");
|
||||||
|
|
||||||
|
// Load mutation details via AJAX
|
||||||
|
$.ajax({
|
||||||
|
url: "/warehouse/mutations/" + mutationId + "/details",
|
||||||
|
type: "GET",
|
||||||
|
beforeSend: function () {
|
||||||
|
$("#mutation-details" + mutationId).html(
|
||||||
|
'<div class="text-center">' +
|
||||||
|
'<div class="spinner-border" role="status">' +
|
||||||
|
'<span class="sr-only">Loading...</span>' +
|
||||||
|
"</div>" +
|
||||||
|
"<p>Memuat detail produk...</p>" +
|
||||||
|
"</div>"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
success: function (response) {
|
||||||
|
var detailsHtml = "<h6>Detail Produk:</h6>";
|
||||||
|
detailsHtml += '<div class="table-responsive">';
|
||||||
|
detailsHtml += '<table class="table table-sm">';
|
||||||
|
detailsHtml += "<thead>";
|
||||||
|
detailsHtml += "<tr>";
|
||||||
|
detailsHtml += "<th>Produk</th>";
|
||||||
|
detailsHtml += "<th>Diminta</th>";
|
||||||
|
detailsHtml += "<th>Disetujui</th>";
|
||||||
|
detailsHtml += "<th>Stock Tersedia</th>";
|
||||||
|
detailsHtml += "</tr>";
|
||||||
|
detailsHtml += "</thead>";
|
||||||
|
detailsHtml += "<tbody>";
|
||||||
|
|
||||||
|
response.details.forEach(function (detail, index) {
|
||||||
|
detailsHtml += "<tr>";
|
||||||
|
detailsHtml += "<td>" + detail.product.name + "</td>";
|
||||||
|
detailsHtml +=
|
||||||
|
"<td>" +
|
||||||
|
parseFloat(detail.quantity_requested).toLocaleString() +
|
||||||
|
"</td>";
|
||||||
|
detailsHtml += "<td>";
|
||||||
|
detailsHtml +=
|
||||||
|
'<input type="number" name="details[' +
|
||||||
|
detail.id +
|
||||||
|
'][quantity_approved]" ';
|
||||||
|
detailsHtml += 'class="form-control form-control-sm" ';
|
||||||
|
detailsHtml += 'value="' + detail.quantity_requested + '" ';
|
||||||
|
detailsHtml +=
|
||||||
|
'min="0" max="' +
|
||||||
|
Math.min(
|
||||||
|
detail.quantity_requested,
|
||||||
|
detail.available_stock
|
||||||
|
) +
|
||||||
|
'" ';
|
||||||
|
detailsHtml += 'step="0.01" required>';
|
||||||
|
detailsHtml += "</td>";
|
||||||
|
detailsHtml +=
|
||||||
|
"<td>" +
|
||||||
|
parseFloat(detail.available_stock).toLocaleString() +
|
||||||
|
"</td>";
|
||||||
|
detailsHtml += "</tr>";
|
||||||
|
});
|
||||||
|
|
||||||
|
detailsHtml += "</tbody>";
|
||||||
|
detailsHtml += "</table>";
|
||||||
|
detailsHtml += "</div>";
|
||||||
|
|
||||||
|
$("#mutation-details" + mutationId).html(detailsHtml);
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
$("#mutation-details" + mutationId).html(
|
||||||
|
'<div class="alert alert-danger">Gagal memuat detail produk</div>'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#approveModal" + mutationId).modal("show");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle other button clicks
|
||||||
|
$(document).on("click", ".btn-reject", function () {
|
||||||
|
var mutationId = $(this).data("id");
|
||||||
|
$("#rejectModal" + mutationId).modal("show");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on("click", ".btn-complete", function () {
|
||||||
|
var mutationId = $(this).data("id");
|
||||||
|
$("#completeModal" + mutationId).modal("show");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle Cancel Button Click with SweetAlert
|
||||||
|
$(document).on("click", ".btn-cancel", function () {
|
||||||
|
var mutationId = $(this).data("id");
|
||||||
|
|
||||||
|
if (typeof Swal !== "undefined") {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Batalkan Mutasi?",
|
||||||
|
text: "Apakah Anda yakin ingin membatalkan mutasi ini?",
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: "#d33",
|
||||||
|
cancelButtonColor: "#3085d6",
|
||||||
|
confirmButtonText: "Ya, Batalkan",
|
||||||
|
cancelButtonText: "Batal",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
cancelMutation(mutationId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (confirm("Apakah Anda yakin ingin membatalkan mutasi ini?")) {
|
||||||
|
cancelMutation(mutationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function cancelMutation(mutationId) {
|
||||||
|
$.ajax({
|
||||||
|
url: "/warehouse/mutations/" + mutationId + "/cancel",
|
||||||
|
type: "POST",
|
||||||
|
data: {
|
||||||
|
_token: $('meta[name="csrf-token"]').attr("content"),
|
||||||
|
},
|
||||||
|
success: function (response) {
|
||||||
|
if (typeof Swal !== "undefined") {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Berhasil!",
|
||||||
|
text: "Mutasi berhasil dibatalkan",
|
||||||
|
icon: "success",
|
||||||
|
timer: 2000,
|
||||||
|
showConfirmButton: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
alert("Mutasi berhasil dibatalkan");
|
||||||
|
}
|
||||||
|
table.ajax.reload();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
var errorMsg =
|
||||||
|
xhr.responseJSON?.message || "Gagal membatalkan mutasi";
|
||||||
|
if (typeof Swal !== "undefined") {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Error!",
|
||||||
|
text: errorMsg,
|
||||||
|
icon: "error",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
alert("Error: " + errorMsg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle form submissions with loading state
|
||||||
|
$(document).on("submit", ".approve-form", function () {
|
||||||
|
$(this)
|
||||||
|
.find('button[type="submit"]')
|
||||||
|
.prop("disabled", true)
|
||||||
|
.html("Memproses...");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Auto-calculate approved quantity based on available stock
|
||||||
|
$(document).on("input", 'input[name*="quantity_approved"]', function () {
|
||||||
|
var maxValue = parseFloat($(this).attr("max"));
|
||||||
|
var currentValue = parseFloat($(this).val());
|
||||||
|
|
||||||
|
if (maxValue && currentValue > maxValue) {
|
||||||
|
$(this).val(maxValue);
|
||||||
|
$(this).addClass("is-invalid");
|
||||||
|
if (!$(this).siblings(".invalid-feedback").length) {
|
||||||
|
$(this).after(
|
||||||
|
'<div class="invalid-feedback">Jumlah melebihi stock yang tersedia</div>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$(this).removeClass("is-invalid");
|
||||||
|
$(this).siblings(".invalid-feedback").remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -215,9 +215,9 @@
|
|||||||
</li>
|
</li>
|
||||||
@endcan
|
@endcan
|
||||||
|
|
||||||
@can('view', $menus['opnames.index'])
|
@can('view', $menus['mutations.index'])
|
||||||
<li class="kt-menu__item" aria-haspopup="true">
|
<li class="kt-menu__item" aria-haspopup="true">
|
||||||
<a href="{{ route('opnames.index') }}" class="kt-menu__link">
|
<a href="{{ route('mutations.index') }}" class="kt-menu__link">
|
||||||
<i class="fa fa-list" style="display: flex; align-items: center; margin-right: 10px;"></i>
|
<i class="fa fa-list" style="display: flex; align-items: center; margin-right: 10px;"></i>
|
||||||
<span class="kt-menu__link-text">Mutasi Produk</span>
|
<span class="kt-menu__link-text">Mutasi Produk</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
214
resources/views/warehouse_management/mutations/_action.blade.php
Normal file
214
resources/views/warehouse_management/mutations/_action.blade.php
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
<!-- View Button -->
|
||||||
|
<a href="{{ route('mutations.show', $row->id) }}"
|
||||||
|
class="btn btn-sm btn-clean btn-icon btn-icon-md"
|
||||||
|
title="Lihat Detail">
|
||||||
|
<i class="la la-eye"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
@if($row->status->value === 'sent')
|
||||||
|
<!-- Receive Button (untuk dealer tujuan) -->
|
||||||
|
@if(auth()->user()->dealer_id == $row->to_dealer_id)
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-receive"
|
||||||
|
data-id="{{ $row->id }}"
|
||||||
|
title="Terima Mutasi">
|
||||||
|
<i class="la la-download text-primary"></i>
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Cancel Button (untuk pengirim) -->
|
||||||
|
@if(auth()->user()->dealer_id == $row->from_dealer_id || auth()->user()->hasRole('admin'))
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-cancel"
|
||||||
|
data-id="{{ $row->id }}"
|
||||||
|
title="Batalkan Mutasi">
|
||||||
|
<i class="la la-ban text-warning"></i>
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($row->status->value === 'received')
|
||||||
|
<!-- Approve Button (untuk pengirim atau admin) -->
|
||||||
|
@if(auth()->user()->dealer_id == $row->from_dealer_id || auth()->user()->hasRole('admin'))
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-approve"
|
||||||
|
data-id="{{ $row->id }}"
|
||||||
|
title="Setujui Mutasi">
|
||||||
|
<i class="la la-check text-success"></i>
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Reject Button (untuk pengirim atau admin) -->
|
||||||
|
@if(auth()->user()->dealer_id == $row->from_dealer_id || auth()->user()->hasRole('admin'))
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-reject"
|
||||||
|
data-id="{{ $row->id }}"
|
||||||
|
title="Tolak Mutasi">
|
||||||
|
<i class="la la-times text-danger"></i>
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($row->status->value === 'approved')
|
||||||
|
<!-- Complete/Receive Button -->
|
||||||
|
@can('complete-mutation')
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-complete"
|
||||||
|
data-id="{{ $row->id }}"
|
||||||
|
title="Terima & Selesaikan Mutasi">
|
||||||
|
<i class="la la-check-circle text-primary"></i>
|
||||||
|
</button>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
<!-- Cancel Button -->
|
||||||
|
@can('edit-mutation')
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-cancel"
|
||||||
|
data-id="{{ $row->id }}"
|
||||||
|
title="Batalkan Mutasi">
|
||||||
|
<i class="la la-ban text-warning"></i>
|
||||||
|
</button>
|
||||||
|
@endcan
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(in_array($row->status->value, ['pending', 'approved']) && auth()->user()->id === $row->requested_by)
|
||||||
|
<!-- Edit Button (only for creator and if still pending/approved) -->
|
||||||
|
<a href="{{ route('mutations.edit', $row->id) }}"
|
||||||
|
class="btn btn-sm btn-clean btn-icon btn-icon-md"
|
||||||
|
title="Edit Mutasi">
|
||||||
|
<i class="la la-edit text-info"></i>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($row->status->value === 'completed')
|
||||||
|
<!-- Print Button -->
|
||||||
|
<a href="{{ route('mutations.print', $row->id) }}"
|
||||||
|
class="btn btn-sm btn-clean btn-icon btn-icon-md"
|
||||||
|
target="_blank"
|
||||||
|
title="Cetak Laporan">
|
||||||
|
<i class="la la-print text-info"></i>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal untuk Approve -->
|
||||||
|
<div class="modal fade" id="approveModal{{ $row->id }}" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Setujui Mutasi</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('mutations.approve', $row->id) }}" method="POST" class="approve-form">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Catatan Persetujuan</label>
|
||||||
|
<textarea name="notes" class="form-control" rows="3" placeholder="Opsional: tambahkan catatan..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Detail produk akan dimuat via AJAX -->
|
||||||
|
<div id="mutation-details{{ $row->id }}">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="spinner-border" role="status">
|
||||||
|
<span class="sr-only">Loading...</span>
|
||||||
|
</div>
|
||||||
|
<p>Memuat detail produk...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-success">Setujui Mutasi</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal untuk Reject -->
|
||||||
|
<div class="modal fade" id="rejectModal{{ $row->id }}" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Tolak Mutasi</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('mutations.reject', $row->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<strong>Peringatan!</strong> Mutasi yang ditolak tidak dapat diubah lagi.
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Alasan Penolakan <span class="text-danger">*</span></label>
|
||||||
|
<textarea name="rejection_reason" class="form-control" rows="3" required placeholder="Masukkan alasan penolakan..."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-danger">Tolak Mutasi</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal untuk Receive -->
|
||||||
|
<div class="modal fade" id="receiveModal{{ $row->id }}" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Terima Mutasi</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('mutations.receive', $row->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<strong>Konfirmasi!</strong> Anda akan menerima mutasi dari <strong>{{ $row->fromDealer->name }}</strong>.
|
||||||
|
</div>
|
||||||
|
<p>Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Ya, Terima</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal untuk Complete -->
|
||||||
|
<div class="modal fade" id="completeModal{{ $row->id }}" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Selesaikan Mutasi</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('mutations.complete', $row->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<strong>Konfirmasi!</strong> Stock akan dipindahkan dari <strong>{{ $row->fromDealer->name }}</strong> ke <strong>{{ $row->toDealer->name }}</strong>.
|
||||||
|
</div>
|
||||||
|
<p>Apakah Anda yakin ingin menyelesaikan mutasi ini? Tindakan ini tidak dapat dibatalkan.</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Ya, Selesaikan</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
159
resources/views/warehouse_management/mutations/create.blade.php
Normal file
159
resources/views/warehouse_management/mutations/create.blade.php
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
@extends('layouts.backapp')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="kt-portlet">
|
||||||
|
<div class="kt-portlet__head">
|
||||||
|
<div class="kt-portlet__head-label">
|
||||||
|
<h3 class="kt-portlet__head-title">
|
||||||
|
Tambah Mutasi Baru
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="kt-portlet__head-toolbar">
|
||||||
|
<div class="kt-portlet__head-wrapper">
|
||||||
|
<div class="kt-portlet__head-actions">
|
||||||
|
<a href="{{ route('mutations.index') }}" class="btn btn-clean btn-sm">
|
||||||
|
<i class="la la-arrow-left"></i>
|
||||||
|
Kembali
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ route('mutations.store') }}" method="POST" id="mutation-form">
|
||||||
|
@csrf
|
||||||
|
<div class="kt-portlet__body">
|
||||||
|
@if ($errors->any())
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<ul class="mb-0">
|
||||||
|
@foreach ($errors->all() as $error)
|
||||||
|
<li>{{ $error }}</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="from_dealer_id">Dealer Asal <span class="text-danger">*</span></label>
|
||||||
|
<select name="from_dealer_id" id="from_dealer_id" class="form-control select2" required>
|
||||||
|
<option value="">Pilih Dealer Asal</option>
|
||||||
|
@foreach($dealers as $dealer)
|
||||||
|
<option value="{{ $dealer->id }}" {{ old('from_dealer_id') == $dealer->id ? 'selected' : '' }}>
|
||||||
|
{{ $dealer->name }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="to_dealer_id">Dealer Tujuan <span class="text-danger">*</span></label>
|
||||||
|
<select name="to_dealer_id" id="to_dealer_id" class="form-control select2" required>
|
||||||
|
<option value="">Pilih Dealer Tujuan</option>
|
||||||
|
@foreach($dealers as $dealer)
|
||||||
|
<option value="{{ $dealer->id }}" {{ old('to_dealer_id') == $dealer->id ? 'selected' : '' }}>
|
||||||
|
{{ $dealer->name }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="notes">Catatan</label>
|
||||||
|
<textarea name="notes" id="notes" class="form-control" rows="3" placeholder="Catatan untuk mutasi ini (opsional)">{{ old('notes') }}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="kt-separator kt-separator--border-dashed kt-separator--space-lg"></div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<label class="form-label mb-0">Detail Produk <span class="text-danger">*</span></label>
|
||||||
|
<button type="button" class="btn btn-success btn-sm" id="add-product">
|
||||||
|
<i class="la la-plus"></i> Tambah Produk
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered" id="products-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="35%">Produk</th>
|
||||||
|
<th width="15%">Stock Tersedia</th>
|
||||||
|
<th width="15%">Quantity</th>
|
||||||
|
<th width="25%">Catatan</th>
|
||||||
|
<th width="10%">Aksi</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="products-tbody">
|
||||||
|
<tr class="product-row" data-index="0">
|
||||||
|
<td>
|
||||||
|
<select name="products[0][product_id]" class="form-control select2 product-select" required>
|
||||||
|
<option value="">Pilih Produk</option>
|
||||||
|
@foreach($products as $product)
|
||||||
|
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="available-stock text-muted">-</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="number"
|
||||||
|
name="products[0][quantity_requested]"
|
||||||
|
class="form-control quantity-input"
|
||||||
|
min="0.01"
|
||||||
|
step="0.01"
|
||||||
|
placeholder="0"
|
||||||
|
required>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text"
|
||||||
|
name="products[0][notes]"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Catatan produk (opsional)">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm remove-product" disabled>
|
||||||
|
<i class="la la-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<i class="la la-info-circle"></i>
|
||||||
|
<strong>Informasi:</strong>
|
||||||
|
Mutasi akan dibuat dengan status "Menunggu Persetujuan" dan memerlukan approval sebelum stock dipindahkan.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="kt-portlet__foot">
|
||||||
|
<div class="kt-form__actions kt-form__actions--right">
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="window.history.back()">
|
||||||
|
Batal
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-primary" id="submit-btn">
|
||||||
|
<i class="la la-save"></i>
|
||||||
|
Simpan Mutasi
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('javascripts')
|
||||||
|
<script src="{{ mix('js/warehouse_management/mutations/create.js') }}"></script>
|
||||||
|
@endsection
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
@extends('layouts.backapp')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="kt-portlet kt-portlet--mobile" id="kt_blockui_datatable">
|
||||||
|
<div class="kt-portlet__head kt-portlet__head--lg">
|
||||||
|
<div class="kt-portlet__head-label">
|
||||||
|
<span class="kt-portlet__head-icon">
|
||||||
|
<i class="kt-font-brand flaticon2-list-1"></i>
|
||||||
|
</span>
|
||||||
|
<h3 class="kt-portlet__head-title">
|
||||||
|
Tabel Mutasi
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="kt-portlet__head-toolbar">
|
||||||
|
<div class="kt-portlet__head-wrapper">
|
||||||
|
<div class="kt-portlet__head-actions">
|
||||||
|
<a href="{{ route('mutations.create') }}" class="btn btn-bold btn-label-brand btn--sm">
|
||||||
|
<i class="la la-plus"></i>
|
||||||
|
Tambah Mutasi
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="kt-portlet__body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<!--begin: Datatable -->
|
||||||
|
<table class="table table-striped table-bordered table-hover" id="mutations-table" data-url="{{ route('mutations.index') }}">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>No.</th>
|
||||||
|
<th>No. Mutasi</th>
|
||||||
|
<th>Tanggal</th>
|
||||||
|
<th>Dari Dealer</th>
|
||||||
|
<th>Ke Dealer</th>
|
||||||
|
<th>Dibuat Oleh</th>
|
||||||
|
<th>Total Item</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Aksi</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
<!--end: Datatable -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('javascripts')
|
||||||
|
<script src="{{ mix('js/warehouse_management/mutations/index.js') }}"></script>
|
||||||
|
@endsection
|
||||||
457
resources/views/warehouse_management/mutations/show.blade.php
Normal file
457
resources/views/warehouse_management/mutations/show.blade.php
Normal file
@@ -0,0 +1,457 @@
|
|||||||
|
@extends('layouts.backapp')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<!-- Mutation Header -->
|
||||||
|
<div class="kt-portlet">
|
||||||
|
<div class="kt-portlet__head">
|
||||||
|
<div class="kt-portlet__head-label">
|
||||||
|
<h3 class="kt-portlet__head-title">
|
||||||
|
Detail Mutasi - {{ $mutation->mutation_number }}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="kt-portlet__head-toolbar">
|
||||||
|
<div class="kt-portlet__head-wrapper">
|
||||||
|
<div class="kt-portlet__head-actions">
|
||||||
|
<a href="{{ route('mutations.index') }}" class="btn btn-secondary btn-sm">
|
||||||
|
<i class="la la-arrow-left"></i>
|
||||||
|
Kembali
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="kt-portlet__body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>No. Mutasi:</strong></label>
|
||||||
|
<p>{{ $mutation->mutation_number }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Dari Dealer:</strong></label>
|
||||||
|
<p>{{ $mutation->fromDealer->name }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Ke Dealer:</strong></label>
|
||||||
|
<p>{{ $mutation->toDealer->name }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Status:</strong></label>
|
||||||
|
<p>
|
||||||
|
<span class="kt-badge kt-badge--{{ $mutation->status_color }} kt-badge--dot"></span>
|
||||||
|
<span class="kt-font-bold kt-font-{{ $mutation->status_color }}">{{ $mutation->status_label }}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Dibuat Oleh:</strong></label>
|
||||||
|
<p>{{ $mutation->requestedBy->name }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Tanggal Dibuat:</strong></label>
|
||||||
|
<p>{{ $mutation->created_at->format('d/m/Y H:i:s') }}</p>
|
||||||
|
</div>
|
||||||
|
@if($mutation->receivedBy)
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Diterima Oleh:</strong></label>
|
||||||
|
<p>{{ $mutation->receivedBy->name }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Tanggal Diterima:</strong></label>
|
||||||
|
<p>{{ $mutation->received_at->format('d/m/Y H:i:s') }}</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if($mutation->approvedBy)
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Disetujui Oleh:</strong></label>
|
||||||
|
<p>{{ $mutation->approvedBy->name }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Tanggal Disetujui:</strong></label>
|
||||||
|
<p>{{ $mutation->approved_at->format('d/m/Y H:i:s') }}</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if($mutation->notes)
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Catatan:</strong></label>
|
||||||
|
<p>{{ $mutation->notes }}</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if($mutation->rejection_reason)
|
||||||
|
<div class="form-group">
|
||||||
|
<label><strong>Alasan Penolakan:</strong></label>
|
||||||
|
<div class="alert alert-danger">{{ $mutation->rejection_reason }}</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mutation Details -->
|
||||||
|
<div class="kt-portlet">
|
||||||
|
<div class="kt-portlet__head">
|
||||||
|
<div class="kt-portlet__head-label">
|
||||||
|
<h3 class="kt-portlet__head-title">
|
||||||
|
Detail Produk
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="kt-portlet__body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>No.</th>
|
||||||
|
<th>Nama Produk</th>
|
||||||
|
<th>Jumlah Diminta</th>
|
||||||
|
<th>Jumlah Disetujui</th>
|
||||||
|
<th>Status Approval</th>
|
||||||
|
<th>Catatan</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($mutation->mutationDetails as $index => $detail)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $index + 1 }}</td>
|
||||||
|
<td>{{ $detail->product->name }}</td>
|
||||||
|
<td>{{ number_format($detail->quantity_requested, 2) }}</td>
|
||||||
|
<td>
|
||||||
|
@if($mutation->status->value === 'received' || $mutation->status->value === 'approved' || $mutation->status->value === 'completed')
|
||||||
|
{{ number_format($detail->quantity_approved ?? 0, 2) }}
|
||||||
|
@else
|
||||||
|
<span class="text-muted">Belum ditentukan</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@if($mutation->status->value === 'received' || $mutation->status->value === 'approved' || $mutation->status->value === 'completed')
|
||||||
|
<span class="kt-badge kt-badge--{{ $detail->approval_status_color }} kt-badge--pill">
|
||||||
|
{{ $detail->approval_status }}
|
||||||
|
</span>
|
||||||
|
@else
|
||||||
|
<span class="kt-badge kt-badge--secondary kt-badge--pill">Menunggu</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td>{{ $detail->notes ?? '-' }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr class="kt-font-bold">
|
||||||
|
<td colspan="2">Total</td>
|
||||||
|
<td>{{ number_format($mutation->mutationDetails->sum('quantity_requested'), 2) }}</td>
|
||||||
|
<td>
|
||||||
|
@if($mutation->status->value === 'received' || $mutation->status->value === 'approved' || $mutation->status->value === 'completed')
|
||||||
|
{{ number_format($mutation->mutationDetails->sum('quantity_approved'), 2) }}
|
||||||
|
@else
|
||||||
|
<span class="text-muted">-</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td colspan="2"></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="kt-portlet">
|
||||||
|
<div class="kt-portlet__body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
@if($mutation->status->value === 'sent' && auth()->user()->dealer_id == $mutation->to_dealer_id)
|
||||||
|
<!-- Receive Button for destination dealer -->
|
||||||
|
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#receiveModal">
|
||||||
|
<i class="la la-download"></i>
|
||||||
|
Terima Mutasi
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($mutation->status->value === 'received' && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin')))
|
||||||
|
<!-- Approve Button for sender or admin -->
|
||||||
|
<button type="button" class="btn btn-success btn-approve" data-id="{{ $mutation->id }}">
|
||||||
|
<i class="la la-check"></i>
|
||||||
|
Setujui Mutasi
|
||||||
|
</button>
|
||||||
|
<!-- Reject Button for sender or admin -->
|
||||||
|
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#rejectModal">
|
||||||
|
<i class="la la-times"></i>
|
||||||
|
Tolak Mutasi
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($mutation->status->value === 'approved')
|
||||||
|
<!-- Complete Button -->
|
||||||
|
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#completeModal">
|
||||||
|
<i class="la la-check-circle"></i>
|
||||||
|
Selesaikan Mutasi
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($mutation->canBeCancelled() && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin')))
|
||||||
|
<!-- Cancel Button -->
|
||||||
|
<button type="button" class="btn btn-warning" data-toggle="modal" data-target="#cancelModal">
|
||||||
|
<i class="la la-ban"></i>
|
||||||
|
Batalkan Mutasi
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($mutation->status->value === 'completed')
|
||||||
|
<!-- Print Button -->
|
||||||
|
<a href="{{ route('mutations.print', $mutation->id) }}" class="btn btn-info" target="_blank">
|
||||||
|
<i class="la la-print"></i>
|
||||||
|
Cetak Laporan
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modals -->
|
||||||
|
@if($mutation->status->value === 'sent' && auth()->user()->dealer_id == $mutation->to_dealer_id)
|
||||||
|
<!-- Receive Modal -->
|
||||||
|
<div class="modal fade" id="receiveModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Terima Mutasi</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('mutations.receive', $mutation->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<strong>Konfirmasi!</strong> Anda akan menerima mutasi dari <strong>{{ $mutation->fromDealer->name }}</strong>.
|
||||||
|
</div>
|
||||||
|
<p>Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Ya, Terima</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($mutation->status->value === 'received' && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin')))
|
||||||
|
<!-- Approve Modal -->
|
||||||
|
<div class="modal fade" id="approveModal{{ $mutation->id }}" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Setujui Mutasi</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('mutations.approve', $mutation->id) }}" method="POST" class="approve-form">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Catatan Persetujuan</label>
|
||||||
|
<textarea name="notes" class="form-control" rows="3" placeholder="Opsional: tambahkan catatan..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Detail produk akan dimuat via AJAX -->
|
||||||
|
<div id="mutation-details{{ $mutation->id }}">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="spinner-border" role="status">
|
||||||
|
<span class="sr-only">Loading...</span>
|
||||||
|
</div>
|
||||||
|
<p>Memuat detail produk...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-success">Setujui Mutasi</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Reject Modal -->
|
||||||
|
<div class="modal fade" id="rejectModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Tolak Mutasi</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('mutations.reject', $mutation->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<strong>Peringatan!</strong> Mutasi yang ditolak tidak dapat diubah lagi.
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Alasan Penolakan <span class="text-danger">*</span></label>
|
||||||
|
<textarea name="rejection_reason" class="form-control" rows="3" required placeholder="Masukkan alasan penolakan..."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-danger">Tolak Mutasi</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($mutation->status->value === 'approved')
|
||||||
|
<!-- Complete Modal -->
|
||||||
|
<div class="modal fade" id="completeModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Selesaikan Mutasi</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('mutations.complete', $mutation->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<strong>Konfirmasi!</strong> Stock akan dipindahkan dari <strong>{{ $mutation->fromDealer->name }}</strong> ke <strong>{{ $mutation->toDealer->name }}</strong>.
|
||||||
|
</div>
|
||||||
|
<p>Apakah Anda yakin ingin menyelesaikan mutasi ini? Tindakan ini tidak dapat dibatalkan.</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Ya, Selesaikan</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($mutation->canBeCancelled() && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin')))
|
||||||
|
<!-- Cancel Modal -->
|
||||||
|
<div class="modal fade" id="cancelModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Batalkan Mutasi</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('mutations.cancel', $mutation->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<strong>Peringatan!</strong> Mutasi yang dibatalkan tidak dapat diubah lagi.
|
||||||
|
</div>
|
||||||
|
<p>Apakah Anda yakin ingin membatalkan mutasi ini?</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-warning">Ya, Batalkan</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('javascripts')
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
// Handle Approve Button Click
|
||||||
|
$(document).on('click', '.btn-approve', function() {
|
||||||
|
var mutationId = $(this).data('id');
|
||||||
|
|
||||||
|
// Load mutation details via AJAX
|
||||||
|
$.ajax({
|
||||||
|
url: '/warehouse/mutations/' + mutationId + '/details',
|
||||||
|
type: 'GET',
|
||||||
|
beforeSend: function() {
|
||||||
|
$('#mutation-details' + mutationId).html(
|
||||||
|
'<div class="text-center">' +
|
||||||
|
'<div class="spinner-border" role="status">' +
|
||||||
|
'<span class="sr-only">Loading...</span>' +
|
||||||
|
'</div>' +
|
||||||
|
'<p>Memuat detail produk...</p>' +
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
var detailsHtml = '<h6>Detail Produk:</h6>';
|
||||||
|
detailsHtml += '<div class="table-responsive">';
|
||||||
|
detailsHtml += '<table class="table table-sm">';
|
||||||
|
detailsHtml += '<thead>';
|
||||||
|
detailsHtml += '<tr>';
|
||||||
|
detailsHtml += '<th>Produk</th>';
|
||||||
|
detailsHtml += '<th>Diminta</th>';
|
||||||
|
detailsHtml += '<th>Disetujui</th>';
|
||||||
|
detailsHtml += '<th>Stock Tersedia</th>';
|
||||||
|
detailsHtml += '</tr>';
|
||||||
|
detailsHtml += '</thead>';
|
||||||
|
detailsHtml += '<tbody>';
|
||||||
|
|
||||||
|
response.details.forEach(function(detail, index) {
|
||||||
|
detailsHtml += '<tr>';
|
||||||
|
detailsHtml += '<td>' + detail.product.name + '</td>';
|
||||||
|
detailsHtml += '<td>' + parseFloat(detail.quantity_requested).toLocaleString() + '</td>';
|
||||||
|
detailsHtml += '<td>';
|
||||||
|
detailsHtml += '<input type="number" name="details[' + detail.id + '][quantity_approved]" ';
|
||||||
|
detailsHtml += 'class="form-control form-control-sm" ';
|
||||||
|
detailsHtml += 'value="' + detail.quantity_requested + '" ';
|
||||||
|
detailsHtml += 'min="0" max="' + Math.min(detail.quantity_requested, detail.available_stock) + '" ';
|
||||||
|
detailsHtml += 'step="0.01" required>';
|
||||||
|
detailsHtml += '</td>';
|
||||||
|
detailsHtml += '<td>' + parseFloat(detail.available_stock).toLocaleString() + '</td>';
|
||||||
|
detailsHtml += '</tr>';
|
||||||
|
});
|
||||||
|
|
||||||
|
detailsHtml += '</tbody>';
|
||||||
|
detailsHtml += '</table>';
|
||||||
|
detailsHtml += '</div>';
|
||||||
|
|
||||||
|
$('#mutation-details' + mutationId).html(detailsHtml);
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
$('#mutation-details' + mutationId).html('<div class="alert alert-danger">Gagal memuat detail produk</div>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#approveModal' + mutationId).modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Auto-calculate approved quantity based on available stock
|
||||||
|
$(document).on('input', 'input[name*="quantity_approved"]', function() {
|
||||||
|
var maxValue = parseFloat($(this).attr('max'));
|
||||||
|
var currentValue = parseFloat($(this).val());
|
||||||
|
|
||||||
|
if (maxValue && currentValue > maxValue) {
|
||||||
|
$(this).val(maxValue);
|
||||||
|
$(this).addClass('is-invalid');
|
||||||
|
if (!$(this).siblings('.invalid-feedback').length) {
|
||||||
|
$(this).after('<div class="invalid-feedback">Jumlah melebihi stock yang tersedia</div>');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$(this).removeClass('is-invalid');
|
||||||
|
$(this).siblings('.invalid-feedback').remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endsection
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<div class="d-flex">
|
|
||||||
<button type="button" class="btn btn-success btn-sm mr-2"
|
|
||||||
onclick="showAdjustStockModal({{ $stock->id }}, 'add')"
|
|
||||||
title="Tambah Stok">
|
|
||||||
<i class="la la-plus"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-warning btn-sm mr-2"
|
|
||||||
onclick="showAdjustStockModal({{ $stock->id }}, 'reduce')"
|
|
||||||
title="Kurangi Stok">
|
|
||||||
<i class="la la-minus"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-info btn-sm"
|
|
||||||
onclick="showStockHistory({{ $stock->id }})"
|
|
||||||
title="Lihat Riwayat">
|
|
||||||
<i class="la la-history"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
@extends('layouts.backapp')
|
|
||||||
|
|
||||||
@section('content')
|
|
||||||
<div class="kt-portlet kt-portlet--mobile">
|
|
||||||
<div class="kt-portlet__head kt-portlet__head--lg">
|
|
||||||
<div class="kt-portlet__head-label">
|
|
||||||
<span class="kt-portlet__head-icon">
|
|
||||||
<i class="kt-font-brand flaticon2-box"></i>
|
|
||||||
</span>
|
|
||||||
<h3 class="kt-portlet__head-title">Manajemen Stok</h3>
|
|
||||||
</div>
|
|
||||||
<div class="kt-portlet__head-toolbar">
|
|
||||||
<div class="kt-portlet__head-actions">
|
|
||||||
<a href="{{ route('opnames.create') }}" class="btn btn-primary">
|
|
||||||
<i class="la la-plus"></i> Buat Opname
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="kt-portlet__body">
|
|
||||||
<!-- Filter -->
|
|
||||||
<div class="row mb-4">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="dealer_filter">Filter Dealer</label>
|
|
||||||
<select class="form-control" id="dealer_filter">
|
|
||||||
<option value="">Semua Dealer</option>
|
|
||||||
@foreach($dealers as $dealer)
|
|
||||||
<option value="{{ $dealer->id }}">{{ $dealer->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="product_filter">Filter Produk</label>
|
|
||||||
<select class="form-control" id="product_filter">
|
|
||||||
<option value="">Semua Produk</option>
|
|
||||||
@foreach($products as $product)
|
|
||||||
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Tabel Stok -->
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-bordered table-hover" id="stocks-table">
|
|
||||||
<thead class="thead-light">
|
|
||||||
<tr>
|
|
||||||
<th>Dealer</th>
|
|
||||||
<th>Produk</th>
|
|
||||||
<th>Stok</th>
|
|
||||||
<th>Aksi</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal Adjust Stock -->
|
|
||||||
<div class="modal fade" id="adjustStockModal" tabindex="-1" role="dialog" aria-hidden="true">
|
|
||||||
<div class="modal-dialog" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Adjust Stok</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<form id="adjustStockForm">
|
|
||||||
<div class="modal-body">
|
|
||||||
<input type="hidden" id="stock_id" name="stock_id">
|
|
||||||
<input type="hidden" id="adjust_type" name="type">
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Jumlah</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="number" class="form-control" name="quantity"
|
|
||||||
step="0.01" min="0.01" required>
|
|
||||||
<div class="input-group-append">
|
|
||||||
<span class="input-group-text">pcs</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Catatan</label>
|
|
||||||
<textarea class="form-control" name="note" rows="3" required></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
|
||||||
<button type="submit" class="btn btn-primary">Simpan</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal Stock History -->
|
|
||||||
<div class="modal fade" id="stockHistoryModal" tabindex="-1" role="dialog" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Riwayat Stok</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-bordered" id="history-table">
|
|
||||||
<thead class="thead-light">
|
|
||||||
<tr>
|
|
||||||
<th>Tanggal</th>
|
|
||||||
<th>User</th>
|
|
||||||
<th>Perubahan</th>
|
|
||||||
<th>Stok Lama</th>
|
|
||||||
<th>Stok Baru</th>
|
|
||||||
<th>Catatan</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endsection
|
|
||||||
|
|
||||||
@section('javascripts')
|
|
||||||
<script>
|
|
||||||
$(document).ready(function() {
|
|
||||||
// Inisialisasi DataTable
|
|
||||||
var table = $('#stocks-table').DataTable({
|
|
||||||
processing: true,
|
|
||||||
serverSide: true,
|
|
||||||
ajax: {
|
|
||||||
url: '{{ route("stocks.index") }}',
|
|
||||||
data: function(d) {
|
|
||||||
d.dealer_id = $('#dealer_filter').val();
|
|
||||||
d.product_id = $('#product_filter').val();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
columns: [
|
|
||||||
{data: 'dealer_name', name: 'dealer_name'},
|
|
||||||
{data: 'product_name', name: 'product_name'},
|
|
||||||
{data: 'quantity', name: 'quantity'},
|
|
||||||
{data: 'action', name: 'action', orderable: false, searchable: false}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Filter change handler
|
|
||||||
$('#dealer_filter, #product_filter').change(function() {
|
|
||||||
table.ajax.reload();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Show adjust stock modal
|
|
||||||
window.showAdjustStockModal = function(stockId, type) {
|
|
||||||
$('#stock_id').val(stockId);
|
|
||||||
$('#adjust_type').val(type);
|
|
||||||
$('#adjustStockModal').modal('show');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle adjust stock form submit
|
|
||||||
$('#adjustStockForm').submit(function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: '{{ route("stocks.adjust") }}',
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
_token: '{{ csrf_token() }}',
|
|
||||||
stock_id: $('#stock_id').val(),
|
|
||||||
type: $('#adjust_type').val(),
|
|
||||||
quantity: $('input[name="quantity"]').val(),
|
|
||||||
note: $('textarea[name="note"]').val()
|
|
||||||
},
|
|
||||||
success: function(response) {
|
|
||||||
if (response.success) {
|
|
||||||
$('#adjustStockModal').modal('hide');
|
|
||||||
table.ajax.reload();
|
|
||||||
toastr.success(response.message);
|
|
||||||
} else {
|
|
||||||
toastr.error(response.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function(xhr) {
|
|
||||||
toastr.error(xhr.responseJSON?.message || 'Terjadi kesalahan');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Show stock history
|
|
||||||
window.showStockHistory = function(stockId) {
|
|
||||||
$.get('{{ route("stocks.history") }}', {
|
|
||||||
stock_id: stockId
|
|
||||||
})
|
|
||||||
.done(function(response) {
|
|
||||||
var tbody = $('#history-table tbody');
|
|
||||||
tbody.empty();
|
|
||||||
|
|
||||||
response.logs.forEach(function(log) {
|
|
||||||
tbody.append(`
|
|
||||||
<tr>
|
|
||||||
<td>${log.date}</td>
|
|
||||||
<td>${log.user}</td>
|
|
||||||
<td>${log.change}</td>
|
|
||||||
<td>${log.old_quantity}</td>
|
|
||||||
<td>${log.new_quantity}</td>
|
|
||||||
<td>${log.note}</td>
|
|
||||||
</tr>
|
|
||||||
`);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#stockHistoryModal').modal('show');
|
|
||||||
})
|
|
||||||
.fail(function(xhr) {
|
|
||||||
toastr.error('Gagal memuat riwayat stok');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Reset form when modal is closed
|
|
||||||
$('#adjustStockModal').on('hidden.bs.modal', function() {
|
|
||||||
$('#adjustStockForm')[0].reset();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@endsection
|
|
||||||
@@ -11,7 +11,7 @@ use App\Http\Controllers\WarehouseManagement\OpnamesController;
|
|||||||
use App\Http\Controllers\WarehouseManagement\ProductCategoriesController;
|
use App\Http\Controllers\WarehouseManagement\ProductCategoriesController;
|
||||||
use App\Http\Controllers\WarehouseManagement\ProductsController;
|
use App\Http\Controllers\WarehouseManagement\ProductsController;
|
||||||
use App\Http\Controllers\WorkController;
|
use App\Http\Controllers\WorkController;
|
||||||
use App\Http\Controllers\WarehouseManagement\StocksController;
|
use App\Http\Controllers\WarehouseManagement\MutationsController;
|
||||||
use App\Models\Menu;
|
use App\Models\Menu;
|
||||||
use App\Models\Privilege;
|
use App\Models\Privilege;
|
||||||
use App\Models\Role;
|
use App\Models\Role;
|
||||||
@@ -241,10 +241,19 @@ Route::group(['middleware' => 'auth'], function() {
|
|||||||
Route::post('get-stock-data', 'getStockData')->name('opnames.get-stock-data');
|
Route::post('get-stock-data', 'getStockData')->name('opnames.get-stock-data');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::prefix('stocks')->controller(StocksController::class)->group(function () {
|
Route::prefix('mutations')->name('mutations.')->controller(MutationsController::class)->group(function () {
|
||||||
Route::get('/', 'index')->name('stocks.index');
|
Route::get('/', 'index')->name('index');
|
||||||
Route::post('adjust', 'adjust')->name('stocks.adjust');
|
Route::get('create', 'create')->name('create');
|
||||||
Route::get('history', 'history')->name('stocks.history');
|
Route::post('/', 'store')->name('store');
|
||||||
|
Route::get('get-product-stock', 'getProductStock')->name('get-product-stock');
|
||||||
|
Route::get('{mutation}', 'show')->name('show');
|
||||||
|
Route::get('{mutation}/edit', 'edit')->name('edit');
|
||||||
|
Route::get('{mutation}/details', 'getDetails')->name('details');
|
||||||
|
Route::post('{mutation}/receive', 'receive')->name('receive');
|
||||||
|
Route::post('{mutation}/approve', 'approve')->name('approve');
|
||||||
|
Route::post('{mutation}/reject', 'reject')->name('reject');
|
||||||
|
Route::post('{mutation}/complete', 'complete')->name('complete');
|
||||||
|
Route::post('{mutation}/cancel', 'cancel')->name('cancel');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -33,6 +33,14 @@ mix.js("resources/js/app.js", "public/js")
|
|||||||
"resources/js/warehouse_management/opnames/detail.js",
|
"resources/js/warehouse_management/opnames/detail.js",
|
||||||
"public/js/warehouse_management/opnames"
|
"public/js/warehouse_management/opnames"
|
||||||
)
|
)
|
||||||
|
.js(
|
||||||
|
"resources/js/warehouse_management/mutations/index.js",
|
||||||
|
"public/js/warehouse_management/mutations"
|
||||||
|
)
|
||||||
|
.js(
|
||||||
|
"resources/js/warehouse_management/mutations/create.js",
|
||||||
|
"public/js/warehouse_management/mutations"
|
||||||
|
)
|
||||||
.sourceMaps();
|
.sourceMaps();
|
||||||
|
|
||||||
mix.browserSync({
|
mix.browserSync({
|
||||||
|
|||||||
Reference in New Issue
Block a user