add: implementar controlador y modelo para la gestión de clientes, incluyendo rutas API

This commit is contained in:
Juan Felipe Zapata Moreno 2026-01-12 14:49:50 -06:00
parent 06425157b8
commit fa8bea2060
6 changed files with 266 additions and 22 deletions

View File

@ -0,0 +1,114 @@
<?php namespace App\Http\Controllers\App;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Client;
use Notsoweb\ApiResponse\Enums\ApiResponse;
class ClientController extends Controller
{
public function index(Request $request)
{
$clients = Client::where('name', 'LIKE', "%{$request->q}%")
->orderBy('name')
->paginate(config('app.pagination'));
return ApiResponse::OK->response(['clients' => $clients]);
}
public function show(Client $client)
{
return ApiResponse::OK->response([
'client' => $client
]);
}
public function store(Request $request)
{
$request->validate([
'name' => 'nullable|string|max:255',
'email' => 'nullable|email|max:255',
'phone' => 'nullable|string|max:20',
'address' => 'nullable|string|max:500',
'rfc' => 'nullable|string|max:13',
],[
'email.unique' => 'El correo electrónico ya está en uso por otro cliente.',
'phone.unique' => 'El teléfono ya está en uso por otro cliente.',
'rfc.unique' => 'El RFC ya está en uso por otro cliente.',
]);
try{
$client = Client::create($request->only([
'name',
'email',
'phone',
'address',
'rfc',
]));
return ApiResponse::OK->response([
'client' => $client,
'message' => 'Cliente creado correctamente.'
]);
}catch(\Exception $e){
return ApiResponse::BAD_REQUEST->response([
'message' => 'Error al crear el cliente.'
]);
}
}
public function update(Request $request, Client $client)
{
$request->validate([
'name' => 'nullable|string|max:255',
'email' => 'nullable|email|max:255',
'phone' => 'nullable|string|max:20',
'address' => 'nullable|string|max:500',
'rfc' => 'nullable|string|max:13',
],[
'email.unique' => 'El correo electrónico ya está en uso por otro cliente.',
'phone.unique' => 'El teléfono ya está en uso por otro cliente.',
'rfc.unique' => 'El RFC ya está en uso por otro cliente.',
]);
try{
$client->update($request->only([
'name',
'email',
'phone',
'address',
'rfc',
]));
return ApiResponse::OK->response([
'client' => $client,
'message' => 'Cliente actualizado correctamente.'
]);
}catch(\Exception $e){
return ApiResponse::BAD_REQUEST->response([
'message' => 'Error al actualizar el cliente.'
]);
}
}
public function destroy(Client $client)
{
try{
$client->delete();
return ApiResponse::OK->response([
'message' => 'Cliente eliminado correctamente.'
]);
}catch(\Exception $e){
return ApiResponse::BAD_REQUEST->response([
'message' => 'Error al eliminar el cliente.'
]);
}
}
}

14
app/Models/Client.php Normal file
View File

@ -0,0 +1,14 @@
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Client extends Model
{
protected $fillable = [
'name',
'email',
'phone',
'address',
'rfc',
];
}

View File

@ -0,0 +1,32 @@
<?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('clients', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->nullable();
$table->string('phone')->nullable();
$table->string('address')->nullable();
$table->string('rfc')->unique()->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('clients');
}
};

View File

