Tul xxx Tul
User / IP
:
216.73.216.227
Host / Server
:
45.84.207.204 / aircan.me
System
:
Linux lt-bnk-web1726.main-hosting.eu 5.14.0-611.36.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Mar 3 11:23:52 EST 2026 x86_64
Command
|
Upload
|
Create
Mass Deface
|
Jumping
|
Symlink
|
Reverse Shell
Ping
|
Port Scan
|
DNS Lookup
|
Whois
|
Header
|
cURL
:
/
home
/
u931257429
/
domains
/
aircan.me
/
public_html
/
vendefacil2
/
controllers
/
Viewing: Ventas.php
<?php require 'vendor/autoload.php'; use Mike42\Escpos\Printer; use Mike42\Escpos\PrintConnectors\WindowsPrintConnector; use Dompdf\Dompdf; use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\Exception; class Ventas extends Controller { private $id_usuario, $id_sucursal; private function getFacturaStyles() { $cssPath = __DIR__ . '/../assets/css/factura.css'; if (!file_exists($cssPath)) { return ''; } $css = file_get_contents($cssPath); return $css !== false ? $css : ''; } private function getLogoDataUri() { $logoPath = __DIR__ . '/../assets/images/logo.png'; if (!file_exists($logoPath)) { return null; } $logo = file_get_contents($logoPath); if ($logo === false) { return null; } return 'data:image/png;base64,' . base64_encode($logo); } public function __construct() { parent::__construct(); session_start(); if (empty($_SESSION['id_usuario'])) { header('Location: ' . BASE_URL); exit; } $this->id_usuario = $_SESSION['id_usuario']; $this->id_sucursal = $_SESSION['id_sucursal']; } private function cantidadEnCarrito($idProducto, $loteId = null) { $cantidad = 0; if (empty($_SESSION['ventas'])) { return $cantidad; } foreach ($_SESSION['ventas'] as $item) { if ((int)$item['id'] !== (int)$idProducto || (int)$item['caja_id'] !== 0) { continue; } if ($loteId !== null && (int)($item['lote_id'] ?? 0) !== (int)$loteId) { continue; } $cantidad += (float)($item['quantity'] ?? 0); } return $cantidad; } private function lotesDisponiblesProducto($idProducto) { $lotes = $this->model->getLotesProducto($idProducto, $this->id_sucursal); foreach ($lotes as &$lote) { $enCarrito = $this->cantidadEnCarrito($idProducto, $lote['id']); $lote['cantidad_real'] = (float)$lote['cantidad']; $lote['cantidad'] = max(0, (float)$lote['cantidad'] - $enCarrito); $lote['en_carrito'] = $enCarrito; } unset($lote); return $lotes; } private function precioVentaInicial($producto) { $preciosVenta = json_decode($producto['precio_venta'], true); if (!is_array($preciosVenta) || empty($preciosVenta)) { $preciosVenta = [['nombre' => 'Precio default', 'monto' => 0]]; } return [$preciosVenta, $preciosVenta[0]]; } public function index() { if (!verificar('crear_ventas')) { header('Location: ' . BASE_URL . 'admin/permisos'); exit; } $data['title'] = 'Ventas'; $data['body_class'] = 'pos-mode'; $data['script'] = 'ventas.js'; $data['busqueda'] = 'busqueda.js'; $data['carrito'] = 'posVenta'; $data['modal'] = 'venta.php'; $data['identidades'] = $this->model->getIdentidades(); $data['formapagos'] = $this->model->getFormaPagos(); $data['empresa'] = $this->model->getEmpresa($this->id_sucursal); $resultSerie = $this->model->getSerie($this->id_sucursal); $serie = ($resultSerie['total'] == null) ? 1 : $resultSerie['total'] + 1; $data['serie'] = generate_numbers($serie, 1, 8); unset($_SESSION['ventas']); $this->views->getView('ventas', 'index', $data); } public function addProduct($idProducto) { if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { if (is_numeric($idProducto)) { $producto = $this->model->getProducto($idProducto); if (!$producto) { echo json_encode(['icono' => 'error', 'msg' => 'Producto no encontrado'], JSON_UNESCAPED_UNICODE); die(); } $descuento = 0; $cantidad = 1; $caja = 0; if ((int)$producto['servicio'] === 0) { $lotes = $this->lotesDisponiblesProducto($idProducto); if (!empty($lotes)) { $lotesDisponibles = array_values(array_filter($lotes, function ($lote) { return (float)$lote['cantidad'] > 0; })); if (empty($lotesDisponibles)) { echo json_encode(['icono' => 'error', 'msg' => 'Stock insuficiente para los lotes de este producto.'], JSON_UNESCAPED_UNICODE); die(); } echo json_encode([ 'icono' => 'info', 'msg' => 'Selecciona el vencimiento del producto.', 'requiere_lote' => true, 'producto' => [ 'id' => (int)$producto['id'], 'descripcion' => $producto['descripcion'], 'cantidad' => (float)$producto['cantidad'] ], 'lotes' => $lotesDisponibles ], JSON_UNESCAPED_UNICODE); die(); } } // Si el producto NO es servicio, validar stock considerando el carrito if ($producto['servicio'] == 0) { $cantidadEnCarrito = $this->cantidadEnCarrito($idProducto); if (!empty($_SESSION['ventas'])) { foreach ($_SESSION['ventas'] as $item) { if ($item['id'] == $idProducto && $item['caja_id'] == 0) { // caja_id según tu lógica $cantidadEnCarrito = $item['quantity']; break; } } } if ($producto['cantidad'] < ($cantidadEnCarrito + $cantidad)) { echo json_encode(['icono' => 'error', 'msg' => 'Stock insuficiente'], JSON_UNESCAPED_UNICODE); die(); } } [$preciosVenta, $precioSeleccionado] = $this->precioVentaInicial($producto); $foto = empty($producto['foto']) ? 'assets/images/productos/default.png' : $producto['foto']; $res = addToCartCaja( 'ventas', $idProducto, $producto['descripcion'], $precioSeleccionado['monto'], $descuento, $cantidad, $caja, $preciosVenta, $precioSeleccionado, $foto ); echo json_encode($res, JSON_UNESCAPED_UNICODE); die(); } } } public function addProductLote() { if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { $json = file_get_contents('php://input'); $data = json_decode($json, true); $idProducto = isset($data['id_producto']) ? (int)$data['id_producto'] : 0; $idLote = isset($data['id_lote']) ? (int)$data['id_lote'] : 0; $cantidad = isset($data['cantidad']) ? max(1, (float)$data['cantidad']) : 1; if ($idProducto <= 0 || $idLote <= 0) { echo json_encode(['icono' => 'warning', 'msg' => 'Selecciona un vencimiento valido.'], JSON_UNESCAPED_UNICODE); die(); } $producto = $this->model->getProducto($idProducto); $lote = $this->model->getLoteProducto($idLote, $idProducto, $this->id_sucursal); if (!$producto || !$lote || (int)$producto['servicio'] === 1) { echo json_encode(['icono' => 'error', 'msg' => 'Lote no disponible para este producto.'], JSON_UNESCAPED_UNICODE); die(); } $cantidadEnCarrito = $this->cantidadEnCarrito($idProducto, $idLote); if ((float)$lote['cantidad'] < ($cantidadEnCarrito + $cantidad)) { echo json_encode(['icono' => 'error', 'msg' => 'Stock insuficiente para ese vencimiento.'], JSON_UNESCAPED_UNICODE); die(); } [$preciosVenta, $precioSeleccionado] = $this->precioVentaInicial($producto); $foto = empty($producto['foto']) ? 'assets/images/productos/default.png' : $producto['foto']; $res = addToCartCaja( 'ventas', $idProducto, $producto['descripcion'], $precioSeleccionado['monto'], 0, $cantidad, 0, $preciosVenta, $precioSeleccionado, $foto, [ 'lote_id' => $idLote, 'lote_fecha_vencimiento' => $lote['fecha_vencimiento'], 'lote_stock' => (float)$lote['cantidad'] ] ); echo json_encode($res, JSON_UNESCAPED_UNICODE); die(); } } public function listarTbl($table) { $data['productos'] = $_SESSION[$table] ?? []; for ($i = 0; $i < count($data['productos']); $i++) { if (empty($data['productos'][$i]['foto'])) { $p = $this->model->getProducto($data['productos'][$i]['id']); $data['productos'][$i]['foto'] = empty($p['foto']) ? 'assets/images/productos/default.png' : $p['foto']; } } // Ordenar por timestamp descendente (si existe timestamp) usort($data['productos'], function ($a, $b) { return ($b['timestamp'] ?? 0) <=> ($a['timestamp'] ?? 0); }); $total = 0; foreach ($data['productos'] as $p) { $monto = isset($p['precio_seleccionado']['monto']) ? $p['precio_seleccionado']['monto'] : $p['price']; $cantidad = $p['quantity'] ?? 1; $total += $monto * $cantidad; } $data['total'] = number_format($total, 2, '.', ''); echo json_encode($data, JSON_UNESCAPED_UNICODE); die(); } public function cambiarPrecio() { if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { $json = file_get_contents('php://input'); $data = json_decode($json, true); // Decodificar 'item' que es un JSON string if (isset($data['item'])) { $precio = json_decode($data['item'], true); } else { $precio = null; } if (is_array($data) && isset($data['id_producto']) && is_array($precio)) { $loteId = isset($data['lote_id']) ? (int)$data['lote_id'] : null; $res = updatePriceCaja('ventas', $data['id_producto'], $precio, 0, $loteId); echo json_encode($res, JSON_UNESCAPED_UNICODE); } else { echo json_encode(['icono' => 'warning', 'msg' => 'Datos inválidos']); } } die(); } public function cambiarCantidad() { if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { $json = file_get_contents('php://input'); $data = json_decode($json, true); if (is_array($data) && isset($data['id_producto'], $data['item'])) { $cantidadSolicitada = max(1, intval($data['item'])); // Recuperar producto del modelo $producto = $this->model->getProducto($data['id_producto']); if (!$producto) { echo json_encode(['icono' => 'error', 'msg' => 'Producto no encontrado'], JSON_UNESCAPED_UNICODE); die(); } // Si NO es servicio, validar stock $loteId = isset($data['lote_id']) ? (int)$data['lote_id'] : null; if ($producto['servicio'] == 0) { if (!empty($loteId)) { $lote = $this->model->getLoteProducto($loteId, $data['id_producto'], $this->id_sucursal); if (!$lote || (float)$lote['cantidad'] < $cantidadSolicitada) { echo json_encode(['icono' => 'error', 'msg' => 'Stock insuficiente para ese vencimiento'], JSON_UNESCAPED_UNICODE); die(); } } else if ($producto['cantidad'] < $cantidadSolicitada) { echo json_encode(['icono' => 'error', 'msg' => 'Stock insuficiente'], JSON_UNESCAPED_UNICODE); die(); } } // Actualizar cantidad en carrito $res = updateCantidadCaja('ventas', $data['id_producto'], $cantidadSolicitada, 0, $loteId); echo json_encode($res, JSON_UNESCAPED_UNICODE); } else { echo json_encode(['icono' => 'warning', 'msg' => 'Datos inválidos']); } } die(); } public function eliminarProducto() { if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { $json = file_get_contents('php://input'); $data = json_decode($json, true); if (is_array($data) && isset($data['id_producto'])) { $loteId = isset($data['lote_id']) ? (int)$data['lote_id'] : null; $res = removeFromCartCaja('ventas', $data['id_producto'], 0, $loteId); echo json_encode($res, JSON_UNESCAPED_UNICODE); } else { echo json_encode(['icono' => 'warning', 'msg' => 'Datos inválidos']); } } die(); } public function historial() { if (!verificar('ver_ventas')) { header('Location: ' . BASE_URL . 'admin/permisos'); exit; } $data['title'] = 'Historial ventas'; $data['script'] = 'historial-ventas.js'; $this->views->getView('ventas', 'historial', $data); } public function edit($id) { if (!verificar('editar_ventas')) { header('Location: ' . BASE_URL . 'admin/permisos'); exit; } $venta = $this->model->getVentaBySucursal($id, $this->id_sucursal); if (empty($venta)) { header('Location: ' . BASE_URL . 'ventas/historial'); exit; } $data['title'] = 'Editar Venta'; $data['body_class'] = 'pos-mode'; $data['script'] = 'ventas.js'; $data['busqueda'] = 'busqueda.js'; $data['carrito'] = 'posVenta'; $data['modal'] = 'venta.php'; $data['identidades'] = $this->model->getIdentidades(); $data['formapagos'] = $this->model->getFormaPagos(); $data['empresa'] = $this->model->getEmpresa($this->id_sucursal); $data['ventaEdit'] = $venta; $data['pagosVenta'] = $this->model->getEfectivos($id); $data['serie'] = [$venta['serie']]; unset($_SESSION['ventas']); $productos = (empty($venta['productos'])) ? [] : json_decode($venta['productos'], true); $descuento = 0; $caja = 0; foreach ($productos as $item) { $producto = $this->model->getProducto($item['id']); $preciosVenta = json_decode($producto['precio_venta'], true) ?: []; $precioSeleccionado = null; foreach ($preciosVenta as $pv) { if ($pv['monto'] == $item['precio']) { $precioSeleccionado = $pv; break; } } if (!$precioSeleccionado && !empty($preciosVenta)) { $precioSeleccionado = $preciosVenta[0]; } $extra = []; if (!empty($item['lote_id'])) { $extra = [ 'lote_id' => (int)$item['lote_id'], 'lote_fecha_vencimiento' => $item['fecha_vencimiento'] ?? null ]; } addToCartCaja( 'ventas', $item['id'], $item['nombre'], $item['precio'], $descuento, $item['cantidad'], $caja, $preciosVenta, $precioSeleccionado, null, $extra ); } $this->views->getView('ventas', 'index', $data); } public function getEfectivos($id_venta) { $data['pagos'] = $this->model->getEfectivos($id_venta); echo json_encode($data, JSON_UNESCAPED_UNICODE); exit; } private function calcularTotal(array $productos): float { $total = 0; foreach ($productos as $producto) { $total += $producto['price'] * $producto['quantity']; } return $total; } private function procesarProductos(array $productos): array { $resultados = []; $hoy = date('Y-m-d'); foreach ($productos as $producto) { $result = $this->model->getProducto($producto['id']); $garantia_valor = !empty($result['garantia_valor']) ? (int)$result['garantia_valor'] : 0; $garantia_tipo = !empty($result['garantia_tipo']) ? $result['garantia_tipo'] : 'ninguna'; $garantia_fin = null; if ($garantia_valor > 0 && $garantia_tipo !== 'ninguna') { $dt = new DateTime($hoy); switch ($garantia_tipo) { case 'dias': $dt->modify("+{$garantia_valor} days"); break; case 'meses': $dt->modify("+{$garantia_valor} months"); break; case 'anios': $dt->modify("+{$garantia_valor} years"); break; } $garantia_fin = $dt->format('Y-m-d'); } $resultados[] = [ 'id' => $result['id'], 'nombre' => $result['descripcion'] . ' - ' . $result['marca'], 'precio' => $producto['price'], 'cantidad' => $producto['quantity'], 'garantia_valor' => $garantia_valor > 0 ? $garantia_valor : null, 'garantia_tipo' => $garantia_tipo !== 'ninguna' ? $garantia_tipo : null, 'garantia_inicio' => ($garantia_fin ? $hoy : null), 'garantia_fin' => $garantia_fin, 'lote_id' => !empty($producto['lote_id']) ? (int)$producto['lote_id'] : null, 'fecha_vencimiento' => !empty($producto['lote_fecha_vencimiento']) ? $producto['lote_fecha_vencimiento'] : null, ]; } return $resultados; } private function actualizarStockYRegistrarMovimientos(array $productos, int $ventaId) { foreach ($productos as $producto) { $result = $this->model->getProducto($producto['id']); if ((int)$result['servicio'] === 1) { continue; } $cantidadVendida = (float)$producto['quantity']; $loteId = !empty($producto['lote_id']) ? (int)$producto['lote_id'] : 0; $fechaLote = $producto['lote_fecha_vencimiento'] ?? null; if ($loteId > 0) { $this->model->descontarLote($loteId, $cantidadVendida); $stockSincronizado = $this->model->sincronizarStockProducto($result['id'], $this->id_sucursal); $nuevaCantidad = $stockSincronizado['total']; } else { $nuevaCantidad = $result['cantidad'] - $cantidadVendida; } $totalVentas = $result['ventas'] + $cantidadVendida; if ($result['servicio'] == 0) { $this->model->actualizarStock($nuevaCantidad, $totalVentas, $result['id']); } $movimiento = 'Venta N°: ' . $ventaId; if (!empty($fechaLote)) { $movimiento .= ' - Vence: ' . date('d/m/Y', strtotime($fechaLote)); } $this->model->registrarMovimiento( $movimiento, 'salida', $cantidadVendida, $nuevaCantidad, $producto['id'], $this->id_usuario, $this->id_sucursal ); } } private function generarSerie(int $sucursalId): string { $resultSerie = $this->model->getSerie($sucursalId); $numSerie = ($resultSerie['total'] == null) ? 1 : $resultSerie['total'] + 1; return generate_numbers($numSerie, 1, 8)[0]; } private function sendResponse(string $msg, string $type, array $data = []) { echo json_encode(array_merge(['msg' => $msg, 'type' => $type], $data)); die(); } public function registrarVenta() { $json = file_get_contents('php://input'); $datos = json_decode($json, true); $array['productos'] = $_SESSION['ventas'] ?? []; if (empty($array['productos'])) { $this->sendResponse('CARRITO VACÍO', 'warning'); } $metodo = $datos['metodo'] ?? null; $idCliente = (empty($datos['idCliente'])) ? null : $datos['idCliente']; $nota = !empty($datos['nota']) ? $datos['nota'] : null; $idVendedor = !empty($datos['id_vendedor']) ? (int)$datos['id_vendedor'] : null; $idPrefactura = !empty($datos['id_prefactura']) ? (int)$datos['id_prefactura'] : null; if (empty($metodo)) { $this->sendResponse('EL MÉTODO ES REQUERIDO', 'warning'); } $pagos = (isset($datos['pagos']) && is_array($datos['pagos'])) ? $datos['pagos'] : []; if (empty($pagos) && $metodo == 'CONTADO') { $msg = array('msg' => 'Debes seleccionar al menos una forma de pago', 'icono' => 'warning'); echo json_encode($msg, JSON_UNESCAPED_UNICODE); exit; } if ($metodo == 'CREDITO' && is_null($idCliente)) { $msg = array('msg' => 'El cliente es requerido para pagos a crédito', 'icono' => 'warning'); echo json_encode($msg, JSON_UNESCAPED_UNICODE); exit; } $pagoCon = 0; $devuelta = 0; foreach ($pagos as $pago) { $devuelta += $pago['devuelta']; $pagoCon += $pago['monto']; } $descuento = (!empty($datos['descuento'])) ? floatval($datos['descuento']) : 0; $totalBruto = $this->calcularTotal($array['productos']); // Validar descuento negativo if ($descuento < 0) { $this->sendResponse('EL DESCUENTO NO PUEDE SER NEGATIVO', 'warning'); } // Validar que descuento no sea mayor al total if ($descuento > $totalBruto) { $this->sendResponse('EL DESCUENTO NO PUEDE SER MAYOR AL TOTAL', 'warning'); } $impuesto = (!empty($datos['impuesto'])) ? $datos['impuesto'] : 0; $empresa = $this->model->getEmpresa($this->id_sucursal); $totalNeto = $totalBruto - $descuento; $impuestoValor = isset($datos['impuesto_valor']) ? (float)$datos['impuesto_valor'] : null; $retencionMonto = isset($datos['retencion']) ? (float)$datos['retencion'] : 0.0; if ($retencionMonto < 0) { $retencionMonto = 0.0; } $ivaMonto = 0.0; if ($impuesto == 1) { if ($impuestoValor !== null && $impuestoValor >= 0) { $ivaMonto = $impuestoValor; $totalConImpuesto = $totalNeto + $ivaMonto; } else { $ivaMonto = $totalNeto * ($empresa['impuesto'] / 100); $totalConImpuesto = $totalNeto + $ivaMonto; } } else { $totalConImpuesto = $totalNeto; } $totalFinal = $totalConImpuesto - $retencionMonto; if ($totalFinal < 0) { $totalFinal = 0; } if ($metodo === 'CONTADO' && $pagoCon < $totalFinal) { $this->sendResponse('El pago debe ser mayor o igual al total final', 'warning'); } $verificarCaja = $this->model->getCaja($this->id_sucursal); if (empty($verificarCaja)) { $this->sendResponse('LA CAJA ESTÁ CERRADA', 'warning'); } $fecha = date('Y-m-d'); $hora = date('H:i:s'); $moneda = MONEDA; $serie = $this->generarSerie($this->id_sucursal); $id_caja = $verificarCaja['id']; $datosProductos = json_encode($this->procesarProductos($array['productos'])); $venta = $this->model->registrarVenta( $datosProductos, $totalNeto, $totalConImpuesto, $fecha, $hora, $metodo, $descuento, $ivaMonto, $retencionMonto, $totalFinal, $impuesto, $moneda, $serie, $pagoCon, $id_caja, $idCliente, $this->id_usuario, $this->id_sucursal, $nota, $idVendedor ); if ($venta > 0) { if ($idPrefactura > 0) { $this->model->marcarPrefacturaFacturada($idPrefactura); } $this->actualizarStockYRegistrarMovimientos($array['productos'], $venta); // Registrar pagos foreach ($pagos as $pago) { $this->model->registrarPagoVenta( $venta, $pago['formapago_id'], $pago['monto'], $pago['cobrado'], $pago['devuelta'], $pago['referencia'], $fecha ); } if ($metodo === 'CREDITO') { $this->model->registrarCredito($totalFinal, $fecha, $hora, $venta); } if (!empty($datos['impresion'])) { $this->impresionDirecta($venta); } unset($_SESSION['ventas']); $this->sendResponse('VENTA GENERADA', 'success', ['idVenta' => $venta]); } else { $this->sendResponse('ERROR AL GENERAR VENTA', 'error'); } } public function modificarVenta() { if (verificar('editar_ventas')) { $json = file_get_contents('php://input'); $datos = json_decode($json, true); $array['productos'] = $_SESSION['ventas'] ?? []; if (empty($array['productos'])) { $this->sendResponse('CARRITO VACÍO', 'warning'); } $metodo = $datos['metodo'] ?? null; $idCliente = (empty($datos['idCliente'])) ? null : $datos['idCliente']; $nota = !empty($datos['nota']) ? $datos['nota'] : null; $id_venta = !empty($datos['id_venta']) ? $datos['id_venta'] : null; if (is_null($id_venta)) { $this->sendResponse('VENTA NO ENCONTRADA', 'warning'); } if (empty($metodo)) { $this->sendResponse('EL MÉTODO ES REQUERIDO', 'warning'); } $pagos = (isset($datos['pagos']) && is_array($datos['pagos'])) ? $datos['pagos'] : []; if (empty($pagos) && $metodo == 'CONTADO') { $msg = array('msg' => 'Debes seleccionar al menos una forma de pago', 'icono' => 'warning'); echo json_encode($msg, JSON_UNESCAPED_UNICODE); exit; } if ($metodo == 'CREDITO' && is_null($idCliente)) { $msg = array('msg' => 'El cliente es requerido para pagos a crédito', 'icono' => 'warning'); echo json_encode($msg, JSON_UNESCAPED_UNICODE); exit; } $pagoCon = 0; $devuelta = 0; foreach ($pagos as $pago) { $devuelta += $pago['devuelta']; $pagoCon += $pago['monto']; } $descuento = (!empty($datos['descuento'])) ? floatval($datos['descuento']) : 0; $totalBruto = $this->calcularTotal($array['productos']); // Validar descuento negativo if ($descuento < 0) { $this->sendResponse('EL DESCUENTO NO PUEDE SER NEGATIVO', 'warning'); } // Validar que descuento no sea mayor al total if ($descuento > $totalBruto) { $this->sendResponse('EL DESCUENTO NO PUEDE SER MAYOR AL TOTAL', 'warning'); } $moneda = MONEDA; $impuesto = (!empty($datos['impuesto'])) ? $datos['impuesto'] : 0; $totalNeto = $totalBruto - $descuento; $impuestoValor = isset($datos['impuesto_valor']) ? (float)$datos['impuesto_valor'] : null; $retencionMonto = isset($datos['retencion']) ? (float)$datos['retencion'] : 0.0; if ($retencionMonto < 0) { $retencionMonto = 0.0; } $ivaMonto = 0.0; if ($impuesto == 1) { if ($impuestoValor !== null && $impuestoValor >= 0) { $ivaMonto = $impuestoValor; $totalConImpuesto = $totalNeto + $ivaMonto; } else { $empresa = $this->model->getEmpresa($this->id_sucursal); $ivaMonto = $totalNeto * ($empresa['impuesto'] / 100); $totalConImpuesto = $totalNeto + $ivaMonto; } } else { $totalConImpuesto = $totalNeto; } $totalFinal = $totalConImpuesto - $retencionMonto; if ($totalFinal < 0) { $totalFinal = 0; } // Validar pago negativo if ($pagoCon < 0) { echo json_encode(['msg' => 'EL PAGO NO PUEDE SER NEGATIVO', 'type' => 'warning']); die(); } // Validar pago suficiente para CONTADO if ($metodo === 'CONTADO' && $pagoCon < $totalFinal) { echo json_encode(['msg' => 'El pago debe ser mayor o igual al total con descuento', 'type' => 'warning']); die(); } $verificarCaja = $this->model->getCaja($this->id_sucursal); if (empty($verificarCaja)) { echo json_encode(['msg' => 'LA CAJA ESTÁ CERRADA', 'type' => 'warning']); die(); } // Proceder con modificación $resultVenta = $this->model->getVenta($id_venta); $datosProductos = json_encode($this->procesarProductos($array['productos'])); $formapago_id = null; $venta = $this->model->modificarVenta($datosProductos, $totalNeto, $totalConImpuesto, $metodo, $descuento, $ivaMonto, $retencionMonto, $totalFinal, $impuesto, $moneda, $pagoCon, $idCliente, $this->id_usuario, $formapago_id, $nota, $id_venta); if ($venta > 0) { // Reponer stock anterior $dataAnterior = ($resultVenta['productos'] != null) ? json_decode($resultVenta['productos'], true) : []; foreach ($dataAnterior as $producto) { $result = $this->model->getProducto($producto['id']); if ((int)$result['servicio'] === 1) { continue; } $cantidadAnterior = (float)$producto['cantidad']; $loteIdAnterior = !empty($producto['lote_id']) ? (int)$producto['lote_id'] : 0; if ($loteIdAnterior > 0) { $this->model->reponerLote($loteIdAnterior, $cantidadAnterior); $stockSincronizado = $this->model->sincronizarStockProducto($result['id'], $this->id_sucursal); $nuevaCantidad = $stockSincronizado['total']; } else { $nuevaCantidad = $result['cantidad'] + $cantidadAnterior; } $totalVentas = $result['ventas'] - $cantidadAnterior; $this->model->actualizarStock($nuevaCantidad, $totalVentas, $result['id']); } // Descontar nuevo stock foreach ($array['productos'] as $producto) { $result = $this->model->getProducto($producto['id']); if ((int)$result['servicio'] === 1) { continue; } $cantidad = (float)$producto['quantity']; $loteId = !empty($producto['lote_id']) ? (int)$producto['lote_id'] : 0; if ($loteId > 0) { $this->model->descontarLote($loteId, $cantidad); $stockSincronizado = $this->model->sincronizarStockProducto($result['id'], $this->id_sucursal); $nuevaCantidad = $stockSincronizado['total']; } else { $nuevaCantidad = $result['cantidad'] - $cantidad; } $totalVentas = $result['ventas'] + $cantidad; $this->model->actualizarStock($nuevaCantidad, $totalVentas, $result['id']); $movimiento = 'Editar Venta N°: ' . $venta; $this->model->registrarMovimiento($movimiento, 'salida', $cantidad, $nuevaCantidad, $producto['id'], $this->id_usuario, $this->id_sucursal); } //ELIMINAR PAGO ANTERIOR $this->model->eliminarPagoAnterior($id_venta); // Registrar pagos foreach ($pagos as $pago) { $this->model->registrarPagoVenta( $venta, $pago['formapago_id'], $pago['monto'], $pago['cobrado'], $pago['devuelta'], $pago['referencia'], date('Y-m-d') ); } if ($metodo == 'CREDITO') { $credito = $this->model->getCredito($id_venta); $monto = $totalFinal; $this->model->actualizarCredito($monto, $credito['id']); } if (!empty($datos['impresion'])) { $this->impresionDirecta($venta); } echo json_encode(['msg' => 'VENTA MODIFICADA', 'type' => 'success', 'idVenta' => $id_venta]); } else { echo json_encode(['msg' => 'ERROR AL MODIFICAR VENTA', 'type' => 'error']); } } else { echo json_encode(['msg' => 'NO TIENES PERMISO PARA EDITAR VENTAS', 'type' => 'warning']); } die(); } public function reporte($datos) { $array = explode(',', $datos); $tipo = $array[0] ?? 'factura'; $idVenta = $array[1] ?? 0; $data['title'] = 'Reporte'; $data['empresa'] = $this->model->getEmpresa($this->id_sucursal); $data['venta'] = $this->model->getVenta($idVenta); $data['efectivos'] = $this->model->getEfectivos($idVenta); $data['inline_css'] = $this->getFacturaStyles(); $data['logo'] = $this->getLogoDataUri(); if (!empty($data['venta'])) { $data['venta']['moneda'] = MONEDA; } if (empty($data['venta'])) { echo 'Pagina no Encontrada'; exit; } if ($tipo !== 'ticked' && $tipo !== 'factura') { $tipo = 'factura'; } if (empty($data['empresa']) || !is_array($data['empresa'])) { $data['empresa'] = [ 'nombre' => '', 'ruc' => '', 'telefono' => '', 'direccion' => '', 'mensaje' => '', 'impuesto' => 0 ]; } if (empty($data['efectivos']) || !is_array($data['efectivos'])) { $data['efectivos'] = []; } $data['barcode'] = null; try { $generator = new Picqer\Barcode\BarcodeGeneratorPNG(); $barcode = $generator->getBarcode('v' . $data['venta']['serie'], $generator::TYPE_CODE_128, 1, 30); $data['barcode'] = 'data:image/png;base64,' . base64_encode($barcode); } catch (\Throwable $e) { error_log('Error generando barcode de venta ID ' . $idVenta . ': ' . $e->getMessage()); } ob_start(); $this->views->getView('ventas', $tipo, $data); $html = ob_get_clean(); try { $dompdf = new Dompdf(); $options = $dompdf->getOptions(); $options->set('isJavascriptEnabled', true); $options->set('isRemoteEnabled', true); $options->set('isHtml5ParserEnabled', true); $dompdf->setOptions($options); $dompdf->loadHtml($html); if ($tipo == 'ticked') { $ticket = TICKETVENTA; $width_mm = $ticket['width'] - 10; $height_mm = $ticket['height']; $width_pt = mmToPoints($width_mm); $height_pt = mmToPoints($height_mm); $dompdf->setPaper([0, 0, $width_pt, $height_pt]); } else { $dompdf->setPaper('A4', 'vertical'); } $dompdf->render(); $dompdf->stream('reporte.pdf', ['Attachment' => false]); } catch (\Throwable $e) { error_log('Error generando reporte de venta ID ' . $idVenta . ': ' . $e->getMessage()); if (!headers_sent()) { header('Content-Type: text/html; charset=UTF-8'); } echo $html; } } public function listar() { $fechaInicio = !empty($_GET['fechaInicio']) ? $_GET['fechaInicio'] : null; $fechaFin = !empty($_GET['fechaFin']) ? $_GET['fechaFin'] : null; // Pasar las fechas al modelo $data = $this->model->getVentas($this->id_sucursal, $fechaInicio, $fechaFin); // Construir las acciones permitidas de forma global $accionesPermitidas = [ 'eliminar' => verificar('anular_ventas') ? '<a class="btn btn-secondary btn-sm" href="#" onclick="eliminarVenta({id})"><i class="fas fa-trash"></i></a>' : '', ]; for ($i = 0; $i < count($data); $i++) { $data[$i]['total'] = number_format($data[$i]['total'], 2); if ($data[$i]['estado'] == 1) { // Acciones para ventas activas $acciones = '<div class="btn-group" role="group">'; $acciones .= str_replace('{id}', $data[$i]['id'], $accionesPermitidas['eliminar']); $acciones .= '<a class="btn btn-danger btn-sm" href="#" onclick="verReporte(' . $data[$i]['id'] . ')"><i class="fas fa-file-pdf"></i></a>'; $acciones .= '</div>'; } else { // Acciones para ventas anuladas $acciones = '<div><span class="badge bg-info">Anulado</span></div>'; } $data[$i]['acciones'] = $acciones; } echo json_encode($data); die(); } public function resumenDetalle() { if (!verificar('ver_ventas')) { echo json_encode(['subtotal' => '0.00', 'iva' => '0.00', 'total' => '0.00']); die(); } $fechaInicio = !empty($_GET['fechaInicio']) ? $_GET['fechaInicio'] : null; $fechaFin = !empty($_GET['fechaFin']) ? $_GET['fechaFin'] : null; $resumen = $this->model->getResumenVentas($this->id_sucursal, $fechaInicio, $fechaFin); $response = [ 'subtotal' => number_format((float)$resumen['subtotal'], 2, '.', ''), 'iva' => number_format((float)$resumen['iva'], 2, '.', ''), 'total' => number_format((float)$resumen['total'], 2, '.', ''), ]; echo json_encode($response); die(); } public function listarDetalle() { if (!verificar('ver_ventas')) { echo json_encode([]); die(); } $fechaInicio = !empty($_GET['fechaInicio']) ? $_GET['fechaInicio'] : null; $fechaFin = !empty($_GET['fechaFin']) ? $_GET['fechaFin'] : null; $data = $this->model->getVentasDetalle($this->id_sucursal, $fechaInicio, $fechaFin); $ventasConAccion = []; for ($i = 0; $i < count($data); $i++) { $data[$i]['cantidad'] = number_format((float)$data[$i]['cantidad'], 2, '.', ''); $data[$i]['precio_compra'] = number_format((float)$data[$i]['precio_compra'], 2, '.', ''); $data[$i]['precio_venta'] = number_format((float)$data[$i]['precio_venta'], 2, '.', ''); $data[$i]['ingreso_ventas'] = number_format((float)$data[$i]['ingreso_ventas'], 2, '.', ''); $data[$i]['costo_ventas'] = number_format((float)$data[$i]['costo_ventas'], 2, '.', ''); $data[$i]['utilidad'] = number_format((float)$data[$i]['utilidad'], 2, '.', ''); $idVenta = $data[$i]['id_venta']; $acciones = '<div class="btn-group" role="group">'; $acciones .= '<a class="btn btn-danger btn-sm" href="#" onclick="verReporte(' . $idVenta . ')"><i class="fas fa-file-pdf"></i></a>'; if (verificar('editar_ventas')) { $acciones .= '<a class="btn btn-primary btn-sm" href="' . BASE_URL . 'ventas/edit/' . $idVenta . '"><i class="fas fa-edit"></i></a>'; } if (verificar('anular_ventas')) { $acciones .= '<a class="btn btn-secondary btn-sm" href="#" onclick="eliminarVenta(' . $idVenta . ')"><i class="fas fa-trash"></i></a>'; } $acciones .= '</div>'; $data[$i]['acciones'] = $acciones; } echo json_encode($data); die(); } public function eliminar($idVenta) { if (verificar('anular_ventas')) { if (isset($_GET) && is_numeric($idVenta)) { $venta = $this->model->getVentaBySucursal($idVenta, $this->id_sucursal); if (empty($venta)) { $res = array('msg' => 'VENTA NO ENCONTRADA', 'type' => 'error'); echo json_encode($res); die(); } $ventaProducto = json_decode($venta['productos'], true); if (is_array($ventaProducto)) { foreach ($ventaProducto as $producto) { if (!isset($producto['id'], $producto['cantidad'])) { continue; } $result = $this->model->getProducto($producto['id']); $nuevaCantidad = $result['cantidad'] + $producto['cantidad']; $totalVentas = $result['ventas'] - $producto['cantidad']; $this->model->actualizarStock($nuevaCantidad, $totalVentas, $producto['id']); // movimientos $movimiento = 'Eliminación Venta N°: ' . $idVenta; $this->model->registrarMovimiento($movimiento, 'entrada', $producto['cantidad'], $nuevaCantidad, $producto['id'], $this->id_usuario, $this->id_sucursal); } } $deleted = $this->model->eliminarVentaFisica($idVenta, $this->id_sucursal); if ($deleted == 1) { $res = array('msg' => 'VENTA ELIMINADA', 'type' => 'success'); } else { $res = array('msg' => 'ERROR AL ELIMINAR', 'type' => 'error'); } } else { $res = array('msg' => 'ERROR DESCONOCIDO', 'type' => 'error'); } } else { $res = array('msg' => 'NO TIENES PERMISOS', 'type' => 'error'); } echo json_encode($res); die(); } public function anular($idVenta) { if (verificar('anular_ventas')) { if (isset($_GET) && is_numeric($idVenta)) { $data = $this->model->anular($idVenta); if ($data == 1) { $resultVenta = $this->model->getVenta($idVenta); $ventaProducto = json_decode($resultVenta['productos'], true); foreach ($ventaProducto as $producto) { $result = $this->model->getProducto($producto['id']); $nuevaCantidad = $result['cantidad'] + $producto['cantidad']; $totalVentas = $result['ventas'] - $producto['cantidad']; $this->model->actualizarStock($nuevaCantidad, $totalVentas, $producto['id']); //movimientos $movimiento = 'Devolución Venta N°: ' . $idVenta; $this->model->registrarMovimiento($movimiento, 'entrada', $producto['cantidad'], $nuevaCantidad, $producto['id'], $this->id_usuario, $this->id_sucursal); } if ($resultVenta['metodo'] == 'CREDITO') { $this->model->anularCredito($idVenta); } $res = array('msg' => 'VENTA ANULADO', 'type' => 'success'); } else { $res = array('msg' => 'ERROR AL ANULAR', 'type' => 'error'); } } else { $res = array('msg' => 'ERROR DESCONOCIDO', 'type' => 'error'); } } else { $res = array('msg' => 'NO TIENES PERMISOS', 'type' => 'error'); } echo json_encode($res); die(); } public function impresionDirecta($idVenta) { $empresa = $this->model->getEmpresa($this->id_sucursal); $venta = $this->model->getVenta($idVenta); $nombre_impresora = NOMBRE_IMPRESORA; $connector = new WindowsPrintConnector($nombre_impresora); $printer = new Printer($connector); # Vamos a alinear al centro lo próximo que imprimamos $printer->setJustification(Printer::JUSTIFY_CENTER); /* Intentaremos cargar e imprimir el logo */ // try { // $logo = EscposImage::load("assets/images/logo.png", false); // $printer->bitImage($logo); // } catch (Exception $e) {/*No hacemos nada si hay error*/ // } /* Ahora vamos a imprimir un encabezado */ $printer->text($empresa['nombre'] . "\n"); $printer->text('RUC: ' . $empresa['ruc'] . "\n"); $printer->text('Telefono: ' . $empresa['telefono'] . "\n"); $printer->text('Dirección: ' . $empresa['direccion'] . "\n"); #La fecha también $printer->text(date("Y-m-d H:i:s") . "\n\n"); #Datos del cliente $printer->text('Datos del Cliente' . "\n"); $printer->text('--------------------' . "\n"); /*Alinear a la izquierda para la cantidad y el nombre*/ $printer->setJustification(Printer::JUSTIFY_LEFT); $printer->text($venta['identidad'] . ': ' . $venta['num_identidad'] . "\n"); $printer->text('Nombre: ' . $venta['nombre'] . "\n"); $printer->text('Telefono: ' . $venta['telefono'] . "\n"); $printer->text('Dirección: ' . $venta['direccion'] . "\n\n"); $printer->setJustification(Printer::JUSTIFY_CENTER); $printer->text('Detalles del Producto' . "\n"); $printer->text('--------------------' . "\n"); $productos = json_decode($venta['productos'], true); foreach ($productos as $producto) { /*Alinear a la izquierda para la cantidad y el nombre*/ $printer->setJustification(Printer::JUSTIFY_LEFT); $printer->text($producto['cantidad'] . " x " . $producto['nombre'] . "\n"); /*Y a la derecha para el importe*/ $printer->setJustification(Printer::JUSTIFY_RIGHT); $printer->text(MONEDA . number_format($producto['precio'], 2) . "\n"); } /* Terminamos de imprimir los productos, ahora va el total */ $subTotal = $venta['total'] / 1.18; $igv = $venta['total'] - $subTotal; $printer->text("--------\n"); $printer->text("PAGO CON: " . MONEDA . number_format($venta['pago'], 2) . "\n"); $printer->text("--------\n"); $printer->text("VUELTO: " . MONEDA . number_format(($venta['pago'] - $venta['total']) - $venta['descuento'], 2) . "\n"); $printer->text("--------\n"); $printer->text("Descuento: " . MONEDA . number_format($venta['descuento'], 2) . "\n"); $printer->text("--------\n"); $printer->text("SUBTOTAL: " . MONEDA . number_format($subTotal, 2) . "\n"); $printer->text("--------\n"); $printer->text("ITBIS: " . MONEDA . number_format($igv, 2) . "\n"); $printer->text("--------\n"); $printer->text("TOTAL: " . MONEDA . number_format($venta['total'] - $venta['descuento'], 2) . "\n\n"); /* Podemos poner también un pie de página */ $printer->text($empresa['mensaje']); /*Alimentamos el papel 3 veces*/ $printer->feed(3); /* Cortamos el papel. Si nuestra impresora no tiene soporte para ello, no generará ningún error */ $printer->cut(); /* Por medio de la impresora mandamos un pulso. Esto es útil cuando la tenemos conectada por ejemplo a un cajón */ $printer->pulse(); /* Para imprimir realmente, tenemos que "cerrar" la conexión con la impresora. Recuerda incluir esto al final de todos los archivos */ $printer->close(); } public function verificarStock($idProducto) { $data = $this->model->getProducto($idProducto); echo json_encode($data); die(); } // ENVIAR TICKET AL CORREO DEL CLIENTE public function enviarCorreo($idVenta) { $data['empresa'] = $this->model->getEmpresa($this->id_sucursal); $data['venta'] = $this->model->getVenta($idVenta); if (!empty($data['venta'])) { $data['venta']['moneda'] = MONEDA; } ob_start(); $data['title'] = 'Reporte'; $this->views->getView('ventas', 'ticket_cliente', $data); $html = ob_get_clean(); if (!empty($data)) { $mail = new PHPMailer(true); try { //Server settings //$mail->SMTPDebug = SMTP::DEBUG_SERVER; //Enable verbose debug output $mail->SMTPDebug = 0; //Enable verbose debug output $mail->isSMTP(); //Send using SMTP $mail->Host = HOST_SMTP; //Set the SMTP server to send through $mail->SMTPAuth = true; //Enable SMTP authentication $mail->Username = USER_SMTP; //SMTP username $mail->Password = CLAVE_SMTP; //SMTP password $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; //Enable implicit TLS encryption $mail->Port = PUERTO_SMTP; //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS` //Recipients $mail->setFrom($data['empresa']['correo'], $data['empresa']['nombre']); $mail->addAddress($data['venta']['correo']); //Content $mail->isHTML(true); $mail->CharSet = 'UTF-8'; //Set email format to HTML $mail->Subject = 'Comprobante - ' . TITLE; $mail->Body = $html; $mail->send(); $res = array('msg' => 'CORREO ENVIADO CON LOS DATOS DE LA VENTA', 'type' => 'success'); } catch (Exception $e) { $res = array('msg' => 'ERROR AL ENVIAR EL CORREO: ' . $mail->ErrorInfo, 'type' => 'error'); } } else { $res = array('msg' => 'VENTA NO ENCONTRADA', 'type' => 'warning'); } echo json_encode($res, JSON_UNESCAPED_UNICODE); die(); } public function getVenta($id) { $venta = $this->model->getVenta($id); $data = ($venta['productos'] != null) ? json_decode($venta['productos'], true) : []; echo json_encode($data, JSON_UNESCAPED_UNICODE); die(); } public function prefacturar() { if (!verificar('ver_prefacturas')) { header('Location: ' . BASE_URL . 'admin/permisos'); exit; } $data['title'] = 'Prefacturación'; $data['body_class'] = 'pos-mode'; $data['script'] = 'prefacturas-vendedor.js'; $data['busqueda'] = 'busqueda.js'; $data['carrito'] = 'posPrefactura'; $data['modal'] = 'venta.php'; $data['identidades'] = $this->model->getIdentidades(); $data['empresa'] = $this->model->getEmpresa($this->id_sucursal); $data['serie'] = ['Borrador']; $this->views->getView('ventas', 'prefacturar', $data); } public function registrarPrefactura() { if (!verificar('crear_prefacturas')) { $this->sendResponse('NO TIENE PERMISOS', 'error'); } $json = file_get_contents('php://input'); $datos = json_decode($json, true); $productos = $datos['productos'] ?? []; if (empty($productos)) { $this->sendResponse('CARRITO VACÍO', 'warning'); } $idCliente = (empty($datos['idCliente'])) ? null : $datos['idCliente']; $nota = !empty($datos['nota']) ? $datos['nota'] : null; $descuento = (!empty($datos['descuento'])) ? floatval($datos['descuento']) : 0.00; $totalBruto = 0; foreach ($productos as $p) { $totalBruto += $p['price'] * $p['quantity']; } if ($descuento < 0) { $this->sendResponse('EL DESCUENTO NO PUEDE SER NEGATIVO', 'warning'); } if ($descuento > $totalBruto) { $this->sendResponse('EL DESCUENTO NO PUEDE SER MAYOR AL TOTAL', 'warning'); } $impuesto = (!empty($datos['impuesto'])) ? $datos['impuesto'] : 0; $empresa = $this->model->getEmpresa($this->id_sucursal); $totalNeto = $totalBruto - $descuento; $ivaMonto = 0.0; if ($impuesto == 1) { $ivaMonto = $totalNeto * ($empresa['impuesto'] / 100); $totalConImpuesto = $totalNeto + $ivaMonto; } else { $totalConImpuesto = $totalNeto; } $retencionMonto = isset($datos['retencion']) ? (float)$datos['retencion'] : 0.0; $totalFinal = $totalConImpuesto - $retencionMonto; if ($totalFinal < 0) { $totalFinal = 0; } $fecha = date('Y-m-d'); $hora = date('H:i:s'); $moneda = MONEDA; $datosProductosArr = []; foreach ($productos as $p) { $datosProductosArr[] = [ 'id' => (int)$p['id'], 'nombre' => $p['name'], 'precio' => (float)$p['price'], 'cantidad' => (float)$p['quantity'], 'lote_id' => !empty($p['lote_id']) ? (int)$p['lote_id'] : null, 'fecha_vencimiento' => !empty($p['lote_fecha_vencimiento']) ? $p['lote_fecha_vencimiento'] : null, ]; } $datosProductos = json_encode($datosProductosArr, JSON_UNESCAPED_UNICODE); $prefacturaId = $this->model->registrarPrefactura( $datosProductos, $totalNeto, $totalConImpuesto, $fecha, $hora, $descuento, $ivaMonto, $retencionMonto, $totalFinal, $impuesto, $moneda, $nota, $idCliente, $this->id_usuario, $this->id_sucursal ); if ($prefacturaId > 0) { $this->sendResponse('PREFACTURA GUARDADA', 'success', ['idPrefactura' => $prefacturaId]); } else { $this->sendResponse('ERROR AL GUARDAR PREFACTURA', 'error'); } } public function listarPrefacturas() { if (!verificar('crear_ventas')) { echo json_encode([]); die(); } $data = $this->model->getPrefacturasActivas($this->id_sucursal); echo json_encode($data, JSON_UNESCAPED_UNICODE); die(); } public function obtenerPrefactura($id) { if (!verificar('crear_ventas')) { echo json_encode(['icono' => 'error', 'msg' => 'Sin permisos']); die(); } $prefactura = $this->model->getPrefactura($id); if (empty($prefactura)) { echo json_encode(['icono' => 'error', 'msg' => 'Prefactura no encontrada']); die(); } echo json_encode($prefactura, JSON_UNESCAPED_UNICODE); die(); } public function eliminarPrefactura($id) { if (!verificar('crear_ventas')) { echo json_encode(['icono' => 'error', 'msg' => 'Sin permisos'], JSON_UNESCAPED_UNICODE); die(); } $res = $this->model->eliminarPrefactura($id); if ($res) { $response = ['icono' => 'success', 'msg' => 'Prefactura eliminada correctamente']; } else { $response = ['icono' => 'error', 'msg' => 'Error al eliminar prefactura']; } echo json_encode($response, JSON_UNESCAPED_UNICODE); die(); } public function cargarCarritoVenta() { if (!verificar('crear_ventas')) { echo json_encode(['icono' => 'error', 'msg' => 'Sin permisos']); die(); } $json = file_get_contents('php://input'); $datos = json_decode($json, true); $productos = $datos['productos'] ?? []; unset($_SESSION['ventas']); $_SESSION['ventas'] = []; foreach ($productos as $p) { $idProducto = (int)$p['id']; $producto = $this->model->getProducto($idProducto); if ($producto) { [$preciosVenta, $precioSeleccionado] = $this->precioVentaInicial($producto); foreach ($preciosVenta as $pv) { if (floatval($pv['monto']) == floatval($p['precio'])) { $precioSeleccionado = $pv; break; } } $foto = empty($producto['foto']) ? 'assets/images/productos/default.png' : $producto['foto']; $extra = []; if (!empty($p['lote_id'])) { $extra = [ 'lote_id' => (int)$p['lote_id'], 'lote_fecha_vencimiento' => $p['fecha_vencimiento'] ?? null ]; } addToCartCaja( 'ventas', $idProducto, $producto['descripcion'], $p['precio'], 0, $p['cantidad'], 0, $preciosVenta, $precioSeleccionado, $foto, $extra ); } } echo json_encode(['icono' => 'success', 'msg' => 'Carrito importado con éxito']); die(); } public function obtenerLotes($idProducto) { $lotes = $this->model->getLotesProducto($idProducto, $this->id_sucursal); echo json_encode($lotes, JSON_UNESCAPED_UNICODE); die(); } }
Coded With 💗 by
0x6ick