Home RSS 2.0 ATOM 1.0  CDF  
 
CodeSegment - Carlos Segura Sanz (blog)
 

No se si lo he comentado alguna vez, pero en el trabajo suelo usar mucho Excel para hacer una gran variedad de cosas, en general mucho de lo que tiene que ver con el área económico financiera (lo terminamos haciendo en Excel).

Muchas de nuestras hojas de cálculo, son planes financieros, estudios de viabilidad, análisis etc. Básicamente estas hojas planifican cobros y pagos ó gastos e ingresos, la cuestión es la planificación, en Excel podemos planificar todo aquello que queramos, es sencillo podemos establecer una fila para cada previsión a realizar y en cada columna podemos poner un periodo (ene, feb, mar…), por último en cada celda (previsión / periodo) el importe de dicha previsión.


El problema se complica un poco cuando el importe de cada previsión no tiene un periodo fijo, sino que este debe establecerse en función de otra variable. Supongamos que tenemos que realizar una previsión entre dos periodos dados (Inicio y Final) y el importe debe ser proporcional al número de periodos.



Como es lógico las formulas se nos van complicando, más y más en función de las condiciones que necesitamos. Con lo que terminamos creando nuestras funciones en VBA para simplificar el proceso.

Function csPDistB(importe As Integer, periodo As Integer, inicio As Integer, fin As Integer)
 
    If (periodo >= inicio) And (periodo <= fin) Then
        csPDistB = importe / ((fin - inicio) + 1)
    End If
    
End Function

Realizaría el mismo trabajo que las formulas vistas. Dándole una vuelta más podemos crear una función matricial para hacer la misma tarea y que automáticamente tome el periodo actual en función del rango en donde se encuentre.

Public Function csPDistB(importe As Variant, primero As Integer, ultimo As Integer) As Variant
    Dim i As Integer
    Dim nPeriodos As Integer
    Dim valor As Double
    ReDim a(0 To Application.Caller.Rows.Count, 0 To Application.Caller.Columns.Count) As Variant
            
    On Error GoTo Handler
    
    nPeriodos = ultimo - primero
    valor = CDbl(importe / (nPeriodos + 1))
            
    For i = 0 To Application.Caller.Columns.Count
        If i + 1 >= primero And i + 1 <= ultimo Then
           a(0, i) = valor
        End If
    Next
        
    csPDistB = a
    Exit Function
Handler:
    csPDistB = CVErr(2015)  'xlErrNum = 2036
End Function

Por último con una pequeñas modificaciones sobre este código podemos crear funciones más complejas para nuestras planificaciones, por ejemplo distribuciones en función de una curva de porcentajes, 25%, 50% y 25% sería el 25% en el primer tercio, el 50% en el segundo tercio y el 25% en el tercer tercio del tiempo.

Public Function csPDistCP(importe As Variant, ParamArray porcentajes()) As Variant
    Dim i As Integer
    Dim nParte As Integer
    Dim p As Integer
    ReDim a(Application.Caller.Columns.Count) As Variant
            
    On Error GoTo Handler
    
    nParte = (UBound(a) + 1) / (UBound(porcentajes) + 1)
    p = -1
    For i = 0 To UBound(a)
      If i Mod Int(nParte) = 0 Then
         If p < UBound(porcentajes) Then
            p = p + 1
         End If
      End If
 
      a(i) = CDbl((importe / nParte) * porcentajes(p))
    Next
        
    csPDistCP = a
    Exit Function
Handler:
    csPDistCP = CVErr(2015)  'xlErrNum = 2036
End Function

Un último ejemplo en donde realizamos previsiones los periodos indicados, el importe proporcional al número de periodos.

 
Public Function csPDistP(importe As Variant, ParamArray periodos()) As Variant
    Dim i As Integer
    Dim nPeriodos As Integer
    Dim valor As Double
    ReDim a(Application.Caller.Columns.Count) As Variant
            
    On Error GoTo Handler
    
    nPeriodos = UBound(periodos)
    valor = CDbl(importe / (nPeriodos + 1))
            
    For i = 0 To nPeriodos
        a(periodos(i)) = valor
    Next
        
    csPDistP = a
    Exit Function
Handler:
    csPDistP = CVErr(2015)  'xlErrNum = 2036
End Function

 

Tuesday, March 28, 2006 12:21:15 AM (Hora de verano romance, UTC+02:00)   #    Comments [0]   Excel  | 

Estos dan las charlas

Este me bautiza

