[IMPROVED] Usar tarifa fullstack.rate × 176 como costo por persona-mes
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2ba3bb68ec
commit
41c40265cf
1 changed files with 57 additions and 3 deletions
|
@ -31,6 +31,11 @@ logger.addHandler(console_handler)
|
||||||
# Variable para controlar si se muestra el resultado en la consola
|
# Variable para controlar si se muestra el resultado en la consola
|
||||||
SHOW_RESULTS = True
|
SHOW_RESULTS = True
|
||||||
|
|
||||||
|
# Directorio base del proyecto
|
||||||
|
BASE_DIR = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
CONFIG_DIR = BASE_DIR / 'bin' / 'config'
|
||||||
|
RATES_DIR = CONFIG_DIR / 'rates' # Ubicación para archivos de tarifas
|
||||||
|
|
||||||
# Constantes para el modelo COCOMO básico
|
# Constantes para el modelo COCOMO básico
|
||||||
COCOMO_MODELS = {
|
COCOMO_MODELS = {
|
||||||
# [a, b, c, d] - Coeficientes para Esfuerzo = a * (KLOC^b) y Tiempo = c * (Esfuerzo^d)
|
# [a, b, c, d] - Coeficientes para Esfuerzo = a * (KLOC^b) y Tiempo = c * (Esfuerzo^d)
|
||||||
|
@ -39,6 +44,9 @@ COCOMO_MODELS = {
|
||||||
'embedded': [3.6, 1.20, 2.5, 0.32] # Proyectos complejos
|
'embedded': [3.6, 1.20, 2.5, 0.32] # Proyectos complejos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Número de horas laborables en un mes (22 días x 8 horas)
|
||||||
|
HOURS_PER_MONTH = 176
|
||||||
|
|
||||||
# Extensiones de archivo a considerar por defecto
|
# Extensiones de archivo a considerar por defecto
|
||||||
DEFAULT_EXTENSIONS = [
|
DEFAULT_EXTENSIONS = [
|
||||||
'.py', '.java', '.c', '.cpp', '.cc', '.cxx', '.h', '.hpp', '.js', '.ts',
|
'.py', '.java', '.c', '.cpp', '.cc', '.cxx', '.h', '.hpp', '.js', '.ts',
|
||||||
|
@ -242,6 +250,33 @@ def determine_cocomo_model(loc):
|
||||||
else:
|
else:
|
||||||
return 'embedded' # Proyectos grandes (más de 300K líneas)
|
return 'embedded' # Proyectos grandes (más de 300K líneas)
|
||||||
|
|
||||||
|
def get_fullstack_rate():
|
||||||
|
"""
|
||||||
|
Obtiene la tarifa por hora de un desarrollador fullstack desde el archivo de configuración.
|
||||||
|
Si el archivo no existe, devuelve un valor predeterminado de 45.00 USD/hora.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Float: Tarifa por hora en USD
|
||||||
|
"""
|
||||||
|
rate_file = RATES_DIR / "fullstack.rate"
|
||||||
|
|
||||||
|
# Comprobar si existe el archivo
|
||||||
|
if not rate_file.exists():
|
||||||
|
logger.warning(f"No se encontró el archivo de tarifa: {rate_file}")
|
||||||
|
logger.warning("Usando tarifa predeterminada de 45.00 USD/hora")
|
||||||
|
return 45.00
|
||||||
|
|
||||||
|
# Leer la tarifa del archivo
|
||||||
|
try:
|
||||||
|
with open(rate_file, 'r', encoding='utf-8') as f:
|
||||||
|
rate = float(f.read().strip())
|
||||||
|
logger.info(f"Tarifa leída desde {rate_file}: {rate:.2f} USD/hora")
|
||||||
|
return rate
|
||||||
|
except (FileNotFoundError, ValueError, IOError) as e:
|
||||||
|
logger.warning(f"Error al leer el archivo de tarifa {rate_file}: {e}")
|
||||||
|
logger.warning("Usando tarifa predeterminada de 45.00 USD/hora")
|
||||||
|
return 45.00
|
||||||
|
|
||||||
def print_results(results):
|
def print_results(results):
|
||||||
"""
|
"""
|
||||||
Imprime los resultados del cálculo COCOMO de manera formateada.
|
Imprime los resultados del cálculo COCOMO de manera formateada.
|
||||||
|
@ -268,8 +303,8 @@ if __name__ == "__main__":
|
||||||
parser.add_argument('--project', required=True, help='Ruta del directorio del proyecto a analizar')
|
parser.add_argument('--project', required=True, help='Ruta del directorio del proyecto a analizar')
|
||||||
parser.add_argument('--model', choices=['organic', 'semi-detached', 'embedded', 'auto'],
|
parser.add_argument('--model', choices=['organic', 'semi-detached', 'embedded', 'auto'],
|
||||||
default='auto', help='Tipo de modelo COCOMO a utilizar (por defecto: auto)')
|
default='auto', help='Tipo de modelo COCOMO a utilizar (por defecto: auto)')
|
||||||
parser.add_argument('--cost', type=float, default=5000.0,
|
parser.add_argument('--cost', type=float,
|
||||||
help='Costo por persona-mes en USD (por defecto: 5000)')
|
help='Costo por persona-mes en USD (por defecto: tarifa fullstack × 176)')
|
||||||
parser.add_argument('--ignore', action='append',
|
parser.add_argument('--ignore', action='append',
|
||||||
help='Patrones adicionales de archivos a ignorar')
|
help='Patrones adicionales de archivos a ignorar')
|
||||||
parser.add_argument('--ext', action='append',
|
parser.add_argument('--ext', action='append',
|
||||||
|
@ -295,6 +330,25 @@ if __name__ == "__main__":
|
||||||
print(f"ERROR: El directorio del proyecto no existe: {args.project}")
|
print(f"ERROR: El directorio del proyecto no existe: {args.project}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Verificar que el directorio de tarifas existe
|
||||||
|
if not RATES_DIR.exists():
|
||||||
|
logger.warning(f"El directorio de tarifas no existe: {RATES_DIR}")
|
||||||
|
logger.warning("Se creará el directorio y se usarán valores predeterminados.")
|
||||||
|
try:
|
||||||
|
os.makedirs(RATES_DIR, exist_ok=True)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error al crear el directorio de tarifas: {e}")
|
||||||
|
|
||||||
|
# Obtener costo por hora desde fullstack.rate y convertir a costo por persona-mes
|
||||||
|
if args.cost is None:
|
||||||
|
# Obtener la tarifa por hora y multiplicar por las horas mensuales
|
||||||
|
hourly_rate = get_fullstack_rate()
|
||||||
|
cost_per_pm = hourly_rate * HOURS_PER_MONTH
|
||||||
|
logger.info(f"Costo por hora: ${hourly_rate:.2f} × {HOURS_PER_MONTH} horas = ${cost_per_pm:.2f} por persona-mes")
|
||||||
|
else:
|
||||||
|
cost_per_pm = args.cost
|
||||||
|
logger.info(f"Usando costo por persona-mes especificado: ${cost_per_pm:.2f}")
|
||||||
|
|
||||||
# Preparar extensiones y patrones de ignorar
|
# Preparar extensiones y patrones de ignorar
|
||||||
extensions = DEFAULT_EXTENSIONS.copy()
|
extensions = DEFAULT_EXTENSIONS.copy()
|
||||||
if args.ext:
|
if args.ext:
|
||||||
|
@ -316,7 +370,7 @@ if __name__ == "__main__":
|
||||||
model_type = args.model
|
model_type = args.model
|
||||||
|
|
||||||
# Calcular estimaciones COCOMO
|
# Calcular estimaciones COCOMO
|
||||||
results = estimate_cocomo(loc, model_type, args.cost)
|
results = estimate_cocomo(loc, model_type, cost_per_pm)
|
||||||
|
|
||||||
# Añadir ruta del proyecto para la presentación
|
# Añadir ruta del proyecto para la presentación
|
||||||
results['project_path'] = str(project_path)
|
results['project_path'] = str(project_path)
|
||||||
|
|
Loading…
Reference in a new issue