Prompt Details
Model
(claude-4-6-sonnet)
Token size
207
Example input
[DESCRIPTION]: Restaurant order system with customer name, table, products, quantity, unit price, total and order status
Example output
<?php
// ============================================================
// SISTEMA 2 — PEDIDOS DE RESTAURANTE
// Laravel 11 · Script completo listo para copiar y pegar
// ============================================================
//
// INSTRUCCIONES:
// Cada sección indica el archivo destino en un comentario.
// Copia el contenido del bloque /* ... */ al archivo indicado.
//
// ORDEN DE MIGRACIÓN IMPORTANTE:
// 1. xxxx_create_pedidos_table.php (tabla padre)
// 2. xxxx_create_pedido_productos_table.php (tabla hija con FK)
//
// COMANDOS FINALES:
// php artisan migrate
// php artisan db:seed --class=PedidoSeeder
// php artisan route:list --path=api/v1/pedidos
// ============================================================
// ============================================================
// ARCHIVO: database/migrations/xxxx_create_pedidos_table.php
// ============================================================
/*
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Crea la tabla principal de pedidos del restaurante.
*/
public function up(): void
{
Schema::create('pedidos', function (Blueprint $table) {
$table->id();
// Datos del cliente y mesa
$table->string('nombre_cliente', 150);
$table->unsignedSmallInteger('mesa')->index();
// Total calculado a partir de las líneas
$table->decimal('total', 10, 2)->default(0.00);
// Estado del pedido
$table->enum('estado', ['pendiente', 'preparando', 'listo', 'entregado'])
->default('pendiente')
->index();
// Tiempo estimado de entrega en minutos
$table->unsignedSmallInteger('tiempo_entrega_estimado')
->nullable()
->comment('Minutos');
// Timestamp de cuando fue entregado realmente
$table->timestamp('entregado_en')->nullable();
$table->timestamps();
$table->softDeletes();
// Índices compuestos para consultas frecuentes
$table->index(['estado', 'created_at'], 'idx_estado_fecha');
$table->index(['mesa', 'estado'], 'idx_mesa_estado');
});
}
public function down(): void
{
Schema::dropIfExists('pedidos');
}
};
*/
// ============================================================
// ARCHIVO: database/migrations/xxxx_create_pedido_productos_table.php
// ============================================================
/*
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Crea la tabla de líneas/productos de cada pedido.
* Precios desnormalizados para conservar historial.
*/
public function up(): void
{
Schema::create('pedido_productos', function (Blueprint $table) {
$table->id();
// Relación con el pedido padre
$table->foreignId('pedido_id')
->constrained('pedidos')
->cascadeOnDelete();
// Datos del producto (desnormalizados para preservar historial de precios)
$table->string('producto', 150);
$table->unsignedSmallInteger('cantidad')->default(1);
$table->decimal('precio_unitario', 8, 2);
// Columna generada: cantidad * precio_unitario
$table->decimal('subtotal', 10, 2)->storedAs('cantidad * precio_unitario');
// Notas especiales por línea (ej: "sin cebolla", "bien cocido")
$table->string('notas', 255)->nullable();
$table->timestamps();
$table->index('pedido_id');
});
}
public function down(): void
{
Schema::dropIfExists('pedido_productos');
}
};
*/
// ============================================================
// ARCHIVO: app/Models/Pedido.php
// ============================================================
/*
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Pedido extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'pedidos';
// ─── Constantes de estado ────────────────────────────────
const ESTADO_PENDIENTE = 'pendiente';
const ESTADO_PREPARANDO = 'preparando';
const ESTADO_LISTO = 'listo';
const ESTADO_ENTREGADO = 'entregado';
// Flujo de transición permitido: estado actual → [estados siguientes]
const TRANSICIONES = [
self::ESTADO_PENDIENTE => [self::ESTADO_PREPARANDO],
self::ESTADO_PREPARANDO => [self::ESTADO_LISTO],
self::ESTADO_LISTO => [self::ESTADO_ENTREGADO],
self::ESTADO_ENTREGADO => [],
];
protected $fillable = [
'nombre_cliente',
'mesa',
'total',
'estado',
'tiempo_entrega_estimado',
'entregado_en',
];
protected $casts = [
'total' => 'decimal:2',
'mesa' => 'integer',
'tiempo_entrega_estimado' => 'integer',
'entregado_en' => 'datetime',
'deleted_at' => 'datetime',
];
protected $hidden = ['deleted_at'];
// ─── Relaciones ──────────────────────────────────────────
/** Líneas de productos que componen este pedido. */
public function productos(): HasMany
{
return $this->hasMany(PedidoProducto::class, 'pedido_id');
}
// ─── Atributos calculados ────────────────────────────────
/** Minutos transcurridos desde que se creó el pedido. */
public function getTiempoTranscurridoAttribute(): int
{
return (int) $this->created_at->diffInMinutes(now());
}
/** Indica si el pedido superó el tiempo estimado sin ser entregado. */
public function getRetrasadoAttribute(): bool
{
if (! $this->tiempo_entrega_estimado || $this->estado === self::ESTADO_ENTREGADO) {
return false;
}
return $this->tiempo_transcurrido > $this->tiempo_entrega_estimado;
}
/** Color semántico para el estado (útil en UIs). */
public function getEtiquetaEstadoAttribute(): string
{
return match ($this->estado) {
self::ESTADO_PENDIENTE => 'warning',
self::ESTADO_PREPARANDO => 'info',
self::ESTADO_LISTO => 'success',
self::ESTADO_ENTREGADO => 'secondary',
default => 'light',
};
}
// ─── Métodos de negocio ──────────────────────────────────
/** Verifica si se puede avanzar al estado indicado. */
public function puedeTransicionarA(string $nuevoEstado): bool
{
return in_array($nuevoEstado, self::TRANSICIONES[$this->estado] ?? []);
}
/** Recalcula y persiste el total sumando los subtotales de sus líneas. */
public function recalcularTotal(): void
{
$this->update([
'total' => $this->productos()->sum('subtotal'),
]);
}
// ─── Scopes locales ──────────────────────────────────────
/** Filtra por estado específico. */
public function scopePorEstado(Builder $query, string $estado): Builder
{
return $query->where('estado', $estado);
}
/** Pedidos no entregados (activos en cocina). */
public function scopeActivos(Builder $query): Builder
{
return $query->whereNotIn('estado', [self::ESTADO_ENTREGADO]);
}
/** Pedidos de una mesa específica. */
public function scopePorMesa(Builder $query, int $mesa): Builder
{
return $query->where('mesa', $mesa);
}
/** Pedidos que superaron su tiempo estimado sin ser entregados. */
public function scopeRetrasados(Builder $query): Builder
{
return $query
->whereNotNull('tiempo_entrega_estimado')
->whereNotIn('estado', [self::ESTADO_ENTREGADO])
->whereRaw('TIMESTAMPDIFF(MINUTE, created_at, NOW()) > tiempo_entrega_estimado');
}
/** Solo pedidos del día actual. */
public function scopeDeHoy(Builder $query): Builder
{
return $query->whereDate('created_at', today());
}
}
*/
// ============================================================
// ARCHIVO: app/Models/PedidoProducto.php
// ============================================================
/*
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class PedidoProducto extends Model
{
use HasFactory;
protected $table = 'pedido_productos';
protected $fillable = [
'pedido_id',
'producto',
'cantidad',
'precio_unitario',
'notas',
];
protected $casts = [
'cantidad' => 'integer',
'precio_unitario' => 'decimal:2',
'subtotal' => 'decimal:2', // columna generada, solo lectura
];
// ─── Relaciones ──────────────────────────────────────────
/** Pedido al que pertenece esta línea. */
public function pedido(): BelongsTo
{
return $this->belongsTo(Pedido::class, 'pedido_id');
}
}
*/
// ============================================================
// ARCHIVO: app/Http/Requests/StorePedidoRequest.php
// ============================================================
/*
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePedidoRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
// Cabecera del pedido
'nombre_cliente' => ['required', 'string', 'max:150'],
'mesa' => ['required', 'integer', 'min:1', 'max:999'],
'tiempo_entrega_estimado' => ['nullable', 'integer', 'min:1', 'max:300'],
// Líneas de productos (mínimo 1)
'productos' => ['required', 'array', 'min:1'],
'productos.*.producto' => ['required', 'string', 'max:150'],
'productos.*.cantidad' => ['required', 'integer', 'min:1', 'max:100'],
'productos.*.precio_unitario' => ['required', 'numeric', 'min:0.01', 'max:99999.99'],
'productos.*.notas' => ['nullable', 'string', 'max:255'],
];
}
public function messages(): array
{
return [
'nombre_cliente.required' => 'El nombre del cliente es obligatorio.',
'mesa.required' => 'El número de mesa es obligatorio.',
'mesa.min' => 'El número de mesa debe ser mayor a cero.',
'productos.required' => 'El pedido debe contener al menos un producto.',
'productos.min' => 'Debes agregar al menos un producto al pedido.',
'productos.*.producto.required' => 'El nombre del producto es obligatorio.',
'productos.*.cantidad.required' => 'La cantidad es obligatoria.',
'productos.*.cantidad.min' => 'La cantidad mínima por producto es 1.',
'productos.*.precio_unitario.required' => 'El precio unitario es obligatorio.',
'productos.*.precio_unitario.min' => 'El precio unitario debe ser mayor a cero.',
];
}
}
*/
// ============================================================
// ARCHIVO: app/Http/Requests/UpdatePedidoRequest.php
// ============================================================
/*
<?php
namespace App\Http\Requests;
use App\Models\Pedido;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdatePedidoRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
// Cabecera — todos opcionales en actualización
'nombre_cliente' => ['sometimes', 'required', 'string', 'max:150'],
'mesa' => ['sometimes', 'required', 'integer', 'min:1', 'max:999'],
'tiempo_entrega_estimado' => ['nullable', 'integer', 'min:1', 'max:300'],
// Estado: validación de valor, transición controlada en el controlador
'estado' => [
'sometimes',
'required',
Rule::in([
Pedido::ESTADO_PENDIENTE,
Pedido::ESTADO_PREPARANDO,
Pedido::ESTADO_LISTO,
Pedido::ESTADO_ENTREGADO,
]),
],
// Líneas de productos (reemplazo completo si se envían)
'productos' => ['sometimes', 'array', 'min:1'],
'productos.*.producto' => ['required_with:productos', 'string', 'max:150'],
'productos.*.cantidad' => ['required_with:productos', 'integer', 'min:1', 'max:100'],
'productos.*.precio_unitario' => ['required_with:productos', 'numeric', 'min:0.01', 'max:99999.99'],
'productos.*.notas' => ['nullable', 'string', 'max:255'],
];
}
public function messages(): array
{
return [
'estado.in' => 'Estado no válido. Valores permitidos: pendiente, preparando, listo, entregado.',
'productos.min' => 'Si actualizas los productos, debe haber al menos uno.',
'productos.*.cantidad.min' => 'La cantidad mínima por producto es 1.',
'productos.*.precio_unitario.min' => 'El precio unitario debe ser mayor a cero.',
];
}
}
*/
// ============================================================
// ARCHIVO: app/Http/Resources/PedidoProductoResource.php
// ============================================================
/*
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PedidoProductoResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'producto' => $this->producto,
'cantidad' => $this->cantidad,
'precio_unitario' => (float) $this->precio_unitario,
'precio_formato' => '$' . number_format($this->precio_unitario, 2),
'subtotal' => (float) $this->subtotal,
'subtotal_formato' => '$' . number_format($this->subtotal, 2),
'notas' => $this->notas,
];
}
}
*/
// ============================================================
// ARCHIVO: app/Http/Resources/PedidoResource.php
// ============================================================
/*
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PedidoResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
// Cliente y mesa
'nombre_cliente' => $this->nombre_cliente,
'mesa' => $this->mesa,
// Estado y etiquetas visuales
'estado' => $this->estado,
'estado_etiqueta' => ucfirst($this->estado),
'etiqueta_color' => $this->etiqueta_estado,
// Tiempos
'tiempo_entrega_estimado' => $this->tiempo_entrega_estimado,
'tiempo_transcurrido' => $this->tiempo_transcurrido,
'retrasado' => $this->retrasado,
'entregado_en' => $this->entregado_en?->toIso8601String(),
// Totales
'total' => (float) $this->total,
'total_formato' => '$' . number_format($this->total, 2),
'cantidad_productos' => $this->productos_count ?? $this->productos->count(),
// Líneas del pedido (solo si fueron cargadas con ->load('productos'))
'productos' => PedidoProductoResource::collection(
$this->whenLoaded('productos')
),
// Timestamps
'creado_en' => $this->created_at?->toIso8601String(),
'actualizado_en' => $this->updated_at?->toIso8601String(),
];
}
}
*/
// ============================================================
// ARCHIVO: app/Http/Resources/PedidoCollection.php
// ============================================================
/*
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
class PedidoCollection extends ResourceCollection
{
public $collects = PedidoResource::class;
public function toArray(Request $request): array
{
return [
'data' => $this->collection,
'meta' => [
'total' => $this->total(),
'por_pagina' => $this->perPage(),
'pagina_actual' => $this->currentPage(),
'ultima_pagina' => $this->lastPage(),
],
];
}
}
*/
// ============================================================
// ARCHIVO: app/Http/Controllers/Api/PedidoController.php
// ============================================================
/*
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\StorePedidoRequest;
use App\Http\Requests\UpdatePedidoRequest;
use App\Http\Resources\PedidoCollection;
use App\Http\Resources\PedidoResource;
use App\Models\Pedido;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable;
class PedidoController extends Controller
{
/**
* Lista paginada de pedidos con filtros opcionales.
* GET /api/v1/pedidos
*/
public function index(Request $request): PedidoCollection|JsonResponse
{
try {
$query = Pedido::withCount('productos');
if ($request->filled('estado')) { $query->porEstado($request->string('estado')); }
if ($request->filled('mesa')) { $query->porMesa($request->integer('mesa')); }
if ($request->boolean('solo_activos')) { $query->activos(); }
if ($request->boolean('retrasados')) { $query->retrasados(); }
if ($request->boolean('solo_hoy')) { $query->deHoy(); }
if ($request->boolean('con_productos')){ $query->with('productos'); }
$pedidos = $query
->orderByRaw("FIELD(estado, 'preparando', 'pendiente', 'listo', 'entregado')")
->orderBy('created_at', 'asc')
->paginate($request->integer('por_pagina', 15));
return new PedidoCollection($pedidos);
} catch (Throwable $e) {
Log::error('Error al listar pedidos', ['error' => $e->getMessage()]);
return response()->json([
'mensaje' => 'Error al obtener los pedidos.',
'error' => $e->getMessage(),
], 500);
}
}
/**
* Crea un nuevo pedido con sus líneas de productos.
* POST /api/v1/pedidos
*/
public function store(StorePedidoRequest $request): JsonResponse
{
try {
$pedido = DB::transaction(function () use ($request): Pedido {
// 1. Crear cabecera
$pedido = Pedido::create([
'nombre_cliente' => $request->nombre_cliente,
'mesa' => $request->mesa,
'tiempo_entrega_estimado' => $request->tiempo_entrega_estimado,
'estado' => Pedido::ESTADO_PENDIENTE,
'total' => 0,
]);
// 2. Insertar líneas de productos
foreach ($request->productos as $linea) {
$pedido->productos()->create([
'producto' => $linea['producto'],
'cantidad' => $linea['cantidad'],
'precio_unitario' => $linea['precio_unitario'],
'notas' => $linea['notas'] ?? null,
]);
}
// 3. Calcular total desde los subtotales generados
$pedido->recalcularTotal();
return $pedido->load('productos');
});
return response()->json([
'mensaje' => 'Pedido registrado exitosamente.',
'data' => new PedidoResource($pedido),
], 201);
} catch (Throwable $e) {
Log::error('Error al crear pedido', ['error' => $e->getMessage()]);
return response()->json([
'mensaje' => 'No se pudo registrar el pedido.',
'error' => $e->getMessage(),
], 500);
}
}
/**
* Muestra un pedido específico con sus productos.
* GET /api/v1/pedidos/{id}
*/
public function show(int $id): JsonResponse
{
try {
$pedido = Pedido::with('productos')->findOrFail($id);
return response()->json([
'data' => new PedidoResource($pedido),
]);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException) {
return response()->json(['mensaje' => 'Pedido no encontrado.'], 404);
} catch (Throwable $e) {
Log::error('Error al obtener pedido', ['id' => $id, 'error' => $e->getMessage()]);
return response()->json([
'mensaje' => 'Error al obtener el pedido.',
'error' => $e->getMessage(),
], 500);
}
}
/**
* Actualiza datos del pedido y/o reemplaza sus productos.
* PUT/PATCH /api/v1/pedidos/{id}
*/
public function update(UpdatePedidoRequest $request, int $id): JsonResponse
{
try {
$pedido = Pedido::findOrFail($id);
// Validar que la transición de estado sea permitida
if ($request->filled('estado') && $request->estado !== $pedido->estado) {
if (! $pedido->puedeTransicionarA($request->estado)) {
return response()->json([
'mensaje' => "No se puede pasar de '{$pedido->estado}' a '{$request->estado}'.",
'transiciones_permitidas' => Pedido::TRANSICIONES[$pedido->estado],
], 422);
}
}
DB::transaction(function () use ($request, $pedido): void {
$datos = $request->except('productos');
// Registrar timestamp de entrega real
if (isset($datos['estado']) && $datos['estado'] === Pedido::ESTADO_ENTREGADO) {
$datos['entregado_en'] = now();
}
$pedido->update($datos);
// Si se envían productos, reemplazar todas las líneas
if ($request->has('productos')) {
$pedido->productos()->delete();
foreach ($request->productos as $linea) {
$pedido->productos()->create([
'producto' => $linea['producto'],
'cantidad' => $linea['cantidad'],
'precio_unitario' => $linea['precio_unitario'],
'notas' => $linea['notas'] ?? null,
]);
}
$pedido->recalcularTotal();
}
});
return response()->json([
'mensaje' => 'Pedido actualizado exitosamente.',
'data' => new PedidoResource($pedido->fresh()->load('productos')),
]);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException) {
return response()->json(['mensaje' => 'Pedido no encontrado.'], 404);
} catch (Throwable $e) {
Log::error('Error al actualizar pedido', ['id' => $id, 'error' => $e->getMessage()]);
return response()->json([
'mensaje' => 'No se pudo actualizar el pedido.',
'error' => $e->getMessage(),
], 500);
}
}
/**
* Elimina un pedido (soft delete). Bloqueado si está en preparación o entregado.
* DELETE /api/v1/pedidos/{id}
*/
public function destroy(int $id): JsonResponse
{
try {
$pedido = Pedido::findOrFail($id);
if (in_array($pedido->estado, [Pedido::ESTADO_PREPARANDO, Pedido::ESTADO_ENTREGADO])) {
return response()->json([
'mensaje' => "No se puede eliminar un pedido en estado '{$pedido->estado}'.",
], 422);
}
$pedido->delete();
return response()->json([
'mensaje' => 'Pedido eliminado correctamente.',
]);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException) {
return response()->json(['mensaje' => 'Pedido no encontrado.'], 404);
} catch (Throwable $e) {
Log::error('Error al eliminar pedido', ['id' => $id, 'error' => $e->getMessage()]);
return response()->json([
'mensaje' => 'No se pudo eliminar el pedido.',
'error' => $e->getMessage(),
], 500);
}
}
/**
* Avanza automáticamente al siguiente estado en el flujo.
* PATCH /api/v1/pedidos/{id}/avanzar-estado
*/
public function avanzarEstado(int $id): JsonResponse
{
try {
$pedido = Pedido::findOrFail($id);
$siguientes = Pedido::TRANSICIONES[$pedido->estado] ?? [];
if (empty($siguientes)) {
return response()->json([
'mensaje' => "El pedido ya está en su estado final: '{$pedido->estado}'.",
], 422);
}
$nuevoEstado = $siguientes[0];
$datos = ['estado' => $nuevoEstado];
if ($nuevoEstado === Pedido::ESTADO_ENTREGADO) {
$datos['entregado_en'] = now();
}
$pedido->update($datos);
return response()->json([
'mensaje' => "Estado actualizado a '{$nuevoEstado}'.",
'data' => new PedidoResource($pedido->fresh()->load('productos')),
]);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException) {
return response()->json(['mensaje' => 'Pedido no encontrado.'], 404);
} catch (Throwable $e) {
Log::error('Error al avanzar estado del pedido', ['id' => $id, 'error' => $e->getMessage()]);
return response()->json([
'mensaje' => 'No se pudo avanzar el estado.',
'error' => $e->getMessage(),
], 500);
}
}
}
*/
// ============================================================
// ARCHIVO: routes/api.php
// ============================================================
/*
<?php
use App\Http\Controllers\Api\PedidoController;
use Illuminate\Support\Facades\Route;
Route::prefix('v1')->group(function () {
// ── Pedidos ──────────────────────────────────────────────
Route::apiResource('pedidos', PedidoController::class);
// Acción de flujo: avanzar al siguiente estado automáticamente
Route::patch('pedidos/{pedido}/avanzar-estado', [PedidoController::class, 'avanzarEstado'])
->name('pedidos.avanzar-estado');
});
*/
// ============================================================
// ARCHIVO: routes/web.php
// ============================================================
/*
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', fn () => view('welcome'))->name('home');
// Panel de pedidos del restaurante
Route::prefix('pedidos')->name('pedidos.')->group(function () {
Route::get('/', fn () => view('pedidos.index'))->name('index');
Route::get('/cocina', fn () => view('pedidos.cocina'))->name('cocina');
Route::get('/{id}', fn () => view('pedidos.show'))->name('show');
});
*/
// ============================================================
// ARCHIVO: database/seeders/PedidoSeeder.php
// ============================================================
/*
<?php
namespace Database\Seeders;
use App\Models\Pedido;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class PedidoSeeder extends Seeder
{
public function run(): void
{
// Menú del restaurante de ejemplo
$menu = [
['producto' => 'Tacos de Suadero', 'precio' => 65.00], // 0
['producto' => 'Tacos de Pastor', 'precio' => 60.00], // 1
['producto' => 'Quesadilla de Flor de Calabaza', 'precio' => 85.00], // 2
['producto' => 'Enchiladas Verdes', 'precio' => 120.00], // 3
['producto' => 'Pozole Rojo', 'precio' => 145.00], // 4
['producto' => 'Agua de Jamaica', 'precio' => 35.00], // 5
['producto' => 'Agua de Tamarindo', 'precio' => 35.00], // 6
['producto' => 'Refresco', 'precio' => 30.00], // 7
['producto' => 'Ceviche de Camarón', 'precio' => 175.00], // 8
['producto' => 'Sopa de Lima', 'precio' => 95.00], // 9
['producto' => 'Flan Napolitano', 'precio' => 65.00], // 10
['producto' => 'Arroz con Leche', 'precio' => 55.00], // 11
];
$pedidosDatos = [
[
'nombre_cliente' => 'Familia Martínez',
'mesa' => 3,
'estado' => 'entregado',
'tiempo_entrega_estimado' => 25,
'entregado_en' => now()->subMinutes(10),
'productos' => [
['idx' => 0, 'cantidad' => 4],
['idx' => 5, 'cantidad' => 2],
['idx' => 10, 'cantidad' => 2],
],
],
[
'nombre_cliente' => 'Carlos Fuentes',
'mesa' => 7,
'estado' => 'listo',
'tiempo_entrega_estimado' => 20,
'entregado_en' => null,
'productos' => [
['idx' => 3, 'cantidad' => 1],
['idx' => 7, 'cantidad' => 1],
],
],
[
'nombre_cliente' => 'Sofía y Ricardo',
'mesa' => 1,
'estado' => 'preparando',
'tiempo_entrega_estimado' => 30,
'entregado_en' => null,
'productos' => [
['idx' => 8, 'cantidad' => 2],
['idx' => 9, 'cantidad' => 2],
['idx' => 6, 'cantidad' => 2],
],
],
[
'nombre_cliente' => 'Don Aurelio',
'mesa' => 5,
'estado' => 'pendiente',
'tiempo_entrega_estimado' => 15,
'entregado_en' => null,
'productos' => [
['idx' => 4, 'cantidad' => 1, 'notas' => 'Sin chile por favor'],
['idx' => 5, 'cantidad' => 1],
],
],
[
'nombre_cliente' => 'Mesa Ejecutiva BBVA',
'mesa' => 10,
'estado' => 'preparando',
'tiempo_entrega_estimado' => 35,
'entregado_en' => null,
'productos' => [
['idx' => 3, 'cantidad' => 3],
['idx' => 0, 'cantidad' => 6],
['idx' => 7, 'cantidad' => 4],
['idx' => 10, 'cantidad' => 3],
],
],
[
'nombre_cliente' => 'Lupita Hernández',
'mesa' => 2,
'estado' => 'pendiente',
'tiempo_entrega_estimado' => 20,
'entregado_en' => null,
'productos' => [
['idx' => 2, 'cantidad' => 2, 'notas' => 'Con queso Oaxaca'],
['idx' => 6, 'cantidad' => 1],
],
],
[
'nombre_cliente' => 'Gerardo Solís',
'mesa' => 8,
'estado' => 'entregado',
'tiempo_entrega_estimado' => 20,
'entregado_en' => now()->subMinutes(45),
'productos' => [
['idx' => 1, 'cantidad' => 3],
['idx' => 11, 'cantidad' => 1],
['idx' => 7, 'cantidad' => 2],
],
],
[
'nombre_cliente' => 'Pareja en Mesa 4',
'mesa' => 4,
'estado' => 'listo',
'tiempo_entrega_estimado' => 25,
'entregado_en' => null,
'productos' => [
['idx' => 8, 'cantidad' => 1, 'notas' => 'Con extra limón'],
['idx' => 9, 'cantidad' => 1],
['idx' => 5, 'cantidad' => 2],
],
],
[
'nombre_cliente' => 'Niños del Cumpleaños',
'mesa' => 6,
'estado' => 'pendiente',
'tiempo_entrega_estimado' => 30,
'entregado_en' => null,
'productos' => [
['idx' => 1, 'cantidad' => 5],
['idx' => 7, 'cantidad' => 5],
['idx' => 10, 'cantidad' => 5],
],
],
[
'nombre_cliente' => 'Ing. Patricia Vega',
'mesa' => 9,
'estado' => 'preparando',
'tiempo_entrega_estimado' => 20,
'entregado_en' => null,
'productos' => [
['idx' => 4, 'cantidad' => 1],
['idx' => 5, 'cantidad' => 1],
],
],
];
foreach ($pedidosDatos as $datosPedido) {
DB::transaction(function () use ($datosPedido, $menu): void {
$pedido = Pedido::create([
'nombre_cliente' => $datosPedido['nombre_cliente'],
'mesa' => $datosPedido['mesa'],
'estado' => $datosPedido['estado'],
'tiempo_entrega_estimado' => $datosPedido['tiempo_entrega_estimado'],
'entregado_en' => $datosPedido['entregado_en'],
'total' => 0,
]);
foreach ($datosPedido['productos'] as $linea) {
$item = $menu[$linea['idx']];
$pedido->productos()->create([
'producto' => $item['producto'],
'cantidad' => $linea['cantidad'],
'precio_unitario' => $item['precio'],
'notas' => $linea['notas'] ?? null,
]);
}
$pedido->recalcularTotal();
});
}
$this->command->info('✅ Se registraron ' . count($pedidosDatos) . ' pedidos de ejemplo con sus productos.');
}
}
*/
// ============================================================
// ARCHIVO: database/seeders/DatabaseSeeder.php
// ============================================================
/*
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call([
PedidoSeeder::class,
]);
}
}
*/
// ============================================================
// FIN — SISTEMA 2: PEDIDOS DE RESTAURANTE
//
// RESUMEN DE ENDPOINTS:
// GET /api/v1/pedidos → index
// POST /api/v1/pedidos → store
// GET /api/v1/pedidos/{id} → show
// PUT /api/v1/pedidos/{id} → update
// DELETE /api/v1/pedidos/{id} → destroy
// PATCH /api/v1/pedidos/{id}/avanzar-estado → avanzarEstado
//
// FILTROS GET /api/v1/pedidos:
// ?estado= pendiente | preparando | listo | entregado
// ?mesa= número de mesa
// ?solo_activos=1 excluye entregados
// ?retrasados=1 superaron el tiempo estimado
// ?solo_hoy=1 solo pedidos del día
// ?con_productos=1 incluye las líneas de detalle
// ?por_pagina=15 registros por página
//
// FLUJO DE ESTADOS:
// pendiente → preparando → listo → entregado
// (saltar o retroceder devuelve HTTP 422)
// ============================================================
By purchasing this prompt, you agree to our terms of service
CLAUDE-4-6-SONNET
Save 4-6 hours of manual Laravel development.
Provide a plain text description of your data model
and get complete production-ready code instantly:
migrations, models, controllers, form requests,
API resources, routes and seeders.
Perfect for:
- Laravel developers building APIs or admin panels
- Teams that need consistent code structure
- Developers working on SaaS or CRM systems
What you get:
✓ Complete CRUD in minutes, not hours
✓ Laravel 11 best practices built-in
✓ Ready to run — just m
...more
Added 10 hours ago