Este soy yo bautizado como em-vi-pi

Estas son las relaciones sociales

Ah... también trabajamos un poquito (si se le puede llamar trabajo :-)

 

Monday, March 27, 2006 10:22:14 PM (Hora de verano romance, UTC+02:00)   #    Comments [1]   Misc  | 

Durante la semana pasada me ha tocado ejercer de administrador de sistemas… he tenido poco tiempo para programar, pero sigo dándole vueltas al inforpathviewer así como algún que otro proyecto que tengo en mente.

Como administrador de sistemas la semana pasada reemplacé un controlador de dominio Windows 2003 por una nueva máquina manteniendo el nombre del anterior, un trabajo que a priori parecía sencillo se convirtió en una ardua tarea…. (vamos, lo de siempre) os dejo aquí un pequeño resumen de lo más y menos destacable.

Escenario: Servidor HP NetServer LC3 (DC + DNS+ DHCP + FileServer + PrintServer) que debía ser reemplazado por un Proliant ML 350 G3 e instalado en un rack donde el NetServer estaba de pie.

Episodio 1

El año pasado, instalaron el armario rack (60x90) según las especificaciones enviadas desde la central.
Cuando llegué me encontré un armario de (60x90) pero con la puerta colocada en el lado de 90 …. Ehhhh ….  (¿Haber como instalo aquí un cacharro con un fondo de 75?)

Episodio 2

Pido un servidor nuevo, más pequeño para poder ponerlo sobre una bandeja (Proliant ML 110 – 2Gb – 2x160Gb). Una logística increíble lo consigo tener en menos de 12 horas.

Episodio 3

La idea es poner los discos en una configuración RAID 1 usando la tarjeta integrada en el Proliant. Unir los dos discos en la BIOS de la tarjeta, no tiene precio 8 horas.

Episodio 4

No me quede esperando con lo que pude dormir unas horas…

Episodio 5

Instalación de Windows 2003, todo pintaba bien… pero Windows 2003 no reconoce la IDE SATA que trae el ML110 … ¿Qué hacer? Buscar los drivers, preparar un disco con ellos e introducirlo en el momento que la instalación nos solicita los drivers del fabricante. PERO …. El ML110 no trae unidad de disco…. No importa .. se desmonta una de un equipo Y?????????????? el ML110 no trae conector de unidad de disco por lo que es imposible conctarla, ¿Funcionará un lapiz USB? Pués NO.

Episodio 6

El tiempo apremia y hay un montón de cosas por hacer durante el viaje…. Hay que tomar una decisión YA.
El RAID funcionará por Software.

Episodio 7

Instalación del nuevo servidor, con Windows 2003. Ok, sin problemas. Lo llamo SrvDelegacion2.

Episodio 8

Copio todos los datos de SrvDelegacion a SrvDelegacion2, dedicándole muchas horas ya que cuando se encuentra con rutas largas la copia se detiene.

Episodio 9

Una vez copiados los datos, degradamos el SrvDelegacion. Se produce un error antes de finalizar (esto ya me ha pasado en alguna ocasión), se insiste y se le vuelve ha hacer el DCPROMO para degradarlo. La segunda intentona con ÉXITO.
Detenemos DNS y DHCP.
Renombramos el equipo como SrvDelegacionOld, nos conectamos por Terminal a la central y forzamos todas las replicas de directorio activo.

Episodio 10

Después de esperar un tiempo a que las replicas concluyerán. Instalamos DNS y DHCP en el SrvDelegacion2, y le cambiamos el nombre a SrvDelegacion. Nos volvemos a conectar a la central y forzamos replicas.

Episodio 11

Promocionamos SrvDelegacion a Controlador de dominio, BIEN, todo correcto a la primera.
Sitios y servicios de Active directory y configuramos la replicación.

Episodio 12

Restablecemos los permisos, creamos las colas de impresión.

Episodio 13

Instalación del DLT… humm, desmonto el DLT con su SCSI PCI y????? el ML110 ya no usa PCI solo PCI Express… Hablo con mi proveedor que vuelve ha hacer magia y me consigue una tarjeta en unas horas.

Episodio 14

Viernes, 17 de Marzo, el tren sale puntual y yo voy en el con la satisfacción de haber cumplido el trabajo, luce el sol y la película que ponen es una mierda.

Tuesday, March 21, 2006 10:49:05 PM (Hora estándar romance, UTC+01:00)   #    Comments [0]   Misc  | 

