]> git.llucax.com Git - mecon/meconlib.git/blob - lib/MLIB/Feriado.php
Se modifican los prefijos de los estilos.
[mecon/meconlib.git] / lib / MLIB / Feriado.php
1 <?php /* vim: set binary expandtab tabstop=4 shiftwidth=4 textwidth=80:
2 -------------------------------------------------------------------------------
3                                     mlib
4 -------------------------------------------------------------------------------
5 This file is part of mlib.
6
7 mlib is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2 of the License, or (at your option)
10 any later version.
11
12 mlib is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15  
16 You should have received a copy of the GNU General Public License; if not,
17 write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 Boston, MA  02111-1307  USA
19 -------------------------------------------------------------------------------
20 Creado: mié abr 10 18:05:33 ART 2002                               |
21 Autor:  Leandro Lucarella <llucar@mecon.gov.ar>
22 -------------------------------------------------------------------------------
23 $Id$
24 -----------------------------------------------------------------------------*/
25
26 require_once 'Date.php';
27 require_once 'Date/Span.php';
28 require_once 'PEAR.php';
29
30 /**
31  * Información sobre feriados.
32  *
33  * Abstracción para hacer ABM sobre la información de los días feriados.
34  * También sirve para hacer consultas y búsquedas.
35  *
36  * @package HE
37  * @version $Rev$
38  * @author  Leandro Lucarella <llucar@mecon.gov.ar>
39  * @todo Probar. Agregar _updateDBInfo() a todas las funciones de Date que
40  *       modifiquen la fecha.
41  */
42 class MLIB_Feriado extends Date {
43
44     /**
45      * Base de datos a usar para las consultas.
46      * @private
47      */
48     var $_db;
49
50     /**
51      * Tipo de día (Feriado, Laborable o No Laborable).
52      * @private
53      */
54     var $_tipo;
55
56     /// Hora en la que empieza el feriado.
57     var $desde;
58
59     /// Descripción del feriado.
60     var $descripcion;
61
62     function MLIB_Feriado($db, $date = null) {
63         $this->_db = $db;
64         parent::Date($date);
65     }
66
67     function setDate($date = null) {
68         parent::setDate($date);
69         $this->_updateDBInfo($date);
70     }
71
72     function copy($date) {
73         parent::copy($date);
74         if (@$date->_tipo) {
75             $this->_tipo = $date->_tipo;
76             $this->desde = $date->desde;
77             $this->descripcion = $date->descripcion;
78         } else {
79             $this->_updateDBInfo();
80         }
81     }
82
83     function setYear($y) {
84         parent::setYear($y);
85         $this->_updateDBInfo();
86     }
87
88     function setMonth($m) {
89         parent::setMonth($m);
90         $this->_updateDBInfo();
91     }
92
93     function setDay($d) {
94         parent::setDay($d);
95         $this->_updateDBInfo();
96     }
97
98     function setHour($h) {
99         parent::setHour($h);
100         $this->_updateDBInfo();
101     }
102
103     function setMinute($m) {
104         parent::setMinute($m);
105         $this->_updateDBInfo();
106     }
107
108     function setSecond($s) {
109         parent::setSecond($s);
110         $this->_updateDBInfo();
111     }
112
113     function _updateDBInfo() {
114         // Resetea valores.
115         $this->desde = null;
116         $this->descripcion = null;
117         // Se fija según el tipo de día.
118         $dia = $this->format('%w');
119         switch ($dia) {
120             case 0: // Domingo.
121                 $this->_tipo = 'feriado';
122                 break;
123             case 6: // Sábado.
124                 $tipo = 'no laborable';
125                 // sigue abajo, no hay break.
126             default: // Cualquier día.
127                 $this->_tipo = isset($tipo) ? $tipo : 'laborable';
128                 // Verificamos si hay algo en la DB.
129                 $fecha = $this->getDate();
130                 $datos = $this->_db->getRow("SELECT * FROM novedades.feriados WHERE fecha = '".$fecha."'", null, DB_FETCHMODE_ASSOC);
131                 // Si hay un error, lo pasamos a quien nos llama.
132                 if (DB::isError($datos)) {
133                     return $datos;
134                 // Si hay un resultado, actualizamos los datos.
135                 } elseif ($datos) {
136                     $this->_tipo = $datos['tipo'];
137                     $this->desde = $datos['desde'];
138                     $this->descripcion = $datos['descripcion'];
139                 }
140         }
141         return true;
142     }
143
144     /**
145      * Obtiene el tipo de día (teniendo en cuenta la hora).
146      * 
147      * Si el día es asueto se fija la hora almacenada en esta fecha y devuelve
148      * 'asueto' o 'laborable' dependiendo de a partir de qué hora se declaró el
149      * asueto.
150      *
151      * @return 'laborable', 'no laborable', 'asueto' o 'feriado'.
152      */
153     function getTipo() {
154         if ($this->_tipo == 'asueto') {
155             $desde = new Date_Span($this->desde);
156             $hora = new Date_Span($this->format('%H:%M'));
157             if ($hora->greaterEqual($desde)) {
158                 return $this->_tipo;
159             } else {
160                 // Posible pitfall, en teoría sólo puede declararse asueto un
161                 // día laborable.
162                 return 'laborable';
163             }
164         } else {
165             return $this->_tipo;
166         }
167     }
168
169     /**
170      * Indica si un día es laborable.
171      *
172      * @return bool   false si no es laborable (o hubo error).
173      *
174      * @access public
175      */
176     function esLaborable() {
177         return $this->getTipo() == 'laborable';
178     }
179
180     /**
181      * Indica si un día es no laborable.
182      *
183      * @return bool   false si no es no laborable (o hubo error).
184      *
185      * @access public
186      */
187     function esNoLaborable() {
188         return $this->getTipo() == 'no laborable';
189     }
190
191     /**
192      * Indica si un día es feriado.
193      *
194      * @return bool   false si no es feriado (o hubo error).
195      *
196      * @access public
197      */
198     function esFeriado() {
199         return $this->getTipo() == 'feriado';
200     }
201
202     /**
203      * Indica si un día es asueto.
204      *
205      * @param  string $fecha Fecha de a chequear (el día actual por
206      *                       defecto).
207      * @param  string $hora  Hora en la que se quiere chequear.
208      *
209      * @return bool   false si no es asueto (o hubo error).
210      *
211      * @access public
212      */
213     function esAsueto() {
214         return $this->getTipo() == 'asueto';
215     }
216
217     /**
218      * Busca feriados que se encuentren en un rango de fechas.
219      *
220      * Ejemplo:
221      * @code
222      * if ($feriado->buscarRango('2002/10/01', '2002/12/31')) {
223      *     while ($f = $feriado->siguiente())
224      *         var_dump( $f );
225      * } elseif ($feriado->error()) {
226      *     trigger_error('Errores: ' . $feriado->errores(), E_USER_ERROR);
227      * } else {
228      *     echo 'No se encontraron feriados en ese rango de fechas';
229      * }
230      * @endcode
231      *
232      * @param  string $ini   Fecha de inicio del rango en donde buscar (por
233      *                       defecto el primer día del mes en curso).
234      * @param  string $fin   Fecha de fin del rango en donde buscar (por
235      *                       defecto el último día del mes en curso).
236      * @param  array $orden  Órden de los resultados. Es un array
237      *                       asociativo con el campo por el cual ordenar
238      *                       como clave y si es descendente o ascendente
239      *                       como valor. Por defecto se toma fecha
240      *                       ascendente.
241      *
242      * @return bool  false si no se encontró nada (o hubo error).
243      *
244      * @todo Pasar a método estático y usar Date en vez de strings para las fechas.
245      */
246     function buscarRango($ini = '', $fin = '', $orden = null ) {
247
248         $ini = empty( $ini ) ? strftime( '%Y/01/01', time() ) : $ini;
249         $fin = empty( $fin ) ? strftime( '%Y/12/31', time() ) : $fin;
250         $ord = ( $ord != 'fecha' and $ord != 'descripcion' and $ord != 'tipo' ) ? 'fecha' : $ord;
251
252         // Valida ambas fechas y que una sea anterior a la otra.
253         if ( ! $this->_es_anterior( $ini, $fin ) )
254             return false;
255
256         // Si no se especifica orden lo inicializa.
257         if ( is_null( $orden ) )
258             $orden = array('fecha' => HE_DB_ASC);
259
260         // Genera un array con las clausulas del ORDER BY del query
261         $order = array();
262         foreach ( $orden as $campo => $ord )
263             $order[] = sprintf( "%s %s", $campo, $ord );
264             
265         // Si no son arrays sale con error.
266         if ( ! is_array( $campos ) or ! is_array( $orden ) ) {
267             $this->raiseError( 'Parámetro incorrecto, no es un array', HE_ERROR );
268             return false;
269         }
270
271         // Prepara el query con el rango de fechas
272         $query = sprintf(
273             'SELECT *
274                 FROM
275                     %s.%s
276                 WHERE
277                     %s <= fecha AND
278                     fecha <= %s
279                 %s',
280             $this->_basededatos,
281             $this->_tabla,
282             $this->_db->quote( $ini ),
283             $this->_db->quote( $fin ),
284             $order ? ( ' ORDER BY ' . join( ',', $order ) ) : ''
285         );
286
287         $resultado =& $this->_db->query( $query );
288         if ( DB::isError( $resultado ) ) {   // Hubo un error
289             $this->_error->agregar( $resultado );
290             return false;
291         } elseif ( $resultado->numRows() ) { // Tiene algún resultado
292             $this->_resultado =& $resultado;
293             return true;
294         } else {
295             return false;
296         }
297
298     }
299
300     /**
301      * Busca dias habiles en un rango de fechas y los devuelve en un array.
302      *
303      * Ejemplo:
304      * @code
305      * $diasHabiles = $feriado->buscarDiasHabiles('2002/10/01', '2002/12/31');
306      * if (count($diasHabiles)) {
307      *     echo 'Cantidad de dias habiles en le rango: '. count($diasHabiles);
308      *     foreach ($diasHabiles as $diaHabil) {
309      *         print '<PRE>';var_dump($diaHabil);print '</PRE>';
310      *     }
311      * }
312      * @endcode
313      *
314      * @param  DB    $db    Conexión a la base de datos.
315      * @param  mixed $ini   Fecha de inicio del rango en donde buscar (por
316      *                      defecto el primer día del mes en curso). Puede ser
317      *                      un objeto Date.
318      * @param  mixed $fin   Fecha de fin del rango en donde buscar (por
319      *                      defecto el día del mes en curso). Puede ser un 
320      *                      objeto Date.
321      *
322      * @return mixed
323      * @static
324      */
325     function buscarDiasHabiles($db, $ini = '', $fin = '') {
326         //Acomodo las fechas pasadas por parametro
327         $ini = empty( $ini ) ? strftime( '%Y-%m-01', time() ) : $ini;
328         $fin = empty( $fin ) ? strftime( '%Y-%m-%d', time() ) : $fin;
329         $ini = (is_string($ini)) ? new Date($ini) : $ini;
330         $fin = (is_string($fin)) ? new Date($fin) : $fin;
331         
332         //Valido que $ini < $fin
333         if ($ini->after($fin)) {
334             return new PEAR_Error ('La fecha de fin debe ser anterior a la '.
335                     'fecha de inicio.');
336         }
337         
338         //Obtener los dias feriados entre $ini y $fin
339         $sql = "SELECT fecha FROM novedades.feriados WHERE YEAR(fecha) = ". 
340             $db->quote($ini->format("%Y")) . " OR YEAR(fecha) = " . 
341             $db->quote($ini->format("%Y"));
342
343         $feriados = $db->getCol($sql);
344         if (DB::IsError($feriados)) {
345             return $feriados;
346         }
347         
348         //Verifico fecha por fecha si es o no un dia habil
349         $ini =& $ini->getPrevDay();
350         while (!$ini->equals($fin)) {
351             $ini =& $ini->getNextDay();
352             //Verifico que la fecha no sea feriado ni sabado o domingo.
353             if (!in_array($ini->format("%Y-%m-%d"), $feriados) &&
354                     ($ini->getDayOfWeek() != 0) && 
355                     ($ini->getDayOfWeek() != 6)) {
356                 $res[] = $ini;
357             }
358         }
359         return $res;
360     }
361 }
362
363 // $Id$
364 ?>