<?php
namespace App\Controller\Api\Product;
use App\Application\Service\Product\ProductFinder;
use App\Application\Service\Product\ProductReseved;
use App\Entity\Idempiere\AdOrg;
use App\Repository\Idempiere\AdUserRepository;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
class GetProductForLocalTemplateController extends AbstractController
{
protected $requestStack;
protected $security;
private ProductFinder $productFinder;
private ProductReseved $productReseved;
public function __construct(
ProductFinder $productFinder,
RequestStack $requestStack,
Security $security,
ProductReseved $productReseved
) {
$this->productFinder = $productFinder;
$this->requestStack = $requestStack;
$this->security = $security;
$this->productReseved = $productReseved;
}
/**
* @Route("/api/products/", name="get_product_list", methods={"GET"})
*/
public function __invoke(
Request $request,
ManagerRegistry $manager
) {
// 1. Prepara los parámetros de la consulta a partir de la petición.
$draw = max(1, $request->query->getInt('draw', 1));
$page = max(0, $request->query->getInt('start', 0));
$limit = max(1, $request->query->getInt('length', 10));
$filters = $request->query->all();
$session = $this->requestStack->getSession();
$user = $this->security->getUser();
$organization = $session->get('organization');
$RUser = new AdUserRepository($manager);
$isSalesRep = false;
foreach ($RUser->findSalesrep('', $organization->getId()) as $salesRep) {
if ($salesRep->getName() == $user->getName()) {
$isSalesRep = true;
}
}
// 2. Delega la lógica de negocio al servicio de la aplicación.
$result = $this->productFinder->findProductsForTemplate($filters, $page, $limit);
$data = array_map(function ($e) use ($isSalesRep) {
$reserved = $this->productReseved->execute($e['m_product_id']);
$e['reserved'] = $reserved;
$e['available'] = $e['qty_function'];
$e['available'] -= $e['reserved_in_templates'];
$e['available'] += $e['on_arrive'];
$e['label'] = $this->setColor($e['available'], !$isSalesRep);
return $e;
}, $result['data']);
// 3. Serializa y devuelve la respuesta.
return new JsonResponse([
'draw' => $draw,
'recordsTotal' => $result['pagination']['total'],
"recordsFiltered" => $result['pagination']['total'],
'data' => $data
]);
}
private function setColor(int $value, bool $show = false): string
{
$state = 'off';
$label = 'Sin Stock';
if ($value > 500) {
$state = 'green';
$label = 'Disponible';
} elseif ($value >= 100) {
$state = 'yellow';
$label = 'Medio';
} elseif ($value >= 1) {
$state = 'red';
$label = 'Bajo';
}
$num = $show ? (string) $value : '';
return $this->renderSingleLight($state, $label, $num);
}
private function renderSingleLight(string $state, string $label, string $num = ''): string
{
$palette = [
'bg' => '#1f2937',
'stroke' => '#111827',
'off' => '#374151',
'red' => '#ef4444',
'yellow' => '#f59e0b',
'green' => '#10b981',
'numOff' => '#9ca3af',
'text' => '#111827',
];
// 1) Color de la luz
$fillMap = [
'red' => $palette['red'],
'yellow' => $palette['yellow'],
'green' => $palette['green'],
];
$fill = array_key_exists($state, $fillMap) ? $fillMap[$state] : $palette['off'];
// 2) Texto ARIA
$ariaMap = [
'red' => 'Semáforo: rojo activo',
'yellow' => 'Semáforo: amarillo activo',
'green' => 'Semáforo: verde activo',
];
$aria = array_key_exists($state, $ariaMap) ? $ariaMap[$state] : 'Semáforo apagado';
$numStyle = $state === 'off' ? "fill:{$palette['numOff']};" : "fill:#fff;";
$numText = $num !== ''
? '<text x="40" y="45" text-anchor="middle" dominant-baseline="middle" class="num" style="' . $numStyle . '">' . $num . '</text>'
: '';
return <<<SVG
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 120" width="80" height="120" role="img" aria-label="{$aria}, etiqueta {$label}">
<style>
.label{ font-family: system-ui, sans-serif; font-size: 12px; font-weight:700; }
.num{ font-family: system-ui, sans-serif; font-size:14px; font-weight:700; stroke:{$palette['stroke']}; stroke-width:.6; }
</style>
<!-- carcasa -->
<rect x="10" y="10" width="60" height="70" rx="12" fill="{$palette['bg']}" stroke="{$palette['stroke']}" stroke-width="2"/>
<!-- luz única -->
<circle cx="40" cy="45" r="18" fill="{$fill}" stroke="{$palette['stroke']}" stroke-width="2"/>
{$numText}
<!-- label -->
<text x="40" y="105" text-anchor="middle" class="label" fill="{$palette['text']}">{$label}</text>
</svg>
SVG;
}
}