This is my first attempt to do an infopath viewer webpart, this is only a test version that run. To run this webpart you need fill the properties, list (form library) field name of the field that you want show in the combo box to select the form and the xsl to render it. (You can extract it from the infopath solution file, rename it as a .cab file and extract the xsl, then copy the content into the xsl property)

  csegInfopathViewer.zip (6,82 KB) 

 

Tuesday, March 14, 2006 8:12:43 PM (Hora estándar romance, UTC+01:00)   #    Comments [5]   csegInfoPathViewer | SharePoint  | 

Estoy trabajando en un pequeño webpart que espero haga las delicias de alguno que otro, todavía estoy puliendo algunas cosillas, pero espero tenerlo listo en unos días. El susodicho, es un visor de formularios de InfoPath, por el momento funciona (que no es poco), os dejo una pantallita de como va al cosa ...

La idea es indicarle una biblioteca de documentos en donde se encuentran los formularios y la vista que se desea. Como siempre Ideas .. Ideas .. Ideas

Sunday, March 12, 2006 9:18:17 PM (Hora estándar romance, UTC+01:00)   #    Comments [10]   csegInfoPathViewer | SharePoint-es  | 

Ayer por la noche ayudando a un amigo ha depurar un webpart para añadir automáticamente áreas dentro de un portal. He revisado el código que me ha pasado por que según me cuenta en la máquina de pruebas todo funcionaba correctamente sin embargo en la máquina de producción daba un error cuando se trataba de obtener el contexto del Portal.

El valor no puede ser nulo. Nombre del parámetro: site
at Microsoft.SharePoint.Portal.PortalApplication.GetContext(PortalSite site, PortalZone zone)
at Microsoft.SharePoint.Portal.PortalApplication.GetContext(PortalSite site)

He recordado que no era la primera vez que me veía este error y me ha costado un poco recordar el problema, así que aquí queda.

Uri uri = new Uri(portalUrl);
output.Write("Url: {0}<br/>", uri.ToString()); 				// 172.26.3.3	
TopologyManager topologyManager = new TopologyManager();
PortalSite site = topologyManager.PortalSites[uri];
PortalContext portalContext = PortalApplication.GetContext(site);  	// ERROR

 

El problema está en que no se han configurado correctamente las rutas de acceso alternativas al portal y SharePoint es muy sensible con estas cosas.

Para solucionarlo basta con indicarle alguna de las otras direcciones. Es muy común que un portal publicado internet / intranet tenga dos direcciones, una para los accesos internos y otra para los externos, cada uno será resuelto por un DNS distinto.

Wednesday, March 08, 2006 8:12:10 PM (Hora estándar romance, UTC+01:00)   #    Comments [0]   SharePoint-es  | 

Hace ya algún tiempo  Mark Bower, explicaba como personalizar el menú de opciones con un bonito ejemplo para enviar el enlace de un documento por correo electrónico. Este fin de semana he tratado de mejorarlo, ya que enviar un enlace está muy bien cuando se envían correos a personas de la misma empresa, evitando duplicar información. Sin embargo si queremos enviar dicho documento a una persona del exterior, tenemos que salvar primero el documento en el escritorio para después adjuntarlo a un mensaje.

Basándome el código de Mark, lo que he hecho ha sido añadir una función en javascript que llama vía activex a outlook, crea un nuevo mensaje,  y le añade el documento seleccionado. Hay que tener en cuenta que para usar este control el sitio debe ser seguro (Herramientas->Opciones de Internet->Seguridad->Sitios->Sitios de confianza) de lo contrario el nos dará el error "Error El servidor de Automatización no puede crear el objeto".

// SendByMail
// Send the file as attachment
function SendMessage(URL)
{
  try 
  {
     var outlook = new ActiveXObject("Outlook.Application");
     var msg = outlook.CreateItem(0);
        
     var atach = msg.Attachments(); 
     
     msg.display();     
     atach.Add(URL);                       
  }
  catch(e)
  {
     alert("Error "+e.description); 
  }
}

 

Monday, March 06, 2006 10:39:14 PM (Hora estándar romance, UTC+01:00)   #    Comments [2]   SharePoint-es  | 

Trying to do a simple mail merge using an excel workbook as data list, stored in SharePoint.

No comment.

Saturday, March 04, 2006 10:47:29 PM (Hora estándar romance, UTC+01:00)   #    Comments [0]    | 

