Last active
August 20, 2016 20:18
-
-
Save fero23/b81362947cc211a1bcccb650b3617853 to your computer and use it in GitHub Desktop.
Creador de presupuestos en Rust on the fly
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::io::{self, Write}; | |
use std::fs::File; | |
use std::path::Path; | |
use std::rc::Rc; | |
use std::cmp; | |
use std::collections::HashMap; | |
enum TableCell { | |
TableHeader { | |
content: String, | |
rowspan: Option<usize>, | |
colspan: Option<usize> | |
}, | |
TableData { | |
content: String, | |
rowspan: Option<usize>, | |
colspan: Option<usize> | |
}, | |
EmptyCell { | |
rowspan: Option<usize>, | |
colspan: Option<usize> | |
} | |
} | |
impl TableCell { | |
fn to_html(&self) -> String { | |
match *self { | |
TableCell::TableHeader { ref content, rowspan: Some(rowspan), colspan: Some(colspan) } => { | |
format!(r#"<th rowspan="{}" colspan="{}">{}</th>"#, rowspan, colspan, content) | |
} | |
TableCell::TableHeader { ref content, rowspan: Some(rowspan), .. } => { | |
format!(r#"<th rowspan="{}">{}</th>"#, rowspan, content) | |
} | |
TableCell::TableHeader { ref content, colspan: Some(colspan), .. } => { | |
format!(r#"<th colspan="{}">{}</th>"#, colspan, content) | |
} | |
TableCell::TableHeader { ref content, .. } => { | |
format!(r#"<th>{}</th>"#, content) | |
} | |
TableCell::TableData { ref content, rowspan: Some(rowspan), colspan: Some(colspan) } => { | |
format!(r#"<td rowspan="{}" colspan="{}">{}</td>"#, rowspan, colspan, content) | |
} | |
TableCell::TableData { ref content, rowspan: Some(rowspan), .. } => { | |
format!(r#"<td rowspan="{}">{}</td>"#, rowspan, content) | |
} | |
TableCell::TableData { ref content, colspan: Some(colspan), .. } => { | |
format!(r#"<td colspan="{}">{}</td>"#, colspan, content) | |
} | |
TableCell::TableData { ref content, .. } => { | |
format!(r#"<td>{}</td>"#, content) | |
} | |
TableCell::EmptyCell { rowspan: Some(rowspan), colspan: Some(colspan) } => { | |
format!(r#"<td rowspan="{}" colspan="{}"></td>"#, rowspan, colspan) | |
} | |
TableCell::EmptyCell { rowspan: Some(rowspan), .. } => { | |
format!(r#"<td rowspan="{}"></td>"#, rowspan) | |
} | |
TableCell::EmptyCell { colspan: Some(colspan), .. } => { | |
format!(r#"<td colspan="{}"></td>"#, colspan) | |
} | |
TableCell::EmptyCell {..} => { | |
format!(r#"<td></td>"#) | |
} | |
} | |
} | |
} | |
type Row = Vec<TableCell>; | |
struct Table(Vec<Row>); | |
impl Table { | |
fn to_html(&self) -> String { | |
let table_body = self.0.iter().map(|row| { | |
format!("<tr>{}</tr>", row.iter().map(|cell| cell.to_html()).collect::<Vec<_>>().concat()) | |
}).collect::<Vec<_>>().concat(); | |
format!("<table>{}</table>", table_body) | |
} | |
} | |
struct Html(Vec<Table>); | |
impl Html { | |
fn to_html(&self) -> String { | |
format!(r#" | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<style> | |
table {{ | |
margin: 10px; | |
}} | |
table, th, td {{ | |
border: 1px solid black; | |
border-collapse: collapse; | |
}} | |
th, td {{ | |
padding: 5px; | |
text-align: left; | |
max-width: 120px; | |
}} | |
</style> | |
</head> | |
<body>{}</body> | |
</html>"#, | |
self.0.iter() | |
.map(|tb| tb.to_html()) | |
.collect::<Vec<_>>() | |
.concat()) | |
} | |
fn save_to<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { | |
let mut file = try!(File::create(path)); | |
try!(file.write_all(self.to_html().as_bytes())); | |
Ok(()) | |
} | |
} | |
#[derive(Clone)] | |
struct Costo { | |
cantidad: u32, | |
producto: String, | |
precio_unitario: f64 | |
} | |
impl Costo { | |
fn get_total(&self) -> f64 { | |
self.cantidad as f64 * self.precio_unitario | |
} | |
} | |
struct Tarea { | |
nombre: String, | |
dur: u32, | |
materiales: Vec<Costo>, | |
mano_obra: Vec<Costo>, | |
costos_indirectos: Vec<Costo> | |
} | |
impl Tarea { | |
fn new(nombre: String, dur: u32) -> Tarea { | |
Tarea { | |
nombre: nombre, | |
dur: dur, | |
materiales: Vec::new(), | |
mano_obra: Vec::new(), | |
costos_indirectos: Vec::new() | |
} | |
} | |
fn add_materiales(&mut self, material: Costo) { | |
self.materiales.push(material); | |
} | |
fn add_mano_obra(&mut self, mano_obra: Costo) { | |
self.mano_obra.push(mano_obra); | |
} | |
fn add_costo_indirecto(&mut self, costo_indirecto: Costo) { | |
self.costos_indirectos.push(costo_indirecto); | |
} | |
fn add_mano_obra_from_builders(&mut self, builders: &[Rc<Fn(u32, f64, f64, f64) -> Costo>]) { | |
for builder in builders { | |
let costo = (builder)(self.dur, | |
self.get_total_materiales(), | |
self.get_total_mano_obra(), | |
self.get_total_costo_indirectos()); | |
self.add_mano_obra(costo); | |
} | |
} | |
fn add_costo_indirecto_from_builders(&mut self, builders: &[Rc<Fn(u32, f64, f64, f64) -> Costo>]) { | |
for builder in builders { | |
let costo = (builder)(self.dur, | |
self.get_total_materiales(), | |
self.get_total_mano_obra(), | |
self.get_total_costo_indirectos()); | |
self.add_costo_indirecto(costo); | |
} | |
} | |
fn get_total_materiales(&self) -> f64 { | |
self.materiales.iter().map(|c| c.get_total()).sum() | |
} | |
fn get_total_mano_obra(&self) -> f64 { | |
self.mano_obra.iter().map(|c| c.get_total()).sum() | |
} | |
fn get_total_costo_indirectos(&self) -> f64 { | |
self.costos_indirectos.iter().map(|c| c.get_total()).sum() | |
} | |
fn get_max_row(&self) -> usize { | |
cmp::max(self.materiales.len(), cmp::max(self.mano_obra.len(), self.costos_indirectos.len())) | |
} | |
fn get_presupuesto(&self) -> Presupuesto { | |
let mut presupuesto = Presupuesto::new(); | |
for material in &self.materiales { | |
presupuesto.add_costo(Presupuesto::material(), material); | |
} | |
for mano_obra in &self.mano_obra { | |
presupuesto.add_costo(Presupuesto::mano_obra(), mano_obra); | |
} | |
for costo_indirecto in &self.costos_indirectos { | |
presupuesto.add_costo(Presupuesto::costo_indirecto(), costo_indirecto); | |
} | |
presupuesto | |
} | |
} | |
struct Actividad { | |
nombre: String, | |
tareas: Vec<Tarea> | |
} | |
impl Actividad { | |
fn add_mano_obra_from_builders(&mut self, builders: &[Rc<Fn(u32, f64, f64, f64) -> Costo>]) { | |
for task in &mut self.tareas { | |
task.add_mano_obra_from_builders(builders); | |
} | |
} | |
fn add_costo_indirecto_from_builders(&mut self, builders: &[Rc<Fn(u32, f64, f64, f64) -> Costo>]) { | |
for task in &mut self.tareas { | |
task.add_costo_indirecto_from_builders(builders); | |
} | |
} | |
fn get_dur_total(&self) -> u32 { | |
self.tareas.iter().map(|task| task.dur).sum() | |
} | |
fn get_total_materiales(&self) -> f64 { | |
self.tareas.iter().map(|task| task.get_total_materiales()).sum() | |
} | |
fn get_total_mano_obra(&self) -> f64 { | |
self.tareas.iter().map(|task| task.get_total_mano_obra()).sum() | |
} | |
fn get_total_costo_indirectos(&self) -> f64 { | |
self.tareas.iter().map(|task| task.get_total_costo_indirectos()).sum() | |
} | |
fn get_presupuesto(&self) -> Option<Presupuesto> { | |
self.tareas.iter().map(|task| task.get_presupuesto()).fold(None, |p1, p2| { | |
match p1 { | |
Some(p1) => Some(p1.merge(p2)), | |
None => Some(p2) | |
} | |
}) | |
} | |
fn get_rows(&self) -> Vec<Row> { | |
let total_rows = self.tareas.iter().map(|task| task.get_max_row() + 1).sum(); | |
self.tareas.iter().enumerate().flat_map(|(i1, task)| { | |
let mut materiales_iter = task.materiales.iter(); | |
let mut mano_obra_iter = task.mano_obra.iter(); | |
let mut costos_indirectos_iter = task.costos_indirectos.iter(); | |
let costo_total_tarea = task.get_total_materiales() + | |
task.get_total_mano_obra() + | |
task.get_total_costo_indirectos(); | |
let task_rows = task.get_max_row() + 1; | |
let mut rows = Vec::new(); | |
for i2 in 0..task_rows { | |
let mut row = Vec::new(); | |
if i2 == 0 { | |
if i1 == 0{ | |
row.push(TableCell::TableData { | |
content: self.nombre.clone(), | |
rowspan: Some(total_rows), | |
colspan: None | |
}); | |
} | |
row.push(TableCell::TableData { | |
content: task.nombre.clone(), | |
rowspan: Some(task_rows), | |
colspan: None | |
}); | |
row.push(TableCell::TableData { | |
content: task.dur.to_string(), | |
rowspan: Some(task_rows), | |
colspan: None | |
}); | |
} | |
macro_rules! add_section { | |
($iter:expr, $total:expr) => {{ | |
if let Some(costo) = $iter.next() { | |
row.push(TableCell::TableData { | |
content: costo.cantidad.to_string(), | |
rowspan: None, | |
colspan: None | |
}); | |
row.push(TableCell::TableData { | |
content: costo.producto.clone(), | |
rowspan: None, | |
colspan: None | |
}); | |
row.push(TableCell::TableData { | |
content: format!("{:.2}", costo.precio_unitario), | |
rowspan: None, | |
colspan: None | |
}); | |
row.push(TableCell::TableData { | |
content: format!("{:.2}", costo.get_total()), | |
rowspan: None, | |
colspan: None | |
}); | |
} else if i2 == task.get_max_row() { | |
row.push(TableCell::EmptyCell {rowspan: None, colspan: Some(3)}); | |
row.push(TableCell::TableData { | |
content: format!("{:.2}", $total), | |
rowspan: None, | |
colspan: None | |
}); | |
} else { | |
for _ in 0..4 { | |
row.push(TableCell::EmptyCell {rowspan: None, colspan: None}); | |
} | |
} | |
}} | |
} | |
add_section!(materiales_iter, task.get_total_materiales()); | |
add_section!(mano_obra_iter, task.get_total_mano_obra()); | |
add_section!(costos_indirectos_iter, task.get_total_costo_indirectos()); | |
if i2 == 0 { | |
row.push(TableCell::TableData { | |
content: format!("{:.2}", costo_total_tarea), | |
rowspan: Some(task_rows), | |
colspan: None | |
}); | |
} | |
rows.push(row); | |
} | |
rows.into_iter() | |
}).collect::<Vec<_>>() | |
} | |
} | |
struct CostoActividad(Vec<Actividad>); | |
impl CostoActividad { | |
fn add_costo_indirecto_from_builders(&mut self, builders: &[Rc<Fn(u32, f64, f64, f64) -> Costo>]) { | |
for actividad in &mut self.0 { | |
actividad.add_costo_indirecto_from_builders(builders); | |
} | |
} | |
fn get_presupuesto(&self) -> Option<Presupuesto> { | |
self.0.iter().map(|act| act.get_presupuesto()).fold(None, |p1, p2| { | |
match (p1, p2) { | |
(Some(p1), Some(p2)) => Some(p1.merge(p2)), | |
(Some(p1), None) => Some(p1), | |
(None, Some(p2)) => Some(p2), | |
_ => None | |
} | |
}) | |
} | |
fn as_html_table(&self) -> Table { | |
let mut dur_total = 0; | |
let mut total_materiales = 0.0; | |
let mut total_mano_obra = 0.0; | |
let mut total_costos_indirectos = 0.0; | |
let mut rows = vec![ | |
vec![ | |
TableCell::EmptyCell {rowspan: Some(2), colspan: Some(2)}, | |
TableCell::TableHeader {content: "Duración (días)".to_string(), rowspan: Some(2), colspan: None}, | |
TableCell::TableHeader {content: "Materiales directos".to_string(), rowspan: None, colspan: Some(4)}, | |
TableCell::TableHeader {content: "Mano de obra directa".to_string(), rowspan: None, colspan: Some(4)}, | |
TableCell::TableHeader {content: "Costos indirectos".to_string(), rowspan: None, colspan: Some(4)}, | |
TableCell::TableHeader {content: "Costo total por actividad".to_string(), rowspan: Some(2), colspan: None} | |
], | |
vec![ | |
TableCell::TableHeader {content: "Cantidad".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Producto".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Costo Unitario".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Total".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Cantidad".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Producto".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Costo Unitario".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Total".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Cantidad".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Producto".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Costo Unitario".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Total".to_string(), rowspan: None, colspan: None}, | |
] | |
]; | |
for actividad in &self.0 { | |
dur_total += actividad.get_dur_total(); | |
total_materiales += actividad.get_total_materiales(); | |
total_mano_obra += actividad.get_total_mano_obra(); | |
total_costos_indirectos += actividad.get_total_costo_indirectos(); | |
rows = rows.into_iter().chain(actividad.get_rows().into_iter()).collect::<Vec<_>>(); | |
} | |
let total_neto = total_materiales + total_mano_obra + total_costos_indirectos; | |
let table_body = rows.into_iter().chain(vec![vec![ | |
TableCell::EmptyCell {rowspan: None, colspan: Some(2)}, | |
TableCell::TableData {content: dur_total.to_string(), rowspan: None, colspan: None}, | |
TableCell::TableData {content: "Total de Materiales".to_string(), rowspan: None, colspan: Some(3)}, | |
TableCell::TableData {content: format!("{:.2}", total_materiales), rowspan: None, colspan: None}, | |
TableCell::TableData {content: "Total de Mano de Obra directa".to_string(), rowspan: None, colspan: Some(3)}, | |
TableCell::TableData {content: format!("{:.2}", total_mano_obra), rowspan: None, colspan: None}, | |
TableCell::TableData {content: "Total de Costos Indirectos".to_string(), rowspan: None, colspan: Some(3)}, | |
TableCell::TableData {content: format!("{:.2}", total_costos_indirectos), rowspan: None, colspan: None}, | |
TableCell::TableData {content: format!("{:.2}", total_neto), rowspan: None, colspan: None} | |
]].into_iter()).collect::<Vec<_>>(); | |
Table(table_body) | |
} | |
} | |
struct Presupuesto(HashMap<u8, HashMap<String, (u32, f64, f64)>>); | |
impl Presupuesto { | |
fn material() -> u8 { 1 } | |
fn mano_obra() -> u8 { 2 } | |
fn costo_indirecto() -> u8 { 3 } | |
fn new() -> Presupuesto { | |
Presupuesto(HashMap::new()) | |
} | |
fn add_costo(&mut self, section: u8, costo: &Costo) { | |
if self.0.contains_key(§ion) { | |
let inner_map = self.0.get_mut(§ion).unwrap(); | |
if inner_map.contains_key(&costo.producto) { | |
let &mut (ref mut cantidad, _, ref mut total) = inner_map.get_mut(&costo.producto).unwrap(); | |
*cantidad = cmp::max(*cantidad, costo.cantidad); | |
*total += costo.get_total(); | |
} else { | |
inner_map.insert(costo.producto.clone(), (costo.cantidad, costo.precio_unitario, costo.get_total())); | |
} | |
} else { | |
let mut new_map = HashMap::new(); | |
new_map.insert(costo.producto.clone(), (costo.cantidad, costo.precio_unitario, costo.get_total())); | |
self.0.insert(section, new_map); | |
} | |
} | |
fn merge(mut self, other: Presupuesto) -> Presupuesto { | |
for (key, other_inner_map) in other.0.iter() { | |
if self.0.contains_key(key) { | |
let self_inner_map = self.0.get_mut(key).unwrap(); | |
for (product, &(c1, precio_unitario, t1)) in other_inner_map.iter() { | |
if self_inner_map.contains_key(product) { | |
let &mut (ref mut c2, _, ref mut t2) = self_inner_map.get_mut(product).unwrap(); | |
*c2 = cmp::max(*c2, c1); | |
*t2 += t1; | |
} else { | |
self_inner_map.insert(product.clone(), (c1, precio_unitario, t1)); | |
} | |
} | |
} else { | |
self.0.insert(*key, other_inner_map.clone()); | |
} | |
} | |
self | |
} | |
fn as_html_table(&self) -> Table { | |
let mut total_materiales = 0.0; | |
let mut total_mano_obra = 0.0; | |
let mut total_costos_indirectos = 0.0; | |
let mut rows = vec![vec![ | |
TableCell::TableHeader {content: "Cantidad".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Productos".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Costo Unitario".to_string(), rowspan: None, colspan: None}, | |
TableCell::TableHeader {content: "Total".to_string(), rowspan: None, colspan: None}, | |
]]; | |
macro_rules! add_table_section_rows { | |
($key:expr, $counter:ident) => {{ | |
if let Some(map) = self.0.get(&$key) { | |
$counter += map | |
.iter() | |
.map(|(_, &(_, _, total))| total) | |
.sum(); | |
rows = rows.into_iter().chain(map | |
.iter() | |
.map(|(producto, &(cantidad, precio_unitario, total))| { | |
vec![ | |
TableCell::TableData {content: cantidad.to_string(), rowspan: None, colspan: None}, | |
TableCell::TableData {content: producto.clone(), rowspan: None, colspan: None}, | |
TableCell::TableData {content: format!("{:.2}", precio_unitario), rowspan: None, colspan: None}, | |
TableCell::TableData {content: format!("{:.2}", total), rowspan: None, colspan: None} | |
] | |
} | |
)).collect::<Vec<_>>(); | |
} | |
}} | |
} | |
add_table_section_rows!(Presupuesto::material(), total_materiales); | |
rows.push(vec![ | |
TableCell::TableData {content: "Total de Materiales".to_string(), rowspan: None, colspan: Some(3)}, | |
TableCell::TableData {content: format!("{:.2}", total_materiales), rowspan: None, colspan: None}, | |
]); | |
add_table_section_rows!(Presupuesto::mano_obra(), total_mano_obra); | |
rows.push(vec![ | |
TableCell::TableData {content: "Total de Mano de Obra".to_string(), rowspan: None, colspan: Some(3)}, | |
TableCell::TableData {content: format!("{:.2}", total_mano_obra), rowspan: None, colspan: None}, | |
]); | |
add_table_section_rows!(Presupuesto::costo_indirecto(), total_costos_indirectos); | |
rows.push(vec![ | |
TableCell::TableData {content: "Total de Costos Indirectos".to_string(), rowspan: None, colspan: Some(3)}, | |
TableCell::TableData {content: format!("{:.2}", total_costos_indirectos), rowspan: None, colspan: None}, | |
]); | |
let total_costos = total_materiales + total_mano_obra + total_costos_indirectos; | |
rows.push(vec![ | |
TableCell::TableData {content: "Total de Costos".to_string(), rowspan: None, colspan: Some(3)}, | |
TableCell::TableData {content: format!("{:.2}", total_costos), rowspan: None, colspan: None}, | |
]); | |
Table(rows) | |
} | |
} | |
fn create_builder_mano_obra(puesto: &'static str, cantidad: u32, salario_base: f64) -> | |
Rc<Fn(u32, f64, f64, f64) -> Costo> | |
{ | |
Rc::new(move |dur, _, _, _| Costo { | |
cantidad: cantidad, | |
producto: puesto.to_string(), | |
precio_unitario: salario_base / 30.0 * dur as f64 | |
}) | |
} | |
fn main() { | |
const TASA_CAMBIO_DOLAR: f64 = 28.66; | |
//Materiales | |
let m1 = Costo { | |
producto: "LibreOffice".to_string(), | |
cantidad: 4, | |
precio_unitario: 0.0 | |
}; | |
let m2 = Costo { | |
producto: "Arch Linux".to_string(), | |
cantidad: 4, | |
precio_unitario: 0.0 | |
}; | |
let m3 = Costo { | |
producto: "StarUML 2".to_string(), | |
cantidad: 4, | |
precio_unitario: 0.0 | |
}; | |
let m4 = Costo { | |
producto: "Android Studio".to_string(), | |
cantidad: 4, | |
precio_unitario: 0.0 | |
}; | |
let m5 = Costo { | |
producto: "Visual Studio Code".to_string(), | |
cantidad: 4, | |
precio_unitario: 0.0 | |
}; | |
let m6 = Costo { | |
producto: "Phoenix Framework".to_string(), | |
cantidad: 8, | |
precio_unitario: 0.0 | |
}; | |
let m7 = Costo { | |
producto: "Licencia de Google Play Store".to_string(), | |
cantidad: 1, | |
precio_unitario: 25.0 * TASA_CAMBIO_DOLAR | |
}; | |
let m8 = Costo { | |
producto: "Licencia de la App Store".to_string(), | |
cantidad: 1, | |
precio_unitario: 99.0 * TASA_CAMBIO_DOLAR | |
}; | |
let m9 = Costo { | |
producto: "Paquete de instancias de AWS EC2 Linux t2.medium + Disco Duros".to_string(), | |
cantidad: 1, | |
precio_unitario: 153.13 * TASA_CAMBIO_DOLAR | |
}; | |
let m10 = Costo { | |
producto: "Paquete de instancias de AWS RDS t2.medium".to_string(), | |
cantidad: 1, | |
precio_unitario: 100.72 * TASA_CAMBIO_DOLAR | |
}; | |
//Mano de obra | |
let analista = create_builder_mano_obra("Analista de Sistemas", 1, 12500.0); | |
let programador_1 = create_builder_mano_obra("Programador", 1, 10000.0); | |
let programador_2 = create_builder_mano_obra("Programador", 2, 10000.0); | |
let dba = create_builder_mano_obra("Administrador de Base de Datos", 1, 10000.0); | |
//Costos indirectos | |
let costo_papel = Costo { | |
producto: "Papelería".to_string(), | |
cantidad: 1, | |
precio_unitario: 50.0 | |
}; | |
let costo_transporte = Rc::new(move |dur, _, _, _| Costo { | |
cantidad: dur, | |
producto: "Transporte de mano de obra".to_string(), | |
precio_unitario: 150.0 | |
}); | |
let costo_electricidad = Rc::new(move |dur, _, _, _| Costo { | |
cantidad: 1, | |
producto: "Luz eléctrica".to_string(), | |
precio_unitario: 2.4 * 8.0 * dur as f64 | |
}); | |
let costo_internet_builder = |cantidad| Rc::new(move |_, _, _, _| Costo { | |
cantidad: cantidad, | |
producto: "Internet".to_string(), | |
precio_unitario: 550.0 | |
}); | |
let costo_dep_pc = |cantidad| Rc::new(move |dur, _, _, _| Costo { | |
cantidad: cantidad, | |
producto: "Depreciación de computadoras".to_string(), | |
precio_unitario: [22.91, 58.33, 31.25, 14.5] | |
.iter() | |
.map(|pd| pd * TASA_CAMBIO_DOLAR) | |
.sum::<f64>() / 30.0 * dur as f64 / 4.0 /*4 pcs*/ | |
}); | |
let costo_impuestos_prof = Rc::new(move |_, _, mano_obra, _| Costo { | |
cantidad: 1, | |
producto: "Impuestos por servicios profesionales".to_string(), | |
precio_unitario: mano_obra * 0.1 | |
}); | |
//Actividad 1 | |
let mut t1_1 = Tarea::new("Inpección de la infraestructuara del MTI".to_string(), 3); | |
let mut t1_2 = Tarea::new("Recolección de requerimientos del negocio".to_string(), 10); | |
let mut t1_3 = Tarea::new("Elaboración de presupuesto y contrato".to_string(), 10); | |
let mut t1_4 = Tarea::new("Elaboración del concepto del sistema".to_string(), 5); | |
let mut t1_5 = Tarea::new("Elaboración del plan de gestión de riesgos".to_string(), 2); | |
t1_1.add_costo_indirecto(costo_papel.clone()); | |
t1_1.add_materiales(m1); | |
t1_1.add_materiales(m2); | |
t1_1.add_costo_indirecto_from_builders(&[costo_transporte.clone()]); | |
t1_2.add_costo_indirecto(costo_papel.clone()); | |
t1_2.add_costo_indirecto_from_builders(&[costo_transporte.clone()]); | |
t1_3.add_costo_indirecto(costo_papel.clone()); | |
t1_3.add_costo_indirecto_from_builders(&[costo_electricidad.clone()]); | |
t1_4.add_costo_indirecto_from_builders(&[costo_electricidad.clone()]); | |
t1_5.add_costo_indirecto_from_builders(&[costo_electricidad.clone()]); | |
let mut t1 = Actividad { | |
nombre: "Actividad 1: Concepción".to_string(), | |
tareas: vec![t1_1, t1_2, t1_3, t1_4, t1_5] | |
}; | |
t1.add_costo_indirecto_from_builders(&[costo_dep_pc(1), costo_internet_builder(1)]); | |
t1.add_mano_obra_from_builders(&[analista.clone()]); | |
//Actividad 2 | |
let mut t2_1 = Tarea::new("Análisis de requerimientos del sistema".to_string(), 5); | |
let t2_2 = Tarea::new("Elaboración de casos de uso".to_string(), 3); | |
let t2_3 = Tarea::new("Diseño de componentes a nivel arquitectónico".to_string(), 7); | |
let t2_4 = Tarea::new("Elaboración del plan de pruebas".to_string(), 2); | |
let t2_5 = Tarea::new("Especificación del sistema".to_string(), 13); | |
let t2_6 = Tarea::new("Iteración II".to_string(), 15); | |
t2_1.add_materiales(m3); | |
let mut t2 = Actividad { | |
nombre: "Actividad 2: Elaboración".to_string(), | |
tareas: vec![t2_1, t2_2, t2_3, t2_4, t2_5, t2_6] | |
}; | |
t2.add_costo_indirecto_from_builders(&[ | |
costo_electricidad.clone(), | |
costo_dep_pc(2), | |
costo_internet_builder(2) | |
]); | |
t2.add_mano_obra_from_builders(&[analista.clone(), programador_1.clone()]); | |
//Actividad 3 | |
let mut t3_1 = Tarea::new("Construcción de componentes individuales".to_string(), 30); | |
let mut t3_2 = Tarea::new("Integración de componentes".to_string(), 15); | |
let mut t3_3 = Tarea::new("Ejecución del plan de pruebas".to_string(), 45); | |
let mut t3_4 = Tarea::new("Iteración II".to_string(), 25); | |
let mut t3_5 = Tarea::new("Iteración III".to_string(), 20); | |
t3_1.add_materiales(m4); | |
t3_1.add_materiales(m5); | |
t3_1.add_materiales(m6); | |
t3_1.add_materiales(m7); | |
t3_1.add_materiales(m8); | |
t3_1.add_materiales(m9); | |
t3_1.add_materiales(m10); | |
t3_1.add_mano_obra_from_builders(&[programador_2.clone()]); | |
t3_1.add_costo_indirecto_from_builders(&[costo_internet_builder(2), costo_dep_pc(2)]); | |
t3_2.add_mano_obra_from_builders(&[programador_2.clone()]); | |
t3_2.add_costo_indirecto_from_builders(&[costo_internet_builder(2), costo_dep_pc(2)]); | |
t3_3.add_mano_obra_from_builders(&[analista.clone(), dba.clone()]); | |
t3_3.add_costo_indirecto_from_builders(&[costo_internet_builder(2), costo_dep_pc(2)]); | |
t3_4.add_mano_obra_from_builders(&[ | |
programador_2.clone(), | |
analista.clone(), | |
dba.clone() | |
]); | |
t3_4.add_costo_indirecto_from_builders(&[costo_internet_builder(4), costo_dep_pc(4)]); | |
t3_5.add_mano_obra_from_builders(&[ | |
programador_2.clone(), | |
analista.clone(), | |
dba.clone() | |
]); | |
t3_5.add_costo_indirecto_from_builders(&[costo_internet_builder(4), costo_dep_pc(4)]); | |
let mut t3 = Actividad { | |
nombre: "Actividad 3: Construcción".to_string(), | |
tareas: vec![t3_1, t3_2, t3_3, t3_4, t3_5] | |
}; | |
t3.add_costo_indirecto_from_builders(&[costo_electricidad.clone()]); | |
//Actividad 4 | |
let t4_1 = Tarea::new("Migración de componentes al entorno de producción".to_string(), 7); | |
let t4_2 = Tarea::new("Verificación de funcionalidad en producción".to_string(), 15); | |
let t4_3 = Tarea::new("Evaluar retroalimentación del usuario".to_string(), 8); | |
let t4_4 = Tarea::new("Iteración II".to_string(), 20); | |
let mut t4 = Actividad { | |
nombre: "Actividad 4: Ejecución".to_string(), | |
tareas: vec![t4_1, t4_2, t4_3, t4_4] | |
}; | |
t4.add_costo_indirecto_from_builders(&[ | |
costo_electricidad.clone(), | |
costo_dep_pc(2), | |
costo_internet_builder(2) | |
]); | |
t4.add_mano_obra_from_builders(&[analista, dba]); | |
let mut costo_actividad = CostoActividad(vec![t1, t2, t3, t4]); | |
costo_actividad.add_costo_indirecto_from_builders(&[costo_impuestos_prof]); | |
let html = Html(vec![ | |
costo_actividad.as_html_table(), | |
costo_actividad.get_presupuesto().unwrap().as_html_table() | |
]); | |
html.save_to("output.html").unwrap(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment