pdv.backend/app/Http/Controllers/App/InvoiceController.php

180 lines
6.4 KiB
PHP

<?php
namespace App\Http\Controllers\App;
use App\Http\Controllers\Controller;
use App\Http\Requests\App\InvoiceStoreRequest;
use App\Models\Client;
use App\Models\InvoiceRequest;
use App\Models\Sale;
use Notsoweb\ApiResponse\Enums\ApiResponse;
class InvoiceController extends Controller
{
/**
* Muestra los datos de la venta para el formulario de facturación.
*/
public function show(string $invoiceNumber)
{
$sale = Sale::where('invoice_number', $invoiceNumber)
->with([
'client',
'details.inventory.category',
'details.serials',
'user:id,name,email',
'invoiceRequests' => function ($query) {
$query->orderBy('requested_at', 'desc');
},
])->first();
if (!$sale) {
return ApiResponse::NOT_FOUND->response([
'message' => 'Venta no encontrada'
]);
}
// Verificar si ya tiene solicitud pendiente o procesada
$existingRequest = $sale->invoiceRequests
->whereIn('status', [InvoiceRequest::STATUS_PENDING, InvoiceRequest::STATUS_PROCESSED])
->first();
if ($existingRequest) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'Esta venta ya tiene una solicitud de facturación ' .
($existingRequest->status === InvoiceRequest::STATUS_PENDING ? 'pendiente' : 'procesada'),
'invoice_request' => $existingRequest,
]);
}
return ApiResponse::OK->response([
'sale' => $this->formatSaleData($sale),
'client' => $sale->client,
'invoice_requests' => $sale->invoiceRequests,
]);
}
/**
* Guarda los datos fiscales del cliente para la venta.
*/
public function store(InvoiceStoreRequest $request, string $invoiceNumber)
{
$sale = Sale::where('invoice_number', $invoiceNumber)
->with('details.serials')
->first();
if (!$sale) {
return ApiResponse::INTERNAL_ERROR->response([
'message' => 'Venta no encontrada'
]);
}
$existingRequest = InvoiceRequest::where('sale_id', $sale->id)
->whereIn('status', [InvoiceRequest::STATUS_PENDING, InvoiceRequest::STATUS_PROCESSED])
->first();
if ($existingRequest) {
return ApiResponse::NO_CONTENT->response([
'message' => 'Esta venta ya tiene una solicitud de facturación ' .
($existingRequest->status === InvoiceRequest::STATUS_PENDING ? 'pendiente' : 'procesada')
]);
}
// Verificar que la venta esté completada
if ($sale->status !== 'completed') {
return ApiResponse::BAD_REQUEST->response([
'message' => 'Solo se pueden facturar ventas completadas'
]);
}
// Buscar si ya existe un cliente con ese RFC
$client = Client::where('rfc', strtoupper($request->rfc))->first();
if ($client) {
// Actualizar datos del cliente existente
$client->update([
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone ?? $client->phone,
'address' => $request->address ?? $client->address,
'razon_social' => $request->razon_social,
'regimen_fiscal' => $request->regimen_fiscal,
'cp_fiscal' => $request->cp_fiscal,
'uso_cfdi' => $request->uso_cfdi,
]);
} else {
// Crear nuevo cliente
$client = Client::create([
'name' => $request->name,
'client_number' => strtoupper($request->rfc),
'email' => $request->email,
'phone' => $request->phone,
'address' => $request->address,
'rfc' => strtoupper($request->rfc),
'razon_social' => $request->razon_social,
'regimen_fiscal' => $request->regimen_fiscal,
'cp_fiscal' => $request->cp_fiscal,
'uso_cfdi' => $request->uso_cfdi,
]);
}
// Asociar cliente a la venta
$sale->update(['client_id' => $client->id]);
// Recargar relaciones
$invoiceRequest = InvoiceRequest::create([
'sale_id' => $sale->id,
'client_id' => $client->id,
'status' => InvoiceRequest::STATUS_PENDING,
'requested_at' => now(),
]);
return ApiResponse::OK->response([
'message' => 'Solicitud de facturación guardada correctamente',
'client' => $client,
'sale' => $this->formatSaleData($sale),
'invoice_request' => $invoiceRequest,
]);
}
/**
* Formatear datos de la venta incluyendo números de serie
*/
private function formatSaleData(Sale $sale): array
{
return [
'id' => $sale->id,
'invoice_number' => $sale->invoice_number,
'total' => $sale->total,
'subtotal' => $sale->subtotal,
'tax' => $sale->tax,
'payment_method' => $sale->payment_method,
'status' => $sale->status,
'created_at' => $sale->created_at,
'user' => $sale->user ? [
'id' => $sale->user->id,
'name' => $sale->user->name,
'email' => $sale->user->email,
] : null,
'items' => $sale->details->map(function ($detail) {
return [
'id' => $detail->id,
'product_name' => $detail->product_name,
'quantity' => $detail->quantity,
'unit_price' => $detail->unit_price,
'subtotal' => $detail->subtotal,
'category' => $detail->inventory->category->name ?? null,
'sku' => $detail->inventory->sku ?? null,
// Números de serie vendidos
'serial_numbers' => $detail->serials->map(function ($serial) {
return [
'serial_number' => $serial->serial_number,
'status' => $serial->status,
];
})->toArray(),
];
})->toArray(),
];
}
}