* * @version 1.0.0 */ class InvoiceRequest extends Model { protected $fillable = [ 'sale_id', 'client_id', 'status', 'requested_at', 'processed_at', 'processed_by', 'notes', 'invoice_xml_path', 'invoice_pdf_path', 'cfdi_uuid', ]; protected $casts = [ 'requested_at' => 'datetime', 'processed_at' => 'datetime', ]; /** * Atributos adicionales para serializar */ protected $appends = ['invoice_xml_url', 'invoice_pdf_url']; const STATUS_PENDING = 'pending'; const STATUS_PROCESSED = 'processed'; const STATUS_REJECTED = 'rejected'; public function sale() { return $this->belongsTo(Sale::class); } public function client() { return $this->belongsTo(Client::class); } public function processedBy() { return $this->belongsTo(User::class, 'processed_by'); } /** * Marcar como procesada */ public function markAsProcessed(int $userId, ?string $notes = null): bool { return $this->update([ 'status' => self::STATUS_PROCESSED, 'processed_at' => now(), 'processed_by' => $userId, 'notes' => $notes ?? $this->notes, ]); } /** * Marcar como rechazada */ public function markAsRejected(int $userId, ?string $notes = null): bool { return $this->update([ 'status' => self::STATUS_REJECTED, 'processed_at' => now(), 'processed_by' => $userId, 'notes' => $notes ?? $this->notes, ]); } /** * Obtener la URL completa del archivo XML */ public function getInvoiceXmlUrlAttribute() { if (!$this->invoice_xml_path) { return null; } return Storage::disk('public')->url($this->invoice_xml_path); } /** * Obtener la URL completa del archivo PDF */ public function getInvoicePdfUrlAttribute() { if (!$this->invoice_pdf_path) { return null; } return Storage::disk('public')->url($this->invoice_pdf_path); } }