###########################################################################
## API COMXAR (Fase 3) - agregado 28-ago-2026
## -------------------------------------------------------------------------
## Suma: ventas (solo lectura) y cobros (solo lectura) con detalle anidado,
## alta de "pedido simple" (cliente + items, sin tocar stock ni facturacion),
## informes agregados de solo lectura, e importacion masiva de productos.
## Reusa la infraestructura de Fase 1/2 (auth, scopes, rate limit, logging).
###########################################################################
/* ---------------------------------------------------------------------
Recurso: ventas (solo lectura, con items_de_ventas y cobros anidados)
--------------------------------------------------------------------- */
function api_items_de_venta_de($venta_id){
global $db_link;
$stmt = mysqli_prepare($db_link,"select id,producto,concepto,cantidad,precio_unitario,importe,costo from items_de_ventas where venta=? and sys_delete is null order by id asc");
mysqli_stmt_bind_param($stmt,"i",$venta_id);
mysqli_stmt_execute($stmt);
$r = mysqli_stmt_get_result($stmt);
$items = array();
while ($rs = mysqli_fetch_array($r, MYSQLI_ASSOC)){
$items[] = array(
"id" => intval($rs['id']),
"producto" => $rs['producto']!="" ? intval($rs['producto']) : null,
"concepto" => $rs['concepto'],
"cantidad" => $rs['cantidad'],
"precio_unitario" => $rs['precio_unitario'],
"importe" => $rs['importe'],
);
}
mysqli_stmt_close($stmt);
return $items;
}
function api_cobros_de_venta($venta_id){
global $db_link;
$stmt = mysqli_prepare($db_link,"select id,fecha,importe,efectivo,transferencia,mercadopago from cobros where venta=? and sys_delete is null order by id asc");
mysqli_stmt_bind_param($stmt,"i",$venta_id);
mysqli_stmt_execute($stmt);
$r = mysqli_stmt_get_result($stmt);
$items = array();
while ($rs = mysqli_fetch_array($r, MYSQLI_ASSOC)){
$items[] = array(
"id" => intval($rs['id']),
"fecha" => $rs['fecha'],
"importe"=> $rs['importe'],
);
}
mysqli_stmt_close($stmt);
return $items;
}
function api_ventas_serializar($rs, $con_detalle=false){
$out = array(
"id" => intval($rs['id']),
"cliente" => $rs['cliente']!="" ? intval($rs['cliente']) : null,
"fecha" => $rs['fecha'],
"confirmado" => $rs['confirmado'],
"estado" => isset($rs['estado']) ? $rs['estado'] : null,
"cancelada" => $rs['cancelada'],
"total" => $rs['total'],
"importe_pago" => $rs['importe_pago'],
"forma_de_pago" => isset($rs['forma_de_pago']) ? $rs['forma_de_pago'] : null,
"referencia" => isset($rs['referencia']) ? $rs['referencia'] : null,
"fecha_de_entrega" => isset($rs['fecha_de_entrega']) ? $rs['fecha_de_entrega'] : null,
"origen" => isset($rs['origen']) ? $rs['origen'] : null,
"cantidad_de_productos" => isset($rs['cantidad_de_productos']) ? $rs['cantidad_de_productos'] : null,
"sys_create" => $rs['sys_create'],
"sys_modify" => $rs['sys_modify'],
);
if ($con_detalle){
$out['items'] = api_items_de_venta_de($rs['id']);
$out['cobros'] = api_cobros_de_venta($rs['id']);
}
return $out;
}
function api_recurso_ventas($metodo,$id,$input,$key_row){
global $db_link;
if ($id!==null and !is_numeric($id)){
api_error_json(422,"id_invalido","El id debe ser numerico.");
}
if ($metodo=="GET" and $id===null){
api_requerir_scope($key_row,"ventas:leer");
$page = isset($_GET['page']) ? max(1,intval($_GET['page'])) : 1;
$per_page = isset($_GET['per_page']) ? max(1,min(100,intval($_GET['per_page']))) : 20;
$offset = ($page-1)*$per_page;
$where = "where sys_delete is null";
$tipos = "";
$valores = array();
if (isset($_GET['cliente']) and is_numeric($_GET['cliente'])){
$where .= " and cliente=?";
$tipos .= "i";
$valores[] = intval($_GET['cliente']);
}
if (isset($_GET['desde']) and trim($_GET['desde'])!=""){
$where .= " and STR_TO_DATE(fecha,'%d/%m/%y %H:%i') >= STR_TO_DATE(?,'%Y-%m-%d')";
$tipos .= "s";
$valores[] = trim($_GET['desde']);
}
if (isset($_GET['hasta']) and trim($_GET['hasta'])!=""){
$where .= " and STR_TO_DATE(fecha,'%d/%m/%y %H:%i') <= STR_TO_DATE(?,'%Y-%m-%d')";
$tipos .= "s";
$valores[] = trim($_GET['hasta']);
}
if (isset($_GET['confirmado'])){
if ($_GET['confirmado']=="1"){
$where .= " and confirmado is not null and confirmado<>''";
}elseif($_GET['confirmado']=="0"){
$where .= " and (confirmado is null or confirmado='')";
}
}
$sql_count = "select count(*) as total from ventas ".$where;
$sql = "select * from ventas ".$where." order by id desc limit ".intval($offset).",".intval($per_page);
$stmt1 = mysqli_prepare($db_link,$sql_count);
if ($tipos!="") api_bind_params($stmt1,$tipos,$valores);
mysqli_stmt_execute($stmt1);
$rowcount = mysqli_fetch_array(mysqli_stmt_get_result($stmt1), MYSQLI_ASSOC);
$total = intval($rowcount['total']);
mysqli_stmt_close($stmt1);
$stmt2 = mysqli_prepare($db_link,$sql);
if ($tipos!="") api_bind_params($stmt2,$tipos,$valores);
mysqli_stmt_execute($stmt2);
$r = mysqli_stmt_get_result($stmt2);
$items = array();
while ($rs = mysqli_fetch_array($r, MYSQLI_ASSOC)){
$items[] = api_ventas_serializar($rs,false);
}
mysqli_stmt_close($stmt2);
api_responder_json(200, array("data"=>$items,"pagina"=>$page,"por_pagina"=>$per_page,"total"=>$total));
}elseif($metodo=="GET" and $id!==null){
api_requerir_scope($key_row,"ventas:leer");
$stmt = mysqli_prepare($db_link,"select * from ventas where id=? and sys_delete is null limit 1");
mysqli_stmt_bind_param($stmt,"i",$id);
mysqli_stmt_execute($stmt);
$rs = mysqli_fetch_array(mysqli_stmt_get_result($stmt), MYSQLI_ASSOC);
mysqli_stmt_close($stmt);
if (!$rs){
api_error_json(404,"no_encontrado","No existe una venta con id ".$id.".");
}
api_responder_json(200, api_ventas_serializar($rs,true));
}elseif($metodo=="POST" and $id===null){
api_requerir_scope($key_row,"ventas:escribir");
api_ventas_crear_pedido($input,$key_row);
}else{
api_error_json(405,"metodo_no_permitido","Metodo ".$metodo." no soportado para /ventas.");
}
}
/* ---------------------------------------------------------------------
Alta de "pedido simple": cliente + items nada mas. Queda como
cotizacion/pedido pendiente (confirmado = NULL), NO descuenta stock
ni genera comprobante -- eso lo termina el staff desde el panel.
Por eso el scope es "ventas:escribir" pero el alcance de lo que hace
esta funcion es deliberadamente chico y no reusa guardar_venta() (que
esta atada al form del panel y hace muchas mas cosas).
--------------------------------------------------------------------- */
function api_ventas_crear_pedido($input,$key_row){
global $db_link;
if (!isset($input['cliente']) or !is_numeric($input['cliente'])){
api_error_json(422,"campo_requerido","El campo 'cliente' (id de contacto) es obligatorio y debe ser numerico.","cliente");
}
$cliente_id = intval($input['cliente']);
$stmt_c = mysqli_prepare($db_link,"select id from contactos where id=? and sys_delete is null limit 1");
mysqli_stmt_bind_param($stmt_c,"i",$cliente_id);
mysqli_stmt_execute($stmt_c);
$existe_cliente = mysqli_fetch_array(mysqli_stmt_get_result($stmt_c), MYSQLI_ASSOC);
mysqli_stmt_close($stmt_c);
if (!$existe_cliente){
api_error_json(422,"cliente_invalido","No existe un contacto con id ".$cliente_id.".","cliente");
}
if (!isset($input['items']) or !is_array($input['items']) or count($input['items'])==0){
api_error_json(422,"campo_requerido","El campo 'items' es obligatorio y debe ser una lista con al menos un elemento.","items");
}
$items_normalizados = array();
$total = 0.0;
$cantidad_de_productos = 0;
foreach ($input['items'] as $idx => $item){
if (!is_array($item)){
api_error_json(422,"item_invalido","El item en la posicion ".$idx." no es un objeto valido.","items");
}
$cantidad = isset($item['cantidad']) ? floatval($item['cantidad']) : 1;
if ($cantidad<=0){
api_error_json(422,"item_invalido","El item en la posicion ".$idx." debe tener cantidad mayor a 0.","items");
}
$producto_id = null;
$concepto = isset($item['concepto']) ? trim($item['concepto']) : "";
$precio_unitario = isset($item['precio_unitario']) ? floatval($item['precio_unitario']) : null;
$costo = null;
if (isset($item['producto']) and $item['producto']!==null and $item['producto']!==""){
if (!is_numeric($item['producto'])){
api_error_json(422,"item_invalido","El campo 'producto' del item en la posicion ".$idx." debe ser numerico.","items");
}
$producto_id = intval($item['producto']);
$stmt_p = mysqli_prepare($db_link,"select id,nombre,precio,costo from productos where id=? and sys_delete is null limit 1");
mysqli_stmt_bind_param($stmt_p,"i",$producto_id);
mysqli_stmt_execute($stmt_p);
$prod = mysqli_fetch_array(mysqli_stmt_get_result($stmt_p), MYSQLI_ASSOC);
mysqli_stmt_close($stmt_p);
if (!$prod){
api_error_json(422,"item_invalido","No existe un producto con id ".$producto_id." (item ".$idx.").","items");
}
if ($concepto==""){
$concepto = $prod['nombre'];
}
if ($precio_unitario===null){
$precio_unitario = floatval(precio_a_float($prod['precio']));
}
$costo = $prod['costo'];
}
if ($concepto==""){
api_error_json(422,"item_invalido","El item en la posicion ".$idx." necesita 'producto' o 'concepto'.","items");
}
if ($precio_unitario===null){
api_error_json(422,"item_invalido","El item en la posicion ".$idx." necesita 'precio_unitario' (o un 'producto' con precio cargado).","items");
}
$importe = round($precio_unitario * $cantidad, 2);
$total += $importe;
$cantidad_de_productos += $cantidad;
$items_normalizados[] = array(
"producto" => $producto_id,
"concepto" => $concepto,
"cantidad" => $cantidad,
"precio_unitario" => $precio_unitario,
"importe" => $importe,
"costo" => $costo,
);
}
$fecha_y_hora = date("d/m/y H:i");
$referencia = isset($input['referencia']) and is_string($input['referencia']) ? trim($input['referencia']) : "";
$origen = "api";
$usuario = "api:".$key_row['id'];
$total_str = number_format($total,2,'.','');
$stmt_v2 = mysqli_prepare($db_link,"insert into ventas (cliente,fecha,total,referencia,origen,sys_create,sys_create_user) values (?,?,?,?,?,?,?)");
mysqli_stmt_bind_param($stmt_v2,"issssss",$cliente_id,$fecha_y_hora,$total_str,$referencia,$origen,$fecha_y_hora,$usuario);
mysqli_stmt_execute($stmt_v2);
$venta_id = mysqli_insert_id($db_link);
mysqli_stmt_close($stmt_v2);
if (!$venta_id){
api_error_json(500,"error_interno","No se pudo crear el pedido.");
}
foreach ($items_normalizados as $it){
$stmt_i = mysqli_prepare($db_link,"insert into items_de_ventas (venta,producto,concepto,cantidad,precio_unitario,importe,costo,sys_create,sys_create_user) values (?,?,?,?,?,?,?,?,?)");
$producto_val = $it['producto'];
$cantidad_str = strval($it['cantidad']);
$precio_str = number_format($it['precio_unitario'],2,'.','');
$importe_str = number_format($it['importe'],2,'.','');
$costo_val = $it['costo']!==null ? strval($it['costo']) : null;
mysqli_stmt_bind_param($stmt_i,"iisssssss",$venta_id,$producto_val,$it['concepto'],$cantidad_str,$precio_str,$importe_str,$costo_val,$fecha_y_hora,$usuario);
mysqli_stmt_execute($stmt_i);
mysqli_stmt_close($stmt_i);
}
$stmt_u = mysqli_prepare($db_link,"update ventas set cantidad_de_productos=? where id=?");
$cant_str = strval($cantidad_de_productos);
mysqli_stmt_bind_param($stmt_u,"si",$cant_str,$venta_id);
mysqli_stmt_execute($stmt_u);
mysqli_stmt_close($stmt_u);
api_log_escritura($key_row['id'],"ventas","crear",$venta_id,null,array("cliente"=>$cliente_id,"total"=>$total_str,"items"=>count($items_normalizados)));
$stmt_f = mysqli_prepare($db_link,"select * from ventas where id=? limit 1");
mysqli_stmt_bind_param($stmt_f,"i",$venta_id);
mysqli_stmt_execute($stmt_f);
$rs = mysqli_fetch_array(mysqli_stmt_get_result($stmt_f), MYSQLI_ASSOC);
mysqli_stmt_close($stmt_f);
api_responder_json(201, api_ventas_serializar($rs,true));
}
/* ---------------------------------------------------------------------
Recurso: cobros (solo lectura)
--------------------------------------------------------------------- */
function api_cobros_serializar($rs){
return array(
"id" => intval($rs['id']),
"venta" => $rs['venta']!="" ? intval($rs['venta']) : null,
"cliente" => $rs['cliente']!="" ? intval($rs['cliente']) : null,
"fecha" => $rs['fecha'],
"importe" => $rs['importe'],
"efectivo" => $rs['efectivo'],
"transferencia" => $rs['transferencia'],
"mercadopago" => $rs['mercadopago'],
"sys_create" => $rs['sys_create'],
);
}
function api_recurso_cobros($metodo,$id,$input,$key_row){
global $db_link;
if ($id!==null and !is_numeric($id)){
api_error_json(422,"id_invalido","El id debe ser numerico.");
}
if ($metodo=="GET" and $id===null){
api_requerir_scope($key_row,"cobros:leer");
$page = isset($_GET['page']) ? max(1,intval($_GET['page'])) : 1;
$per_page = isset($_GET['per_page']) ? max(1,min(100,intval($_GET['per_page']))) : 20;
$offset = ($page-1)*$per_page;
$where = "where sys_delete is null";
$tipos = "";
$valores = array();
if (isset($_GET['venta']) and is_numeric($_GET['venta'])){
$where .= " and venta=?";
$tipos .= "i";
$valores[] = intval($_GET['venta']);
}
if (isset($_GET['cliente']) and is_numeric($_GET['cliente'])){
$where .= " and cliente=?";
$tipos .= "i";
$valores[] = intval($_GET['cliente']);
}
$sql_count = "select count(*) as total from cobros ".$where;
$sql = "select * from cobros ".$where." order by id desc limit ".intval($offset).",".intval($per_page);
$stmt1 = mysqli_prepare($db_link,$sql_count);
if ($tipos!="") api_bind_params($stmt1,$tipos,$valores);
mysqli_stmt_execute($stmt1);
$rowcount = mysqli_fetch_array(mysqli_stmt_get_result($stmt1), MYSQLI_ASSOC);
$total = intval($rowcount['total']);
mysqli_stmt_close($stmt1);
$stmt2 = mysqli_prepare($db_link,$sql);
if ($tipos!="") api_bind_params($stmt2,$tipos,$valores);
mysqli_stmt_execute($stmt2);
$r = mysqli_stmt_get_result($stmt2);
$items = array();
while ($rs = mysqli_fetch_array($r, MYSQLI_ASSOC)){
$items[] = api_cobros_serializar($rs);
}
mysqli_stmt_close($stmt2);
api_responder_json(200, array("data"=>$items,"pagina"=>$page,"por_pagina"=>$per_page,"total"=>$total));
}elseif($metodo=="GET" and $id!==null){
api_requerir_scope($key_row,"cobros:leer");
$stmt = mysqli_prepare($db_link,"select * from cobros where id=? and sys_delete is null limit 1");
mysqli_stmt_bind_param($stmt,"i",$id);
mysqli_stmt_execute($stmt);
$rs = mysqli_fetch_array(mysqli_stmt_get_result($stmt), MYSQLI_ASSOC);
mysqli_stmt_close($stmt);
if (!$rs){
api_error_json(404,"no_encontrado","No existe un cobro con id ".$id.".");
}
api_responder_json(200, api_cobros_serializar($rs));
}else{
api_error_json(405,"metodo_no_permitido","Metodo ".$metodo." no soportado para /cobros.");
}
}
/* ---------------------------------------------------------------------
Recurso: informes (solo lectura, agregados -- no exponen filas crudas
de ventas/cobros, solo totales agrupados)
--------------------------------------------------------------------- */
function api_informes_rango_fechas(){
$desde = isset($_GET['desde']) and trim($_GET['desde'])!="" ? trim($_GET['desde']) : date("Y-m-d", strtotime("-30 days"));
$hasta = isset($_GET['hasta']) and trim($_GET['hasta'])!="" ? trim($_GET['hasta']) : date("Y-m-d");
return array($desde,$hasta);
}
function api_informe_resumen_financiero(){
global $db_link;
list($desde,$hasta) = api_informes_rango_fechas();
$sql_cotizado = "select coalesce(sum(0+total),0) s from ventas where sys_delete is null and (confirmado is null or confirmado='') and STR_TO_DATE(fecha,'%d/%m/%y %H:%i') between STR_TO_DATE(?,'%Y-%m-%d') and STR_TO_DATE(?,'%Y-%m-%d')";
$sql_vendido = "select coalesce(sum(0+total),0) s from ventas where sys_delete is null and confirmado is not null and confirmado<>'' and STR_TO_DATE(confirmado,'%d/%m/%Y') between STR_TO_DATE(?,'%Y-%m-%d') and STR_TO_DATE(?,'%Y-%m-%d')";
$sql_cobrado = "select coalesce(sum(0+importe),0) s from cobros where sys_delete is null and STR_TO_DATE(fecha,'%d/%m/%y %H:%i') between STR_TO_DATE(?,'%Y-%m-%d') and STR_TO_DATE(?,'%Y-%m-%d')";
$sql_facturado= "select coalesce(sum(0+total),0) s from ventas where sys_delete is null and confirmado is not null and confirmado<>'' and fecha_de_facturacion is not null and STR_TO_DATE(fecha_de_facturacion,'%d/%m/%y %H:%i') between STR_TO_DATE(?,'%Y-%m-%d') and STR_TO_DATE(?,'%Y-%m-%d')";
$resultado = array();
foreach (array("cotizado"=>$sql_cotizado,"vendido"=>$sql_vendido,"cobrado"=>$sql_cobrado,"facturado"=>$sql_facturado) as $clave => $sql){
$stmt = mysqli_prepare($db_link,$sql);
mysqli_stmt_bind_param($stmt,"ss",$desde,$hasta);
mysqli_stmt_execute($stmt);
$rs = mysqli_fetch_array(mysqli_stmt_get_result($stmt), MYSQLI_ASSOC);
mysqli_stmt_close($stmt);
$resultado[$clave] = floatval($rs['s']);
}
api_responder_json(200, array("desde"=>$desde,"hasta"=>$hasta) + $resultado);
}
function api_informe_top_productos(){
global $db_link;
list($desde,$hasta) = api_informes_rango_fechas();
$limite = isset($_GET['limite']) ? max(1,min(50,intval($_GET['limite']))) : 10;
$sql = "select items_de_ventas.producto, productos.nombre,
sum(items_de_ventas.cantidad) cant,
sum(0+items_de_ventas.importe) imp
from items_de_ventas
left outer join ventas on items_de_ventas.venta = ventas.id
left outer join productos on productos.id = items_de_ventas.producto
where ventas.sys_delete is null and items_de_ventas.sys_delete is null
and ventas.cancelada is null and ventas.session is null
and ventas.confirmado is not null and ventas.confirmado<>''
and STR_TO_DATE(ventas.confirmado,'%d/%m/%Y') between STR_TO_DATE(?,'%Y-%m-%d') and STR_TO_DATE(?,'%Y-%m-%d')
and items_de_ventas.producto is not null and items_de_ventas.producto<>'' and items_de_ventas.producto<>0
group by items_de_ventas.producto
order by cant desc
limit ".intval($limite);
$stmt = mysqli_prepare($db_link,$sql);
mysqli_stmt_bind_param($stmt,"ss",$desde,$hasta);
mysqli_stmt_execute($stmt);
$r = mysqli_stmt_get_result($stmt);
$items = array();
while ($rs = mysqli_fetch_array($r, MYSQLI_ASSOC)){
$items[] = array(
"producto" => intval($rs['producto']),
"nombre" => $rs['nombre'],
"cantidad_vendida" => floatval($rs['cant']),
"importe_total" => floatval($rs['imp']),
);
}
mysqli_stmt_close($stmt);
api_responder_json(200, array("desde"=>$desde,"hasta"=>$hasta,"data"=>$items));
}
function api_informe_deuda_por_cliente(){
global $db_link;
$limite = isset($_GET['limite']) ? max(1,min(100,intval($_GET['limite']))) : 20;
$sql = "select cliente, sum(0+total) t, sum(0+importe_pago) p, count(*) c
from ventas
where sys_delete is null and cancelada is null and confirmado is not null and confirmado<>''
and (0+total > 0+importe_pago or importe_pago is null)
group by cliente
order by (sum(0+total)-sum(0+importe_pago)) desc
limit ".intval($limite);
$r = mysqli_query($db_link,$sql);
$items = array();
while ($rs = mysqli_fetch_array($r, MYSQLI_ASSOC)){
if ($rs['cliente']=="" or $rs['cliente']===null){
continue;
}
$deuda = floatval($rs['t']) - floatval($rs['p']);
if ($deuda<=0){
continue;
}
$items[] = array(
"cliente" => intval($rs['cliente']),
"deuda" => $deuda,
"cantidad_ventas" => intval($rs['c']),
);
}
api_responder_json(200, array("data"=>$items));
}
function api_informe_stock_bajo(){
global $db_link;
$limite = isset($_GET['limite']) ? max(1,min(200,intval($_GET['limite']))) : 50;
$sql = "select id,nombre,codigo,stock,stock_minimo from productos
where sys_delete is null and habilitado is not null and habilitado<>''
and stock_minimo is not null and stock_minimo<>''
and (0+stock) <= (0+stock_minimo)
order by (0+stock) asc
limit ".intval($limite);
$r = mysqli_query($db_link,$sql);
$items = array();
while ($rs = mysqli_fetch_array($r, MYSQLI_ASSOC)){
$items[] = array(
"id" => intval($rs['id']),
"nombre"=> $rs['nombre'],
"codigo"=> $rs['codigo'],
"stock" => $rs['stock'],
"stock_minimo" => $rs['stock_minimo'],
);
}
api_responder_json(200, array("data"=>$items));
}
function api_recurso_informes($metodo,$id,$input,$key_row){
if ($metodo!="GET"){
api_error_json(405,"metodo_no_permitido","Metodo ".$metodo." no soportado para /informes.");
}
api_requerir_scope($key_row,"informes:leer");
switch ($id){
case "resumen_financiero":
api_informe_resumen_financiero();
break;
case "top_productos":
api_informe_top_productos();
break;
case "deuda_por_cliente":
api_informe_deuda_por_cliente();
break;
case "stock_bajo":
api_informe_stock_bajo();
break;
default:
api_error_json(404,"informe_no_encontrado","'".$id."' no es un informe disponible. Opciones: resumen_financiero, top_productos, deuda_por_cliente, stock_bajo.");
}
}
/* ---------------------------------------------------------------------
Importacion masiva de productos: alta/actualizacion en lote. Cada item
se procesa de forma independiente (uno falla, los demas siguen), y la
respuesta detalla el resultado item por item.
--------------------------------------------------------------------- */
function api_productos_importar($input,$key_row){
global $db_link;
api_requerir_scope($key_row,"productos:escribir");
if (!isset($input['productos']) or !is_array($input['productos']) or count($input['productos'])==0){
api_error_json(422,"campo_requerido","El campo 'productos' es obligatorio y debe ser una lista con al menos un elemento.","productos");
}
if (count($input['productos'])>200){
api_error_json(422,"demasiados_items","Maximo 200 productos por importacion. Dividi la carga en lotes mas chicos.","productos");
}
$campos_permitidos = api_productos_campos_editables();
$resultados = array();
$creados = 0;
$actualizados = 0;
$con_error = 0;
foreach ($input['productos'] as $idx => $item){
if (!is_array($item)){
$resultados[] = array("indice"=>$idx,"ok"=>false,"error"=>"item_invalido","mensaje"=>"El item no es un objeto valido.");
$con_error++;
continue;
}
$id_existente = (isset($item['id']) and is_numeric($item['id'])) ? intval($item['id']) : null;
$codigo = isset($item['codigo']) ? trim($item['codigo']) : null;
// Si no vino id pero si codigo, buscamos por codigo para decidir alta vs modificacion.
if ($id_existente===null and $codigo!==null and $codigo!==""){
$stmt_b = mysqli_prepare($db_link,"select id from productos where codigo=? and sys_delete is null limit 1");
mysqli_stmt_bind_param($stmt_b,"s",$codigo);
mysqli_stmt_execute($stmt_b);
$existente = mysqli_fetch_array(mysqli_stmt_get_result($stmt_b), MYSQLI_ASSOC);
mysqli_stmt_close($stmt_b);
if ($existente){
$id_existente = intval($existente['id']);
}
}
$datos = array();
foreach ($campos_permitidos as $c){
if (array_key_exists($c,$item) and !is_array($item[$c])){
$datos[$c] = is_string($item[$c]) ? trim($item[$c]) : $item[$c];
}
}
if ($id_existente===null){
if (!isset($datos['nombre']) or trim($datos['nombre'])==""){
$resultados[] = array("indice"=>$idx,"ok"=>false,"error"=>"campo_requerido","mensaje"=>"Falta 'nombre' para dar de alta el producto.");
$con_error++;
continue;
}
$fecha_y_hora = date("d/m/y H:i");
$datos['sys_create'] = $fecha_y_hora;
$datos['sys_create_user'] = "api:".$key_row['id'];
$cols = array_keys($datos);
$marcas = implode(",", array_fill(0,count($cols),"?"));
$tipos = str_repeat("s", count($cols));
$stmt = mysqli_prepare($db_link,"insert into productos (".implode(",",$cols).") values (".$marcas.")");
if (!$stmt){
$resultados[] = array("indice"=>$idx,"ok"=>false,"error"=>"error_interno","mensaje"=>"No se pudo preparar el alta.");
$con_error++;
continue;
}
$valores = array_values($datos);
api_bind_params($stmt,$tipos,$valores);
mysqli_stmt_execute($stmt);
$nuevo_id = mysqli_insert_id($db_link);
mysqli_stmt_close($stmt);
if (!$nuevo_id){
$resultados[] = array("indice"=>$idx,"ok"=>false,"error"=>"error_interno","mensaje"=>"No se pudo crear el producto.");
$con_error++;
continue;
}
api_log_escritura($key_row['id'],"productos","crear",$nuevo_id,null,$datos);
$resultados[] = array("indice"=>$idx,"ok"=>true,"accion"=>"creado","id"=>$nuevo_id);
$creados++;
}else{
$stmt0 = mysqli_prepare($db_link,"select * from productos where id=? and sys_delete is null limit 1");
mysqli_stmt_bind_param($stmt0,"i",$id_existente);
mysqli_stmt_execute($stmt0);
$antes = mysqli_fetch_array(mysqli_stmt_get_result($stmt0), MYSQLI_ASSOC);
mysqli_stmt_close($stmt0);
if (!$antes){
$resultados[] = array("indice"=>$idx,"ok"=>false,"error"=>"no_encontrado","mensaje"=>"No existe un producto con id ".$id_existente.".");
$con_error++;
continue;
}
if (empty($datos)){
$resultados[] = array("indice"=>$idx,"ok"=>true,"accion"=>"sin_cambios","id"=>$id_existente);
continue;
}
$fecha_y_hora = date("d/m/y H:i");
$datos['sys_modify'] = $fecha_y_hora;
$datos['sys_modify_user'] = "api:".$key_row['id'];
$sets = array();
foreach (array_keys($datos) as $c){
$sets[] = $c."=?";
}
$tipos = str_repeat("s", count($datos));
$stmt = mysqli_prepare($db_link,"update productos set ".implode(",",$sets)." where id=?");
$valores = array_values($datos);
$valores[] = $id_existente;
api_bind_params($stmt,$tipos."i",$valores);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
api_log_escritura($key_row['id'],"productos","actualizar",$id_existente,$antes,$datos);
$resultados[] = array("indice"=>$idx,"ok"=>true,"accion"=>"actualizado","id"=>$id_existente);
$actualizados++;
}
}
api_responder_json(200, array(
"total" => count($input['productos']),
"creados" => $creados,
"actualizados" => $actualizados,
"con_error" => $con_error,
"resultados" => $resultados,
));
}
Warning: Cannot modify header information - headers already sent by (output started at /var/www/default.contactopuro.com/public_html/admin/inc/functions.php:10697) in /var/www/default.contactopuro.com/public_html/inc/front_processor.php on line 59
https://dietaberazategui.comx.ar/
https://dietaberazategui.comx.ar/registro
https://dietaberazategui.comx.ar/terminos
https://dietaberazategui.comx.ar/registro
https://dietaberazategui.comx.ar/dp-descenso-progresivo-1-mes-4-reuniones
https://dietaberazategui.comx.ar/ind-individual-con-nutricionista-4-reuniones
https://dietaberazategui.comx.ar/ind-individual-con-nutricionista-3-meses-12-reuniones