HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/be.naniguide.com/app/Http/Controllers/Refactor/Admin/InvoiceController.php
<?php

namespace App\Http\Controllers\Refactor\Admin;

use App\Dto\Refactor\Invoice\InvoiceListFilterDto;
use App\Http\Controllers\Controller;
use App\Http\Requests\Refactor\Admin\Invoice\ApproveInvoiceRequest;
use App\Http\Requests\Refactor\Admin\Invoice\DeleteInvoiceRequest;
use App\Http\Requests\Refactor\Admin\Invoice\ListInvoicesRequest;
use App\Http\Requests\Refactor\Admin\Invoice\RejectInvoiceRequest;
use App\Model\Invoice;
use App\Services\Admin\InvoiceService;
use App\Services\Subscription\SubscriptionManagementService;
use Illuminate\Http\Request;
use Validator;

/**
 * Thin controller — orchestration only.
 *
 * Layering: FormRequest (auth + validate) → DTO (typed transport)
 *         → InvoiceService (read aggregator)
 *         → SubscriptionManagementService (write side: approve / reject / delete)
 *         → view / JSON.
 */
class InvoiceController extends Controller
{
    public function index(Request $request, InvoiceService $service)
    {
        return view('refactor.pages.admin.invoices.index', [
            'stats'   => $service->dashboardStats(),
            'sidebar' => $service->sidebarStats(),
        ]);
    }

    public function listing(ListInvoicesRequest $request, InvoiceService $service)
    {
        $filter = InvoiceListFilterDto::fromRequest($request);

        return view('refactor.pages.admin.invoices._list', [
            'invoices' => $service->list($filter),
        ]);
    }

    public function approve(ApproveInvoiceRequest $request, $uid, SubscriptionManagementService $svc)
    {
        $invoice = Invoice::findByUid($uid);
        if ($invoice === null) {
            return response()->json(['message' => trans('refactor/admin_invoices.errors.not_found')], 404);
        }

        try {
            $svc->approvePendingInvoice($invoice);
            return response()->json([
                'status'  => 'success',
                'message' => trans('refactor/admin_invoices.flash.approved'),
            ]);
        } catch (\Throwable $e) {
            \Log::warning('Invoice approve failed', ['uid' => $uid, 'error' => $e->getMessage()]);
            return response()->json(['message' => $e->getMessage()], 400);
        }
    }

    /** GET — render the reject-invoice popup form. */
    public function rejectForm($uid)
    {
        $invoice = Invoice::findByUid($uid);
        if ($invoice === null) {
            return response()->json(['message' => trans('refactor/admin_invoices.errors.not_found')], 404);
        }
        return view('refactor.pages.admin.invoices.reject', ['invoice' => $invoice]);
    }

    /** POST — process the reject submission. RejectInvoiceRequest validates the body. */
    public function reject(RejectInvoiceRequest $request, $uid, SubscriptionManagementService $svc)
    {
        $invoice = Invoice::findByUid($uid);
        if ($invoice === null) {
            return response()->json(['message' => trans('refactor/admin_invoices.errors.not_found')], 404);
        }

        try {
            $svc->rejectInvoice($invoice, $request->input('reason'));
            return response()->json([
                'status'  => 'success',
                'message' => trans('refactor/admin_invoices.flash.rejected'),
            ]);
        } catch (\Throwable $e) {
            \Log::warning('Invoice reject failed', ['uid' => $uid, 'error' => $e->getMessage()]);
            return response()->json(['message' => $e->getMessage()], 400);
        }
    }

    public function logs(Request $request, $uid)
    {
        $invoice = Invoice::findByUid($uid);
        if ($invoice === null) {
            return response()->json(['message' => trans('refactor/admin_invoices.errors.not_found')], 404);
        }

        return view('refactor.pages.admin.invoices.logs', ['invoice' => $invoice]);
    }

    public function download(Request $request, $uid)
    {
        $invoice = Invoice::findByUid($uid);
        if ($invoice === null) {
            abort(404);
        }

        $pdf = $invoice->exportToPdf();

        return response($pdf, 200, [
            'Content-Type'        => 'application/pdf',
            'Content-Disposition' => 'inline; filename="invoice-' . $invoice->uid . '.pdf"',
        ]);
    }

    public function delete(DeleteInvoiceRequest $request, $uid)
    {
        $invoice = Invoice::findByUid($uid);
        if ($invoice === null) {
            return response()->json(['message' => trans('refactor/admin_invoices.errors.not_found')], 404);
        }

        // cancelInvoice runs each OrderItem handler's canCancel() guard then
        // refundItems() — both can throw business-rule exceptions (e.g.
        // SubscriptionNewHandler refuses to cancel a NEW sub's order). Without
        // catching, the admin only sees a 500 / "server error" and has no clue
        // why. Catch + surface the actual reason. Past incident (Konstantin,
        // 2026-05-14): admin tried to delete invoice → 500 with no message.
        try {
            app(\App\Library\OrderFulfillment\FulfillmentService::class)->cancelInvoice($invoice);
        } catch (\Throwable $e) {
            \Log::warning('admin.invoices.delete refused or failed', [
                'invoice_uid' => $invoice->uid,
                'admin_uid'   => $request->user()->admin->uid ?? null,
                'error'       => $e->getMessage(),
            ]);
            return response()->json([
                'status'  => 'error',
                'message' => trans('refactor/admin_invoices.errors.delete_failed', ['reason' => $e->getMessage()]),
            ], 422);
        }

        return response()->json([
            'status'  => 'success',
            'message' => trans('refactor/admin_invoices.flash.deleted'),
        ]);
    }

    public function customCreate(Request $request)
    {
        // View never existed in old codebase — redirect to invoices index.
        return redirect()->route('refactor.admin.invoices.index');
    }

    public function templateEdit(Request $request)
    {
        if ($request->isMethod('post')) {
            \App\Model\Setting::set('invoice.custom_template', $request->content);
            return response()->json([
                'status'  => 'success',
                'message' => trans('refactor/admin_invoices.flash.template_saved'),
            ]);
        }

        return view('refactor.pages.admin.invoices.template_edit');
    }
}