Skip to content

Instantly share code, notes, and snippets.

@jsianes
Last active December 19, 2015 17:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsianes/5994066 to your computer and use it in GitHub Desktop.
Save jsianes/5994066 to your computer and use it in GitHub Desktop.
This Java code helps you to analyze economic proposals of a contest according to art.85 hiring law of Public Administrations in Spain (Real Decreto 1098/2001,Reglamento LCAP - artículo 85: http://is.gd/uANADN )
import java.io.*;
import java.util.*;
import java.text.*;
public class LCAP {
public static void Ley() {
System.out.printf("Evaluacion segun la LCAP:\n\n"+
"Articulo 85. Criterios para apreciar las ofertas desproporcionadas o temerarias en las\n"+
"subastas.- Se consideraran, en principio, desproporcionadas o temerarias las ofertas que\n"+
"se encuentren en los siguientes supuestos:\n\n"+
"1. Cuando, concurriendo un solo licitador, sea inferior al presupuesto base de licitacion en\n"+
" mas de 25 unidades porcentuales.\n"+
"2. Cuando concurran dos licitadores, la que sea inferior en mas de 20 unidades\n"+
" porcentuales a la otra oferta.\n"+
"3. Cuando concurran tres licitadores, las que sean inferiores en mas de 10 unidades\n"+
" porcentuales a la media aritmetica de las ofertas presentadas. No obstante, se excluira para\n"+
" el computo de dicha media la oferta de cuantia mas elevada cuando sea superior en mas\n"+
" de 10 unidades porcentuales a dicha media. En cualquier caso, se considerara\n"+
" desproporcionada la baja superior a 25 unidades porcentuales.\n"+
"4. Cuando concurran cuatro o mas licitadores, las que sean inferiores en mas de 10\n"+
" unidades porcentuales a la media aritmetica de las ofertas presentadas. No obstante, si\n"+
" entre ellas existen ofertas que sean superiores a dicha media en mas de 10 unidades\n"+
" porcentuales, se procedera al calculo de una nueva media solo con las ofertas que no se\n"+
" encuentren en el supuesto indicado. En todo caso, si el numero de las restantes ofertas es\n"+
" inferior a tres, la nueva media se calculara sobre las tres ofertas de menor cuantia.\n"+
"5. Excepcionalmente, y atendiendo al objeto del contrato y circunstancias del mercado, el\n"+
" organo de contratacion podra motivadamente reducir en un tercio en el correspondiente\n"+
" pliego de clausulas administrativas particulares los porcentajes establecidos en los\n"+
" apartados anteriores.\n"+
"6. Para la valoracion de la ofertas como desproporcionadas, la mesa de contratacion\n"+
" podra considerar la relacion entre la solvencia de la empresa y la oferta presentada.\n\n");
}
public static void mensajeAyuda() {
System.out.println("");
System.out.println("Uso:");
System.out.println("");
System.out.println(" java -jar LCAP.jar ley");
System.out.println(" - Muestra la informacion de la ley relativa al articulo 85 de la LCAP");
System.out.println("");
System.out.println(" java -jar LCAP.jar PresupuestoBase escala aceptarBajas fichero.csv");
System.out.println("");
System.out.println("Donde:");
System.out.println(" - PresupuestoBase: Es el presupuesto base en euros de licitacion");
System.out.println(" - escala: Numero entero mayor que 0 que indica la escala sobre la que puntuar");
System.out.println(" evaluandose los licitadores con puntuacion de 0 y el valor de la escala");
System.out.println(" - aceptarBajar: valor entero binario: 0 indica que no se deben tener en consideracion");
System.out.println(" las bajas temerarias y 1 que si deben tenerse en consideracion en la evaluacion");
System.out.println(" - 'fichero.csv' nombre del fichero CSV de entrada que contiene por cada linea");
System.out.println(" el nombre del licitador y la oferta economica presentada, ambos valores separados");
System.out.println(" por el caracter \';\'. La oferta economica debe ir expresada en notacion decimal");
System.out.println(" americana, es decir, el caracter \'.\' debe usarse para separar los decimales");
System.out.println("");
System.out.println(" Ejemplo:");
System.out.println("");
System.out.println(" Oferta 1;10000");
System.out.println(" Oferta 2;12500.25");
System.out.println(" Oferta 3;20000.5");
System.out.println(" Oferta 4;20000.95");
System.out.println(" Oferta 5;21100");
System.out.println("");
System.out.println("Copyleft 2013 - Javier Sianes (jsianes@gmail.com)");
System.out.println("");
System.exit(1);
}
public static void main(String[] args) {
DecimalFormat df = new DecimalFormat("#.##");
int escala=0,aceptarBajas=0,lineas=0;
double presupuestoBase=0.0;
if (args.length<=3) {if (args.length==1) {Ley();} else {mensajeAyuda();}}
try {
presupuestoBase=Double.parseDouble(args[0]);
escala=Integer.parseInt(args[1]);
aceptarBajas=Integer.parseInt(args[2]);
}catch(NumberFormatException e) {System.exit(3);}
File f = new File(args[3]);
if(f.exists()) {
try{
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(args[3])));
lnr.skip(Long.MAX_VALUE);
lineas=lnr.getLineNumber();
lnr.close();
System.out.println("-- El fichero \""+args[3]+"\",en base al numero de lineas, contiene "+lineas+" potenciales licitadores");
if (aceptarBajas==1) {
System.out.println("-- Se aceptan a evaluacion las bajas temerarias");
} else {
System.out.println("-- No se aceptan a evalucion las bajas temerarias");
}
FileInputStream fstream = new FileInputStream(args[3]);
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
Double value=0.0;
Vector<Licitador> v = new Vector<Licitador>();
while ((line = br.readLine())!=null) {
String[] linea = line.split(";");
if (linea.length==2) {
try
{
if (!linea[0].isEmpty()) {
value=Double.parseDouble(linea[1]);
Licitador l = new Licitador(linea[0],value);
if (!ofertanteExiste(v,l)) {
if (l.oferta<=presupuestoBase) {v.add(l);} else {
System.out.println("-- Descartado licitador \""+l.licitador+"\" por exceder su oferta ("+l.oferta+") el presupuesto base ("+presupuestoBase+")");
}
} else {
System.out.println("-- Eliminada la oferta del licitador \""+l.licitador+"\" ("+df.format(l.oferta)+") por duplicidad");
}
}
}catch(NumberFormatException e) {}
}
}
in.close();
switch (v.size()) {
case 0:
System.out.println("-- ERROR: No existen ofertas que cumplan los criterios de valoracion indicados.");
System.out.println("");
System.exit(2);
break;
case 1:
puntuacion1Licitador(presupuestoBase, escala, aceptarBajas, v);
break;
case 2:
puntuacion2Licitadores(presupuestoBase, escala, aceptarBajas, v);
break;
case 3:
puntuacion3Licitadores(presupuestoBase, escala, aceptarBajas, v);
break;
default:
puntuacion4omasLicitadores(presupuestoBase, escala, aceptarBajas, v);
break;
}
}catch (Exception e){
System.err.println("Error: " + e.getMessage());
System.exit(255);
}
}
}
public static void puntuacion1Licitador(double presupuestoBase, int escala, int aceptarBajas, Vector<Licitador> v) {
DecimalFormat df = new DecimalFormat("#.##");
double bajaTemeraria=0.0;
System.out.println("-- Un licitador valido: aplicando norma de LCAP para un licitador");
System.out.println("-- Presupuesto base: "+df.format(presupuestoBase));
bajaTemeraria=0.75*presupuestoBase;
muestraResultados(bajaTemeraria, presupuestoBase, escala, aceptarBajas, v);
}
public static void puntuacion2Licitadores(double presupuestoBase, int escala, int aceptarBajas, Vector<Licitador> v) {
DecimalFormat df = new DecimalFormat("#.##");
double bajaTemeraria=0.0;
System.out.println("-- Dos licitadores validos: aplicando norma de LCAP para dos licitadores");
System.out.println("-- Presupuesto base: "+df.format(presupuestoBase));
if (v.get(0).oferta>=v.get(1).oferta) {bajaTemeraria=0.8*v.get(0).oferta;}else{bajaTemeraria=0.8*v.get(1).oferta;}
muestraResultados(bajaTemeraria, presupuestoBase, escala, aceptarBajas, v);
}
public static void puntuacion3Licitadores(double presupuestoBase, int escala, int aceptarBajas, Vector<Licitador> v) {
DecimalFormat df = new DecimalFormat("#.##");
double bajaTemeraria=0.0,promedio=0.0,suma=0.0,max=0.0;
for (int i=0;i<v.size();i++) {
suma=suma+v.get(i).oferta;
if ((v.get(i).oferta)>max) {max=v.get(i).oferta;}
}
promedio=suma/v.size();
System.out.println("-- Tres licitadores: aplicando norma de LCAP para tres licitadores");
System.out.println("-- Presupuesto base: "+df.format(presupuestoBase));
System.out.println("-- Promedio de las tres ofertas: "+df.format(promedio));
if (max>(promedio*1.1)) {
promedio=(suma-max)/((v.size())-1);
System.out.println("-- La mayor oferta ("+df.format(max)+") supera en 10 puntos porcentuales al promedio, recalculando promedio sin dicha oferta");
System.out.println("-- Nuevo promedio: "+df.format(promedio));
}
bajaTemeraria=0.75*promedio;
muestraResultados(bajaTemeraria, presupuestoBase, escala, aceptarBajas, v);
}
public static void puntuacion4omasLicitadores(double presupuestoBase, int escala, int aceptarBajas, Vector<Licitador> v) {
DecimalFormat df = new DecimalFormat("#.##");
int j=0,k=0,total=v.size();
double bajaTemeraria=0.0,promedio=0.0,suma=0.0,max=0.0;
for (int i=0;i<v.size();i++) {
suma=suma+v.get(i).oferta;
if ((v.get(i).oferta)>max) {max=v.get(i).oferta;}
}
promedio=suma/v.size();
System.out.println("-- Cuatro o mas licitadores: aplicando norma de LCAP para cuatro o mas licitadores");
System.out.println("-- Presupuesto base: "+df.format(presupuestoBase));
System.out.println("-- Promedio de las "+total+" ofertas: "+df.format(promedio));
for (int i=0;i<v.size();i++) {
if ((v.get(i).oferta)>(promedio*1.1)) {
System.out.println("-- La oferta del licitador \""+v.get(i).licitador+"\" excede en 10 puntos porcentuales la media ("+df.format(v.get(i).oferta)+")");
j++;
}
}
System.out.println("-- Del total de "+total+" ofertas hay "+j+" ofertas que exceden en 10 puntos porcentuales el promedio ");
if ((total-j)<3) {
System.out.println("-- Se usaran las 3 ofertas de menor valor para recalcular el promedio");
List<Double> w = new Vector<Double>(total);
for (int i=0;i<v.size();i++) {
w.add(v.get(i).oferta);
}
Collections.sort(w);
promedio=(w.get(0)+w.get(1)+w.get(2))/3;
System.out.println("-- Promedio con las tres ofertas mas bajas: "+df.format(promedio));
} else {
System.out.println("-- Se usaran las ofertas que no exceden para recalcular el promedio");
suma=0.0;
for (int i=0;i<v.size();i++) {
if ((v.get(i).oferta)<=(promedio*1.1)) {
suma=suma+v.get(i).oferta;
k++;
}
}
promedio=(suma/k);
System.out.println("-- Nuevo promedio empleando estas "+k+" ofertas: "+df.format(promedio));
}
bajaTemeraria=0.9*promedio;
muestraResultados(bajaTemeraria, presupuestoBase, escala, aceptarBajas, v);
}
public static boolean ofertanteExiste(Vector<Licitador> v, Licitador l) {
Iterator<Licitador> itr = v.iterator();
while(itr.hasNext()) {
Licitador k = itr.next();
if (l.licitador.toLowerCase().equals(k.licitador.toLowerCase())) {return true;}
}
return false;
}
public static void muestraResultados(double bajaTemeraria, double presupuestoBase, int escala, int aceptarBajas, Vector<Licitador> v) {
String baja="";
int j=0,indexGanadora=0;
double max=0.0,min=0.0,punt=0.0;
DecimalFormat df = new DecimalFormat("#.##");
System.out.println("-- Se puntuaran las ofertas con \'0\' como valor minimo y \'"+escala+"\' como valor maximo");
System.out.println("-- Baja temeraria: "+df.format(bajaTemeraria));
for (int i=0;i<v.size();i++) {
if ((v.get(i).oferta)>max) {max=v.get(i).oferta;}
if (i==0) {min=v.get(i).oferta;} else {if (v.get(i).oferta<min) {min=v.get(i).oferta;}}
if (v.get(i).oferta<bajaTemeraria) {v.get(i).enBajaTemeraria=true;}
}
if (aceptarBajas==0) {
j=0;
while (j<v.size()) {
if (v.get(j).enBajaTemeraria) {
System.out.println("-- Oferta del licitador \""+v.get(j).licitador+"\" eliminada por estar en baja temeraria ("+df.format(v.get(j).oferta)+")");
v.remove(j);
j=0;
} else {
j++;
}
}
}
if (presupuestoBase>max) {max=presupuestoBase;}
if (aceptarBajas==0) {min=bajaTemeraria;}
for (int i=0;i<v.size();i++) {
v.get(i).puntuacion=(((max-v.get(i).oferta)*escala)/(max-min));
if (v.get(i).puntuacion>punt) {punt=v.get(i).puntuacion;indexGanadora=(i+1);}
}
if (indexGanadora!=0) {
System.out.println("-- Indice de la oferta ganadora: "+indexGanadora);
System.out.println("");
System.out.println("Indice;Licitador;Baja;Oferta;Puntuacion");
for (int i=0;i<v.size();i++) {
if (v.get(i).oferta<bajaTemeraria) {baja="Si";}else{baja="No";}
System.out.println((i+1)+";"+v.get(i).licitador+";"+baja+";"+df.format(v.get(i).oferta)+";"+df.format(v.get(i).puntuacion));
}
} else {
System.out.println("-- No existe ninguna oferta que cumpla los requisitos");
}
System.out.println("");
}
}
public class Licitador {
public String licitador;
public double oferta;
public boolean enBajaTemeraria;
public double puntuacion;
public Licitador(String name, double value) {
this.licitador=name;
this.oferta=value;
this.enBajaTemeraria=false;
this.puntuacion=0.0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment