Descripción: Se ha realizado una refactorización mayor del sistema de notificaciones y generación de comprobantes para eliminar dependencias legacy (Imagick/FTP) y modernizar la arquitectura. 🚀 Nuevas Características (Features) Microservicio PDF (pdf-cropper): Nuevo servicio en Python (FastAPI + Poppler) desplegado en Docker (Puerto 8050) para la conversión de PDF a Imagen. Reemplaza la librería Imagick de PHP, aislando el procesamiento pesado fuera del plugin. Modo Full: Garantiza la conversión del PDF completo respetando su relación de aspecto original (sin recortes ni "square crop"). Overlay de Texto: Capacidad nativa en el backend para sobreescribir texto dinámicamente (ej. cambiar "Tarjeta de crédito Stripe" por "OXXO Pay") basado en parámetros. Integración S3 / MinIO: Implementación de MinioStorageService . Los comprobantes (JPG) y Vouchers OXXO se suben automáticamente a MinIO en lugar de usar FTP. Generación de URLs públicas seguras. 🧹 Mantenimiento y Limpieza (Chores/Refactor) Limpieza Automática (Cleanup): Se implementó lógica para eliminar archivos temporales locales (PDFs descargados, JPGs generados) inmediatamente después de una subida exitosa a MinIO. Aplica tanto para comprobantes de pago como para Vouchers OXXO. Refactor ClientCallBellAPI : Eliminación de código muerto relacionado con FTP de WordPress. Implementación de cliente HTTP Guzzle para comunicación con pdf-cropper. Cache Busting: Se añade Timestamp al nombre de archivo (_time()) para evitar caché agresivo en WhatsApp/Navegadores. Detección de Método: Lógica preliminar para detectar "OXXO" o "Transferencia" en notas de pago y aplicar Overlay. Docker Infraestructura: Actualización de docker-compose.yml para incluir pdf-cropper. Instalación de fuentes (fonts-dejavu-core) para renderizado correcto de texto. 🐛 Correcciones (Bug Fixes) Fix Recorte de Imagen: Se eliminó la restricción de relación de aspecto 1:1 (cuadrado) que cortaba headers y footers en documentos rectangulares. Standardización de Notas: Actualización de AbstractStripeOperationsFacade para incluir explícitamente "OXXO" o "Transferencia" en las notas de pago de UCRM (preparación para lógica de plantillas).
235 lines
5.8 KiB
PHP
235 lines
5.8 KiB
PHP
<?php
|
|
namespace Aws;
|
|
|
|
use Aws\Api\ListShape;
|
|
use Aws\Api\MapShape;
|
|
use Aws\Api\Service;
|
|
use Aws\Api\Shape;
|
|
use Aws\Api\StructureShape;
|
|
use Closure;
|
|
|
|
/**
|
|
* Inspects command input values and casts them to their modeled type.
|
|
* This covers query compatible services which have migrated from query
|
|
* to JSON wire protocols.
|
|
*
|
|
* @internal
|
|
*/
|
|
class QueryCompatibleInputMiddleware
|
|
{
|
|
/** @var callable */
|
|
private $nextHandler;
|
|
|
|
/** @var Service */
|
|
private $service;
|
|
|
|
/** @var CommandInterface */
|
|
private $command;
|
|
|
|
/**
|
|
* Create a middleware wrapper function.
|
|
*
|
|
* @param Service $service
|
|
* @return Closure
|
|
*/
|
|
public static function wrap(Service $service) : Closure
|
|
{
|
|
return static function (callable $handler) use ($service) {
|
|
return new self($handler, $service);
|
|
};
|
|
}
|
|
|
|
public function __construct(callable $nextHandler, Service $service)
|
|
{
|
|
$this->service = $service;
|
|
$this->nextHandler = $nextHandler;
|
|
}
|
|
|
|
public function __invoke(CommandInterface $cmd)
|
|
{
|
|
$this->command = $cmd;
|
|
$nextHandler = $this->nextHandler;
|
|
$op = $this->service->getOperation($cmd->getName());
|
|
$inputMembers = $op->getInput()->getMembers();
|
|
$input = $cmd->toArray();
|
|
|
|
foreach ($input as $param => $value) {
|
|
if (isset($inputMembers[$param])) {
|
|
$shape = $inputMembers[$param];
|
|
$this->processInput($value, $shape, [$param]);
|
|
}
|
|
}
|
|
|
|
return $nextHandler($this->command);
|
|
}
|
|
|
|
/**
|
|
* Recurses a given input shape. if a given scalar input does not match its
|
|
* modeled type, it is cast to its modeled type.
|
|
*
|
|
* @param $input
|
|
* @param $shape
|
|
* @param array $path
|
|
*
|
|
* @return void
|
|
*/
|
|
private function processInput($input, $shape, array $path) : void
|
|
{
|
|
switch ($shape->getType()) {
|
|
case 'structure':
|
|
$this->processStructure($input, $shape, $path);
|
|
break;
|
|
case 'list':
|
|
$this->processList($input, $shape, $path);
|
|
break;
|
|
case 'map':
|
|
$this->processMap($input, $shape, $path);
|
|
break;
|
|
default:
|
|
$this->processScalar($input, $shape, $path);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array $input
|
|
* @param StructureShape $shape
|
|
* @param array $path
|
|
*
|
|
* @return void
|
|
*/
|
|
private function processStructure(
|
|
array $input,
|
|
StructureShape $shape,
|
|
array $path
|
|
) : void
|
|
{
|
|
foreach ($input as $param => $value) {
|
|
if ($shape->hasMember($param)) {
|
|
$memberPath = array_merge($path, [$param]);
|
|
$this->processInput($value, $shape->getMember($param), $memberPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array $input
|
|
* @param ListShape $shape
|
|
* @param array $path
|
|
*
|
|
* @return void
|
|
*/
|
|
private function processList(
|
|
array $input,
|
|
ListShape $shape,
|
|
array $path
|
|
) : void
|
|
{
|
|
foreach ($input as $param => $value) {
|
|
$memberPath = array_merge($path, [$param]);
|
|
$this->processInput($value, $shape->getMember(), $memberPath);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array $input
|
|
* @param MapShape $shape
|
|
* @param array $path
|
|
*
|
|
* @return void
|
|
*/
|
|
private function processMap(array $input, MapShape $shape, array $path) : void
|
|
{
|
|
foreach ($input as $param => $value) {
|
|
$memberPath = array_merge($path, [$param]);
|
|
$this->processInput($value, $shape->getValue(), $memberPath);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $input
|
|
* @param Shape $shape
|
|
* @param array $path
|
|
*
|
|
* @return void
|
|
*/
|
|
private function processScalar($input, Shape $shape, array $path) : void
|
|
{
|
|
$expectedType = $shape->getType();
|
|
|
|
if (!$this->isModeledType($input, $expectedType)) {
|
|
trigger_error(
|
|
"The provided type for `". implode(' -> ', $path) ."` value was `"
|
|
. (gettype($input) === 'double' ? 'float' : gettype($input)) . "`."
|
|
. " The modeled type is `{$expectedType}`.",
|
|
E_USER_WARNING
|
|
);
|
|
$value = $this->castValue($input, $expectedType);
|
|
$this->changeValueAtPath($path, $value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Modifies command in place
|
|
*
|
|
* @param array $path
|
|
* @param $newValue
|
|
*
|
|
* @return void
|
|
*/
|
|
private function changeValueAtPath(array $path, $newValue) : void
|
|
{
|
|
$commandRef = &$this->command;
|
|
|
|
foreach ($path as $segment) {
|
|
if (!isset($commandRef[$segment])) {
|
|
return;
|
|
}
|
|
$commandRef = &$commandRef[$segment];
|
|
}
|
|
$commandRef = $newValue;
|
|
}
|
|
|
|
/**
|
|
* @param $value
|
|
* @param $type
|
|
*
|
|
* @return bool
|
|
*/
|
|
private function isModeledType($value, $type) : bool
|
|
{
|
|
switch ($type) {
|
|
case 'string':
|
|
return is_string($value);
|
|
case 'integer':
|
|
case 'long':
|
|
return is_int($value);
|
|
case 'float':
|
|
return is_float($value);
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $value
|
|
* @param $type
|
|
*
|
|
* @return float|int|mixed|string
|
|
*/
|
|
private function castValue($value, $type)
|
|
{
|
|
switch ($type) {
|
|
case 'integer':
|
|
return (int) $value;
|
|
case 'long' :
|
|
return $value + 0;
|
|
case 'float':
|
|
return (float) $value;
|
|
case 'string':
|
|
return (string) $value;
|
|
default:
|
|
return $value;
|
|
}
|
|
}
|
|
}
|