@ -1,4 +1,7 @@
<?php namespace Database\Seeders;
<?php
namespace Database\Seeders;
/**
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
*/
@ -11,9 +14,9 @@
/**
* Roles y permisos
*
*
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
*
*
* @version 1.0.0
*/
class RoleSeeder extends Seeder
@ -61,11 +64,54 @@ public function run(): void
]);
$activityIndex = $this->onIndex(
code: 'activities',
type: $pulse,
code: 'activities',
type: $pulse,
guardName: 'api'
);
// ==================== NUEVOS PERMISOS PARA PDV ====================
// Permisos de Caja
$cashRegisterType = PermissionType::create([
'name' => 'Caja registradora'
]);
$cashRegisterIndex = $this->onIndex('cash-registers', 'Mostrar datos', $cashRegisterType, 'api');
$cashRegisterOpen = $this->onPermission('cash-registers.open', 'Abrir caja', $cashRegisterType, 'api');
$cashRegisterClose = $this->onPermission('cash-registers.close', 'Cerrar caja', $cashRegisterType, 'api');
$cashRegisterCurrent = $this->onPermission('cash-registers.current', 'Ver caja actual', $cashRegisterType, 'api');
// Permisos de Ventas
$salesType = PermissionType::create([
'name' => 'Ventas'
]);
$salesIndex = $this->onIndex('sales', 'Mostrar datos', $salesType, 'api');
$salesCreate = $this->onCreate('sales', 'Crear registros', $salesType, 'api');
$salesCancel = $this->onPermission('sales.cancel', 'Cancelar venta', $salesType, 'api');
// Permisos de Inventario (solo lectura)
$inventoryType = PermissionType::create([
'name' => 'Inventario'
]);
$inventoryIndex = $this->onIndex('inventario', 'Mostrar datos', $inventoryType, 'api');
// Permisos de Clientes
$clientsType = PermissionType::create([
'name' => 'Clientes'
]);
[
$clientIndex,
$clientCreate,
$clientEdit,
$clientDestroy
] = $this->onCRUD('clients', $clientsType, 'api');
// ==================== ROLES ====================
// Desarrollador
Role::create([
'name' => 'developer',
@ -90,7 +136,41 @@ public function run(): void
$roleEdit,
$roleDestroy,
$systemPulse,
$activityIndex
$activityIndex,
// Permisos completos de PDV
$cashRegisterIndex,
$cashRegisterOpen,
$cashRegisterClose,
$cashRegisterCurrent,
$salesIndex,
$salesCreate,
$salesCancel,
$inventoryIndex,
$clientIndex,
$clientCreate,
$clientEdit,
$clientDestroy
);
//Operador PDV (solo permisos de operación de caja y ventas)
Role::create([
'name' => 'operador_pdv',
'description' => 'Operador de Punto de Venta',
'guard_name' => 'api'
])->givePermissionTo(
// Caja
$cashRegisterIndex, // Ver historial de cajas
$cashRegisterOpen, // Abrir caja
$cashRegisterClose, // Cerrar caja
$cashRegisterCurrent, // Ver caja actual
// Ventas
$salesIndex, // Ver historial de ventas
$salesCreate, // Crear ventas
// Inventario (solo lectura)
$inventoryIndex, // Listar productos
// Clientes
$clientIndex, // Buscar clientes
$clientCreate // Crear clientes
);
}
}

View File

@ -9,9 +9,9 @@
/**
* Usuarios predeterminados del sistema
*
*
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
*
*
* @version 1.0.0
*/
class UserSeeder extends Seeder
@ -21,34 +21,34 @@ class UserSeeder extends Seeder
*/
public function run(): void
{
$developer = UserSecureSupport::create('developer@notsoweb.com');
$developer = UserSecureSupport::create('developer@golsystems.com');
User::create([
'name' => 'Developer',
'paternal' => 'Notsoweb',
'maternal' => 'Software',
'paternal' => 'Golsystems',
'maternal' => 'Dev',
'email' => $developer->email,
'password' => $developer->hash,
])->assignRole(__('developer'));
$admin = UserSecureSupport::create('admin@notsoweb.com');
$admin = UserSecureSupport::create('admin@golsystems.com');
User::create([
'name' => 'Admin',
'paternal' => 'Notsoweb',
'maternal' => 'Software',
'paternal' => 'Golsystems',
'maternal' => 'Dev',
'email' => $admin->email,
'password' => $admin->hash,
'password' => 'SoyAdmin123..',
])->assignRole(__('admin'));
$demo = UserSecureSupport::create('demo@notsoweb.com');
$operadorPdv = UserSecureSupport::create('opv@golsystems.com');
User::create([
'name' => 'Demo',
'paternal' => 'Notsoweb',
'maternal' => 'Software',
'email' => $demo->email,
'password' => $demo->hash,
]);
'name' => 'Operador PDV',
'paternal' => 'Golsystems',
'maternal' => 'Dev',
'email' => $operadorPdv->email,
'password' => $operadorPdv->hash,
])->assignRole(__('operador_pdv'));
}
}

View File

@ -2,6 +2,7 @@
use App\Http\Controllers\App\CashRegisterController;
use App\Http\Controllers\App\CategoryController;
use App\Http\Controllers\App\ClientController;
use App\Http\Controllers\App\InventoryController;
use App\Http\Controllers\App\PriceController;
use App\Http\Controllers\App\ReportController;
@ -55,6 +56,9 @@
Route::get('top-selling-product', [ReportController::class, 'topSellingProduct']);
Route::get('products-without-movement', [ReportController::class, 'productsWithoutMovement']);
});
//CLIENTES
Route::resource('clients', ClientController::class);
});
/** Rutas públicas */