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');
}
}