Initial commit: Horux Backend API

- API REST para gestion de facturas electronicas mexicanas (CFDI)
- Laravel 9 con autenticacion OAuth 2.0 (Passport)
- Integracion con Syntage, Clerk y Facturama
- 30 modelos Eloquent, 39 controladores
- Documentacion completa en /docs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-18 07:44:29 +00:00
commit 61320b44d8
191 changed files with 22895 additions and 0 deletions

View File

@@ -0,0 +1,287 @@
<?php
namespace App\Http\Controllers;
use App\Models\InvoiceLine;
use App\Models\Invoice;
use App\Models\InvoiceRequest;
use App\Models\User;
use App\Models\Rfc;
use App\Models\InvoiceType;
use App\Models\PaymentType;
use App\Models\Status;
use Carbon\Carbon;
use App\Imports\LineItemsImport;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\RequestException;
class InvoiceLineController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}
public function obtenerLineasFacturas(Request $request)
{
$start = microtime(true);
set_time_limit(1800);
$user = $request->user();
//$user = User::where('email', strip_tags($request->email))->first();
$rfc = Rfc::where('rfc', strip_tags($request->rfc))->first();
$now = Carbon::now();
$invoice_request = InvoiceRequest::where('rfc_id', $rfc->id)->where('type', 'line')->first();
if ($invoice_request) {
$last_request = new Carbon($invoice_request->requested_at);
$min_days = ($last_request->diff($now)->days > 1) ? true : null;
} else {
$min_days = true;
$invoice_request = new InvoiceRequest();
}
if (in_array($rfc->id, $user->rfcs->pluck('id')->toArray()) && $min_days == true) {
$dataCounter = 1;
$arrayCount = 999;
$header_id = null;
do {
try {
if (isset($header_id) && $dataCounter >= $arrayCount) {
$dataCounter = 1;
// Realizar una petición GET con encabezados
$response = Http::withHeaders([
'accept' => 'application/ld+json',
'X-API-Key' => 'b16ec9be960cdf3a8302e92a7aec84d2'
])->get('https://api.syntage.com/taxpayers/'. $request->rfc .'/invoices/line-items?id[lt]='. $header_id .'&itemsPerPage=1000');
} else {
// Realizar una petición GET con encabezados
$response = Http::withHeaders([
'accept' => 'application/ld+json',
'X-API-Key' => 'b16ec9be960cdf3a8302e92a7aec84d2'
])->get('https://api.syntage.com/taxpayers/'. $request->rfc .'/invoices/line-items?itemsPerPage=1000');
}
// Verificar si la petición fue exitosa
if ($response->successful()) {
// Manejar la respuesta exitosa
$data = $response->json();
$invoiceLines = $data['hydra:member'];
$arrayCount = count($invoiceLines);
foreach ($invoiceLines as $invoiceLine_data) {
// code...
$invoiceLine = $this->setInvoiceLine($invoiceLine_data, $rfc);
$dataCounter++;
if ($dataCounter == 999) {
$header_id = $invoiceLine_data['id'];
}
}
$time = microtime(true) - $start;
} else {
// Manejar la respuesta fallida
return response()->json(['error' => 'Error al obtener los datos'], $response->status());
}
} catch (RequestException $e) {
// Manejar excepciones específicas de solicitudes HTTP
return response()->json(['error' => 'Excepción al obtener los datos: ' . $e->getMessage()], 500);
}
} while ($arrayCount >= 999);
$invoice_request->rfc_id = $rfc->id;
$invoice_request->type = 'line';
$invoice_request->requested_at = Carbon::now();
$invoice_request->save();
return response()->json(['success' => 'Datos almacenados con exito', 'time' => $time]);
} else {
$time = microtime(true) - $start;
return response()->json(['success' => 'Datos almacenados con exito', 'time' => $time]);
}
}
public function importarLineasFacturas(Request $request) {
// Validar que se ha subido un archivo y que es un Excel
$request->validate([
'file' => 'required|mimes:xlsx,xls,csv|max:20480', // Limitar el tamaño del archivo a 10MB
'rfc' => 'required|string', // Validación para el parámetro adicional
]);
$rfc = $request->rfc;
set_time_limit(1000);
//ini_set('memory_limit', '-1');
try {
// Procesar el archivo usando la clase de importación
Excel::import(new LineItemsImport($rfc), $request->file('file'));
return response()->json([
'success' => true,
'message' => 'Excel importado correctamente'
], 200);
} catch (\Exception $e) {
// Manejar errores durante la importación
return response()->json([
'success' => false,
'message' => 'Error al importar el archivo: ' . $e->getMessage()
], 500);
}
}
public function obtenerFacturasConceptos(Request $request) {
$user = $request->user();
//$user = User::where('email', strip_tags($request->email))->first();
$rfc = Rfc::where('rfc', strip_tags($request->rfc))->first();
if (in_array($rfc->id, $user->rfcs->pluck('id')->toArray())) {
return response()->json(Invoice::where('rfc_id', $rfc->id)->with('invoiceLines')->get());
}
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param \App\Models\InvoiceLine $invoiceLine
* @return \Illuminate\Http\Response
*/
public function show(InvoiceLine $invoiceLine)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\InvoiceLine $invoiceLine
* @return \Illuminate\Http\Response
*/
public function edit(InvoiceLine $invoiceLine)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\InvoiceLine $invoiceLine
* @return \Illuminate\Http\Response
*/
public function update(Request $request, InvoiceLine $invoiceLine)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\InvoiceLine $invoiceLine
* @return \Illuminate\Http\Response
*/
public function destroy(InvoiceLine $invoiceLine)
{
//
}
public function setInvoiceLine($invoiceLine_data, $rfc)
{
//
$invoiceLine = InvoiceLine::firstOrNew(['id' => $invoiceLine_data['id']]);
$invoiceLine->rfc_id = $rfc->id;
$invoice = Invoice::where('id', $invoiceLine_data['invoice']['uuid'])->first();
if($invoice) {
$invoiceLine->invoice_id = $invoiceLine_data['invoice']['uuid'];
} else {
$invoiceLine->invoice_id = null;
}
$type = InvoiceType::where('id', $invoiceLine_data['invoice']['type'])->first();
if (!$type) {
$type = new InvoiceType();
$type->id = $invoiceLine_data['invoice']['type'];
$type->save();
}
$invoiceLine->invoice_type_id = $invoiceLine_data['invoice']['type'];
if ($invoiceLine_data['invoice']['paymentType']) {
$payment_method = PaymentType::where('id', strip_tags($invoiceLine_data['invoice']['paymentType']))->first();
if (!$payment_method) {
$payment_method = new PaymentType();
$payment_method->id = $invoiceLine_data['invoice']['paymentType'];
$payment_method->save();
}
}
$invoiceLine->payment_type_id = $invoiceLine_data['invoice']['paymentType'];
if ($invoiceLine_data['invoice']['status']) {
$status = Status::where('description', strip_tags($invoiceLine_data['invoice']['status']))->first();
if (!$status) {
$status = new Status();
$status->description = $invoiceLine_data['invoice']['status'];
$status->save();
}
}
$invoiceLine->status_id = $status->id;
$rfc = Rfc::where('rfc', strip_tags($invoiceLine_data['invoice']['issuer']['rfc']))->first();
if (!$rfc) {
$rfc = new Rfc();
$rfc->rfc = $invoiceLine_data['invoice']['issuer']['rfc'];
$rfc->save();
}
$invoiceLine->issuer_rfc_id = $rfc->id;
$invoiceLine->issuer_name = $invoiceLine_data['invoice']['issuer']['name'];
$rfc = Rfc::where('rfc', strip_tags($invoiceLine_data['invoice']['receiver']['rfc']))->first();
if (!$rfc) {
$rfc = new Rfc();
$rfc->rfc = $invoiceLine_data['invoice']['receiver']['rfc'];
$rfc->save();
}
$invoiceLine->receiver_rfc_id = $rfc->id;
$invoiceLine->receiver_name = $invoiceLine_data['invoice']['receiver']['name'];
$invoiceLine->issued_at = Carbon::createFromFormat('Y-m-d H:i:s', $invoiceLine_data['invoice']['issuedAt']);
$invoiceLine->identification_number = $invoiceLine_data['identificationNumber'];
$invoiceLine->product_identification = $invoiceLine_data['productIdentification'];
$invoiceLine->description = $invoiceLine_data['description'];
$invoiceLine->description = $invoiceLine_data['description'];
$invoiceLine->unit_amount = $invoiceLine_data['unitAmount'];
$invoiceLine->unit_code = $invoiceLine_data['unitCode'];
$invoiceLine->quantity = $invoiceLine_data['quantity'];
$invoiceLine->discount_amount = $invoiceLine_data['discountAmount'];
$invoiceLine->total_amount = $invoiceLine_data['totalAmount'];
$invoiceLine->retained_vat = $invoiceLine_data['retainedTaxes']['valueAddedTax'];
$invoiceLine->retained_income_tax = $invoiceLine_data['retainedTaxes']['incomeTax'];
$invoiceLine->retained_sin_tax = $invoiceLine_data['retainedTaxes']['sinTax'];
$invoiceLine->transferred_vat = $invoiceLine_data['transferredTaxes']['valueAddedTax'];
$invoiceLine->transferred_sin_tax = $invoiceLine_data['transferredTaxes']['sinTax'];
$invoiceLine->save();
return $invoiceLine;
}
}