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 * @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
*/ */
@ -11,9 +14,9 @@
/** /**
* Roles y permisos * Roles y permisos
* *
* @author Moisés Cortés C. <moises.cortes@notsoweb.com> * @author Moisés Cortés C. <moises.cortes@notsoweb.com>
* *
* @version 1.0.0 * @version 1.0.0
*/ */
class RoleSeeder extends Seeder class RoleSeeder extends Seeder
@ -61,11 +64,54 @@ public function run(): void
]); ]);
$activityIndex = $this->onIndex( $activityIndex = $this->onIndex(
code: 'activities', code: 'activities',
type: $pulse, type: $pulse,
guardName: 'api' 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 // Desarrollador
Role::create([ Role::create([
'name' => 'developer', 'name' => 'developer',
@ -90,7 +136,41 @@ public function run(): void
$roleEdit, $roleEdit,
$roleDestroy, $roleDestroy,
$systemPulse, $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 * Usuarios predeterminados del sistema
* *
* @author Moisés Cortés C. <moises.cortes@notsoweb.com> * @author Moisés Cortés C. <moises.cortes@notsoweb.com>
* *
* @version 1.0.0 * @version 1.0.0
*/ */
class UserSeeder extends Seeder class UserSeeder extends Seeder
@ -21,34 +21,34 @@ class UserSeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
$developer = UserSecureSupport::create('developer@notsoweb.com'); $developer = UserSecureSupport::create('developer@golsystems.com');
User::create([ User::create([
'name' => 'Developer', 'name' => 'Developer',
'paternal' => 'Notsoweb', 'paternal' => 'Golsystems',
'maternal' => 'Software', 'maternal' => 'Dev',
'email' => $developer->email, 'email' => $developer->email,
'password' => $developer->hash, 'password' => $developer->hash,
])->assignRole(__('developer')); ])->assignRole(__('developer'));
$admin = UserSecureSupport::create('admin@notsoweb.com'); $admin = UserSecureSupport::create('admin@golsystems.com');
User::create([ User::create([
'name' => 'Admin', 'name' => 'Admin',
'paternal' => 'Notsoweb', 'paternal' => 'Golsystems',
'maternal' => 'Software', 'maternal' => 'Dev',
'email' => $admin->email, 'email' => $admin->email,
'password' => $admin->hash, 'password' => 'SoyAdmin123..',
])->assignRole(__('admin')); ])->assignRole(__('admin'));
$demo = UserSecureSupport::create('demo@notsoweb.com'); $operadorPdv = UserSecureSupport::create('opv@golsystems.com');
User::create([ User::create([
'name' => 'Demo', 'name' => 'Operador PDV',
'paternal' => 'Notsoweb', 'paternal' => 'Golsystems',
'maternal' => 'Software', 'maternal' => 'Dev',
'email' => $demo->email, 'email' => $operadorPdv->email,
'password' => $demo->hash, 'password' => $operadorPdv->hash,
]); ])->assignRole(__('operador_pdv'));
} }
} }

View File

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