Estos días he estado trabajando en una nueva biblioteca de clases para SharePoint, bueno, en parte nueva y en parte adaptando a mis necesidades  algunas de las clases del SDK, (¡Que grande es la POO!). Aquí como siempre existirán discrepancias en cuanto al diseño, allí donde se reúnan programadores siempre habrá más puristas y otros más prácticos. Yo me decanto por los segundos. Con esto no quiero decir que estropee la magia de una clase introduciendo metodusHorribilis, pero sí que soy partidario de subclasear aquello que dispone de una interfaz poco agradable, creando una fachada más práctica y coherente con la aplicación que se está desarrollando, de este modo más adelante podremos intercambiar el subsistema haciendo unos pequeños cambios en nuestra subclase sin retocar nada más.

Bueno, dejándonos de teorías la cosa empezó con las interfaces de conexión de los WebParts. A mi juicio un claro ejemplo de interfaz poco agradable (probar a tener un interfaz ICellProvider y un ICellConsumer en el mismo WebPart), pero se le puede buscar la vuelta realizándolo con dos clases una CellConsumer y otra CellProvider, cada una con su correspondiente interfaz para después registrarlos en el EnsureInterfaces(), de este modo podemos usar tantos interfaces de conexión como deseemos en un mismo webpart.

Basándome en las clases auxiliares, un CellProvider siempre proveerá una celda y CellConsumer siempre consumirá una celda por lo tanto esas clases pueden quedar fijas e instanciarse con un  nombre de interfaz de conexión cuando se deseen usar.

Para mejorar la fachada que nos ofrece la clase WebPart, la idea es crear en nuestra subclase una tabla ó lista donde iremos añadiendo las distintas interfaces, también he incluido los métodos engorrosos que debemos usar siempre que usamos interfaces de conexión PartCommunicationConnect, PartCommunicationInit, PartCommunicationMain. De este modo si hemos añadido interfaces de conexión a nuestra clase ellos deberán actuar en consecuencia.

 

 

Básicamente añadir interfaces de conexión sería algo como esto

    public class csegTestLibrary : csegWebPart
    {
        private const string defaultText = "";
        private string text = defaultText;
 
        private string sProvider = "Test Cell";
        private string sProvider2 = "Test Cell 2";
        // csegWebPart Connection interfaces
        WebPartCellConsumer cellConsumer;
        WebPartCellProvider cellProvider;
        WebPartCellProvider cellProvider2;
        
        #region WEBPART CONSTRUCTOR
public csegTestLibrary()
        {
            cellConsumer = new WebPartCellConsumer("csegRollUpConsumer");
            cellProvider = new WebPartCellProvider("csegRollUpProvider");
            cellProvider2 = new WebPartCellProvider("csegRollUpProvider2");
            
            AddInterface(new WebPartConnectionInterface(
                    "ICellConsumer",
                    WebPart.UnlimitedConnections,                
                    ConnectionRunAt.Server,                        
                    cellConsumer,                                        
                    "csegCellConsumer",                                                                
                    "Get cell from",                                                                    
                    "Consumes a cell"
                ));
 
            AddInterface(new WebPartConnectionInterface(
                    "ICellProvider",
                    WebPart.UnlimitedConnections,                
                    ConnectionRunAt.Server,                        
                    cellProvider,                                        
                    "csegCellProvider",                                                                
                    "Set cell from",                                                                    
                    "Provide a cell"
                ));
            
            AddInterface(new WebPartConnectionInterface(
                    "ICellProvider",
                    WebPart.UnlimitedConnections,
                    ConnectionRunAt.Server,
                    cellProvider2,
                    "csegCellProvider2",    
                    "Set a second cell from",
                    "Provide a second cell"
                ));        
        }
        #endregion

 

Y para enviar y recibir las celdas bastaría con

        #region WEBPART INTERFACES
        public override void InitConsumers()
        {
            if (cellConsumer.IsConnected)
            {
                cellConsumer.FireInit("Celda", "CeldaNombre");
            }
        }
 
        public override void InitProviders()
        {
            //Is it connected
            if (cellProvider.IsConnected)
            {
                cellProvider.Fire(sProvider);
            }
 
            //Is it connected
            if (cellProvider2.IsConnected)
            {
                cellProvider2.Fire(sProvider2);
            }
        }
        #endregion

Y el resultado

Continuará.....

Wednesday, March 01, 2006 11:41:36 PM (Hora estándar romance, UTC+01:00)   #    Comments [0]   NET Development | SharePoint-es  | 


Copyright © 2008 Carlos Segura. All rights reserved.