diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 2c6b41b7796..ff4c3cc6a6b 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -204,7 +204,7 @@ $tabsql[28]= "SELECT h.rowid as rowid, h.code, h.label, h.affect, h.delay, h.new $tabsql[29]= "SELECT rowid as rowid, code, label, percent, position, active FROM ".MAIN_DB_PREFIX."c_lead_status"; $tabsql[30]= "SELECT rowid, code, name, paper_size, orientation, metric, leftmargin, topmargin, nx, ny, spacex, spacey, width, height, font_size, custom_x, custom_y, active FROM ".MAIN_DB_PREFIX."c_format_cards"; //$tabsql[31]= "SELECT s.rowid as rowid, pcg_version, s.label, s.active FROM ".MAIN_DB_PREFIX."accounting_system as s"; -$tabsql[32]= "SELECT a.id as rowid, a.entity, a.code, a.fk_country as country_id, c.code as country_code, c.label as country, a.day, a.month, a.year, a.active FROM ".MAIN_DB_PREFIX."c_hrm_public_holiday as a LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON a.fk_country=c.rowid AND c.active=1"; +$tabsql[32]= "SELECT a.id as rowid, a.entity, a.code, a.fk_country as country_id, c.code as country_code, c.label as country, a.dayrule, a.day, a.month, a.year, a.active FROM ".MAIN_DB_PREFIX."c_hrm_public_holiday as a LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON a.fk_country=c.rowid AND c.active=1"; $tabsql[33]= "SELECT rowid, pos, code, label, active FROM ".MAIN_DB_PREFIX."c_hrm_department"; $tabsql[34]= "SELECT rowid, pos, code, label, c_level, active FROM ".MAIN_DB_PREFIX."c_hrm_function"; $tabsql[35]= "SELECT c.rowid, c.label, c.active, c.entity FROM ".MAIN_DB_PREFIX."c_exp_tax_cat c"; @@ -244,7 +244,7 @@ $tabsqlsort[28]="country ASC, code ASC"; $tabsqlsort[29]="position ASC"; $tabsqlsort[30]="code ASC"; //$tabsqlsort[31]="pcg_version ASC"; -$tabsqlsort[32]="year ASC, month ASC, day ASC"; +$tabsqlsort[32]="country, year ASC, month ASC, day ASC"; $tabsqlsort[33]="code ASC"; $tabsqlsort[34]="code ASC"; $tabsqlsort[35]="c.label ASC"; @@ -284,7 +284,7 @@ $tabfield[28]= "code,label,affect,delay,newbymonth,country_id,country"; $tabfield[29]= "code,label,percent,position"; $tabfield[30]= "code,name,paper_size,orientation,metric,leftmargin,topmargin,nx,ny,spacex,spacey,width,height,font_size,custom_x,custom_y"; //$tabfield[31]= "pcg_version,label"; -$tabfield[32]= "code,year,month,day,country_id,country"; +$tabfield[32]= "code,dayrule,year,month,day,country_id,country"; $tabfield[33]= "code,label"; $tabfield[34]= "code,label"; $tabfield[35]= "label"; @@ -324,7 +324,7 @@ $tabfieldvalue[28]= "code,label,affect,delay,newbymonth,country"; $tabfieldvalue[29]= "code,label,percent,position"; $tabfieldvalue[30]= "code,name,paper_size,orientation,metric,leftmargin,topmargin,nx,ny,spacex,spacey,width,height,font_size,custom_x,custom_y"; //$tabfieldvalue[31]= "pcg_version,label"; -$tabfieldvalue[32]= "code,day,month,year,country"; +$tabfieldvalue[32]= "code,dayrule,day,month,year,country"; $tabfieldvalue[33]= "code,label"; $tabfieldvalue[34]= "code,label"; $tabfieldvalue[35]= "label"; @@ -365,7 +365,7 @@ $tabfieldinsert[29]= "code,label,percent,position"; $tabfieldinsert[30]= "code,name,paper_size,orientation,metric,leftmargin,topmargin,nx,ny,spacex,spacey,width,height,font_size,custom_x,custom_y"; //$tabfieldinsert[31]= "pcg_version,label"; //$tabfieldinsert[32]= "code,label,range_account,sens,category_type,formula,position,fk_country"; -$tabfieldinsert[32]= "code,day,month,year,fk_country"; +$tabfieldinsert[32]= "code,dayrule,day,month,year,fk_country"; $tabfieldinsert[33]= "code,label"; $tabfieldinsert[34]= "code,label"; $tabfieldinsert[35]= "label"; @@ -487,7 +487,7 @@ $tabhelp[28] = array('affect'=>$langs->trans("FollowedByACounter"),'delay'=>$lan $tabhelp[29] = array('code'=>$langs->trans("EnterAnyCode"), 'percent'=>$langs->trans("OpportunityPercent"), 'position'=>$langs->trans("PositionIntoComboList")); $tabhelp[30] = array('code'=>$langs->trans("EnterAnyCode"), 'name'=>$langs->trans("LabelName"), 'paper_size'=>$langs->trans("LabelPaperSize")); //$tabhelp[31] = array('pcg_version'=>$langs->trans("EnterAnyCode")); -$tabhelp[32] = array('code'=>$langs->trans("EnterAnyCode"), 'daterule'=>"Use 'date'", 'country'=>$langs->trans("EnterACountryOnlyIfSpecificToOneCountry"), 'year'=>$langs->trans("ZeroMeansEveryYear")); +$tabhelp[32] = array('code'=>$langs->trans("EnterAnyCode"), 'dayrule'=>"Keep empty for a date defined with month and day (most common case).
Use a keyword like 'easter', 'eastermonday', ... for a date predefined by complex rules.", 'country'=>$langs->trans("EnterACountryOnlyIfSpecificToOneCountry"), 'year'=>$langs->trans("ZeroMeansEveryYear")); $tabhelp[33] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[34] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[35] = array(); diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index a1d01136401..25a557a47bd 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1152,9 +1152,8 @@ class Form $sql .= ", dictp.code as country_code"; } - $sql.= " FROM (".MAIN_DB_PREFIX ."societe as s"; + $sql.= " FROM ".MAIN_DB_PREFIX ."societe as s"; if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - $sql.= " )"; if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) { $sql.= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid=s.fk_pays"; } diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php index 8b30f56c0d2..9f1963dc9b9 100644 --- a/htdocs/core/lib/date.lib.php +++ b/htdocs/core/lib/date.lib.php @@ -82,7 +82,6 @@ function getServerTimeZoneString() */ function getServerTimeZoneInt($refgmtdate = 'now') { - global $conf; if (method_exists('DateTimeZone', 'getOffset')) { // Method 1 (include daylight) @@ -329,6 +328,7 @@ function dolSqlDateFilter($datefield, $day_date, $month_date, $year_date) */ function dol_stringtotime($string, $gm = 1) { + $reg=array(); // Convert date with format DD/MM/YYY HH:MM:SS. This part of code should not be used. if (preg_match('/^([0-9]+)\/([0-9]+)\/([0-9]+)\s?([0-9]+)?:?([0-9]+)?:?([0-9]+)?/i', $string, $reg)) { @@ -595,39 +595,47 @@ function dol_get_first_day_week($day, $month, $year, $gm = false) } /** - * Fonction retournant le nombre de jour feries, samedis et dimanches entre 2 dates entrees en timestamp. Dates must be UTC with hour, day, min to 0 + * Return the number of non working days including saturday and sunday (or not) between 2 dates in timestamp. + * Dates must be UTC with hour, day, min to 0. * Called by function num_open_day * * @param int $timestampStart Timestamp de debut * @param int $timestampEnd Timestamp de fin - * @param string $countrycode Country code + * @param string $country_code Country code * @param int $lastday Last day is included, 0: no, 1:yes - * @return int Nombre de jours feries + * @param int $includesaturday Include saturday as non working day (-1=use setup, 0=no, 1=yes) + * @param int $includesunday Include sunday as non working day (-1=use setup, 0=no, 1=yes) + * @return int|string Number of non working days or error message string if error * @see num_between_day(), num_open_day() */ -function num_public_holiday($timestampStart, $timestampEnd, $countrycode = 'FR', $lastday = 0) +function num_public_holiday($timestampStart, $timestampEnd, $country_code = '', $lastday = 0, $includesaturday = -1, $includesunday = -1) { - global $conf; + global $db, $conf, $mysoc; $nbFerie = 0; + $specialdayrule = array(); // Check to ensure we use correct parameters if ((($timestampEnd - $timestampStart) % 86400) != 0) return 'ErrorDates must use same hours and must be GMT dates'; + if (empty($country_code)) $country_code = $mysoc->country_code; + + if ($includesaturday < 0) $includesaturday = (isset($conf->global->MAIN_NON_WORKING_DAYS_INCLUDE_SATURDAY) ? $conf->global->MAIN_NON_WORKING_DAYS_INCLUDE_SATURDAY : 1); + if ($includesunday < 0) $includesunday = (isset($conf->global->MAIN_NON_WORKING_DAYS_INCLUDE_SUNDAY) ? $conf->global->MAIN_NON_WORKING_DAYS_INCLUDE_SUNDAY : 1); + + $i=0; while (( ($lastday == 0 && $timestampStart < $timestampEnd) || ($lastday && $timestampStart <= $timestampEnd) ) && ($i < 50000)) // Loop end when equals (Test on i is a security loop to avoid infinite loop) { $ferie=false; - $countryfound=0; - $includesaturdayandsunday=1; $jour = date("d", $timestampStart); $mois = date("m", $timestampStart); $annee = date("Y", $timestampStart); - // Check into var $conf->global->HOLIDAY_MORE_DAYS MM-DD,YYYY-MM-DD, ... + // Do not use this anymore, use instead the dictionary of public holidays. if (! empty($conf->global->HOLIDAY_MORE_PUBLIC_HOLIDAYS)) { $arrayofdaystring=explode(',', $conf->global->HOLIDAY_MORE_PUBLIC_HOLIDAYS); @@ -645,29 +653,61 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode = 'FR', } } - if ($countrycode == 'FR') + $country_id = dol_getIdFromCode($db, $country_code, 'c_country', 'code', 'rowid'); + + // Loop on public holiday defined into hrm_public_holiday + $sql = "SELECT code, entity, fk_country, dayrule, year, month, day, active"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_hrm_public_holiday"; + $sql.= " WHERE active = 1 and fk_country IN (0".($country_id > 0 ? ", ".$country_id : 0).")"; + + $resql = $db->query($sql); + if ($resql) { - $countryfound=1; + $num_rows = $db->num_rows($resql); + $i=0; + while ($i < $num_rows) + { + $obj = $db->fetch_object($resql); - // Definition of fixed working days - if($jour == 1 && $mois == 1) $ferie=true; // 1er january - if($jour == 1 && $mois == 5) $ferie=true; // 1er may - if($jour == 8 && $mois == 5) $ferie=true; // 5 may - if($jour == 14 && $mois == 7) $ferie=true; // 14 july - if($jour == 15 && $mois == 8) $ferie=true; // 15 august - if($jour == 1 && $mois == 11) $ferie=true; // 1 november - if($jour == 11 && $mois == 11) $ferie=true; // 11 november - if($jour == 25 && $mois == 12) $ferie=true; // 25 december + if (! empty($obj->dayrule) && $obj->dayrule != 'date') // For example 'easter', '...' + { + $specialdayrule[$obj->dayrule] = $obj->dayrule; + } + else + { + $match = 1; + if (! empty($obj->year) && $obj->year != $annee) $match = 0; + if ($obj->month != $mois) $match = 0; + if ($obj->day != $jour) $match = 0; + if ($match) $ferie = true; + } + + $i++; + } + } + else + { + dol_syslog($db->lasterror(), LOG_ERR); + return 'Error sql '.$db->lasterror(); + } + + // Special dayrules + if (in_array('easter', $specialdayrule)) + { // Calculation for easter date $date_paques = easter_date($annee); $jour_paques = date("d", $date_paques); $mois_paques = date("m", $date_paques); if($jour_paques == $jour && $mois_paques == $mois) $ferie=true; - // Pâques + // Easter (sunday) + } + if (in_array('eastermonday', $specialdayrule)) + { // Calculation for the monday of easter date - $date_lundi_paques = mktime( + $date_paques = easter_date($annee); + $date_lundi_paques = mktime( date("H", $date_paques), date("i", $date_paques), date("s", $date_paques), @@ -677,11 +717,15 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode = 'FR', ); $jour_lundi_ascension = date("d", $date_lundi_paques); $mois_lundi_ascension = date("m", $date_lundi_paques); - if($jour_lundi_ascension == $jour && $mois_lundi_ascension == $mois) $ferie=true; - // Lundi de Pâques + if ($jour_lundi_ascension == $jour && $mois_lundi_ascension == $mois) $ferie=true; + // Easter (monday) + } - // Calcul du jour de l'ascension (38 days after easter day) - $date_ascension = mktime( + if (in_array('ascension', $specialdayrule)) + { + // Calcul du jour de l'ascension (39 days after easter day) + $date_paques = easter_date($annee); + $date_ascension = mktime( date("H", $date_paques), date("i", $date_paques), date("s", $date_paques), @@ -692,10 +736,14 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode = 'FR', $jour_ascension = date("d", $date_ascension); $mois_ascension = date("m", $date_ascension); if($jour_ascension == $jour && $mois_ascension == $mois) $ferie=true; - // Ascension + // Ascension (thursday) + } - // Calculation of "Pentecote" (11 days after easter day) - $date_pentecote = mktime( + if (in_array('pentecote', $specialdayrule)) + { + // Calculation of "Pentecote" (49 days after easter day) + $date_paques = easter_date($annee); + $date_pentecote = mktime( date("H", $date_paques), date("i", $date_paques), date("s", $date_paques), @@ -706,71 +754,31 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode = 'FR', $jour_pentecote = date("d", $date_pentecote); $mois_pentecote = date("m", $date_pentecote); if($jour_pentecote == $jour && $mois_pentecote == $mois) $ferie=true; - // "Pentecote" + // "Pentecote" (sunday) } - - // Pentecoste and Ascensione in Italy go to the sunday after: isn't holiday. - // Pentecoste is 50 days after Easter, Ascensione 40 - if ($countrycode == 'IT') + if (in_array('pentecotemonday', $specialdayrule)) { - $countryfound=1; - - // Definition des dates feriees fixes - if($jour == 1 && $mois == 1) $ferie=true; // Capodanno - if($jour == 6 && $mois == 1) $ferie=true; // Epifania - if($jour == 25 && $mois == 4) $ferie=true; // Anniversario Liberazione - if($jour == 1 && $mois == 5) $ferie=true; // Festa del Lavoro - if($jour == 2 && $mois == 6) $ferie=true; // Festa della Repubblica - if($jour == 15 && $mois == 8) $ferie=true; // Ferragosto - if($jour == 1 && $mois == 11) $ferie=true; // Tutti i Santi - if($jour == 8 && $mois == 12) $ferie=true; // Immacolata Concezione - if($jour == 25 && $mois == 12) $ferie=true; // 25 decembre - if($jour == 26 && $mois == 12) $ferie=true; // Santo Stefano - - // Calcul du jour de paques + // Calculation of "Pentecote" (49 days after easter day) $date_paques = easter_date($annee); - $jour_paques = date("d", $date_paques); - $mois_paques = date("m", $date_paques); - if($jour_paques == $jour && $mois_paques == $mois) $ferie=true; - // Paques + $date_pentecote = mktime( + date("H", $date_paques), + date("i", $date_paques), + date("s", $date_paques), + date("m", $date_paques), + date("d", $date_paques) + 50, + date("Y", $date_paques) + ); + $jour_pentecote = date("d", $date_pentecote); + $mois_pentecote = date("m", $date_pentecote); + if($jour_pentecote == $jour && $mois_pentecote == $mois) $ferie=true; + // "Pentecote" (monday) } - if ($countrycode == 'IN') + if (in_array('viernessanto', $specialdayrule)) { - $countryfound=1; - - if($jour == 1 && $mois == 1) $ferie=true; // New Year's Day - if($jour == 26 && $mois == 1) $ferie=true; // Republic Day - if($jour == 1 && $mois == 5) $ferie=true; // May Day - if($jour == 15 && $mois == 8) $ferie=true; // Independence Day - if($jour == 2 && $mois == 10) $ferie=true; // Gandhi Jayanti - if($jour == 25 && $mois == 12) $ferie=true; // Christmas - } - - if ($countrycode == 'ES') - { - $countryfound=1; - - // Definition des dates feriees fixes - if($jour == 1 && $mois == 1) $ferie=true; // Año nuevo - if($jour == 6 && $mois == 1) $ferie=true; // Día Reyes - if($jour == 1 && $mois == 5) $ferie=true; // 1 Mayo - if($jour == 15 && $mois == 8) $ferie=true; // 15 Agosto - if($jour == 12 && $mois == 10) $ferie=true; // Día Hispanidad - if($jour == 1 && $mois == 11) $ferie=true; // 1 noviembre - if($jour == 6 && $mois == 12) $ferie=true; // Constitución - if($jour == 8 && $mois == 12) $ferie=true; // Inmaculada - if($jour == 25 && $mois == 12) $ferie=true; // 25 diciembre - - // Calcul día de Pascua - $date_paques = easter_date($annee); - $jour_paques = date("d", $date_paques); - $mois_paques = date("m", $date_paques); - if($jour_paques == $jour && $mois_paques == $mois) $ferie=true; - // Paques - // Viernes Santo - $date_viernes = mktime( + $date_paques = easter_date($annee); + $date_viernes = mktime( date("H", $date_paques), date("i", $date_paques), date("s", $date_paques), @@ -784,74 +792,10 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode = 'FR', //Viernes Santo } - if ($countrycode == 'AT') + if (in_array('fronleichnam', $specialdayrule)) { - $countryfound=1; - - // Definition des dates feriees fixes - if($jour == 1 && $mois == 1) $ferie=true; // Neujahr - if($jour == 6 && $mois == 1) $ferie=true; // Hl. 3 Koenige - if($jour == 1 && $mois == 5) $ferie=true; // 1. Mai - if($jour == 15 && $mois == 8) $ferie=true; // Mariae Himmelfahrt - if($jour == 26 && $mois == 10) $ferie=true; // 26. Oktober - if($jour == 1 && $mois == 11) $ferie=true; // Allerheiligen - if($jour == 8 && $mois == 12) $ferie=true; // Mariae Empfaengnis - if($jour == 24 && $mois == 12) $ferie=true; // Heilig abend - if($jour == 25 && $mois == 12) $ferie=true; // Christtag - if($jour == 26 && $mois == 12) $ferie=true; // Stefanietag - if($jour == 31 && $mois == 12) $ferie=true; // Silvester - - // Easter calculation - $date_paques = easter_date($annee); - $jour_paques = date("d", $date_paques); - $mois_paques = date("m", $date_paques); - if($jour_paques == $jour && $mois_paques == $mois) $ferie=true; - // Easter sunday - - // Monday after easter - $date_eastermonday = mktime( - date("H", $date_paques), - date("i", $date_paques), - date("s", $date_paques), - date("m", $date_paques), - date("d", $date_paques) + 1, - date("Y", $date_paques) - ); - $jour_eastermonday = date("d", $date_eastermonday); - $mois_eastermonday = date("m", $date_eastermonday); - if($jour_eastermonday == $jour && $mois_eastermonday == $mois) $ferie=true; - // Easter monday - - // Christi Himmelfahrt (39 days after easter sunday) - $date_ch = mktime( - date("H", $date_paques), - date("i", $date_paques), - date("s", $date_paques), - date("m", $date_paques), - date("d", $date_paques) + 39, - date("Y", $date_paques) - ); - $jour_ch = date("d", $date_ch); - $mois_ch = date("m", $date_ch); - if($jour_ch == $jour && $mois_ch == $mois) $ferie=true; - // Christi Himmelfahrt - - // Pfingsten (50 days after easter sunday) - $date_pentecote = mktime( - date("H", $date_paques), - date("i", $date_paques), - date("s", $date_paques), - date("m", $date_paques), - date("d", $date_paques) + 50, - date("Y", $date_paques) - ); - $jour_pentecote = date("d", $date_pentecote); - $mois_pentecote = date("m", $date_pentecote); - if($jour_pentecote == $jour && $mois_pentecote == $mois) $ferie=true; - // Pfingsten - // Fronleichnam (60 days after easter sunday) - $date_fronleichnam = mktime( + $date_fronleichnam = mktime( date("H", $date_paques), date("i", $date_paques), date("s", $date_paques), @@ -866,15 +810,21 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode = 'FR', } // If we have to include saturday and sunday - if ($includesaturdayandsunday) + if ($includesaturday || $includesunday) { $jour_julien = unixtojd($timestampStart); $jour_semaine = jddayofweek($jour_julien, 0); - if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true; - //Saturday (6) and Sunday (0) + if ($includesaturday) //Saturday (6) and Sunday (0) + { + if ($jour_semaine == 6) $ferie=true; + } + if ($includesunday) //Saturday (6) and Sunday (0) + { + if($jour_semaine == 0) $ferie=true; + } } - // On incremente compteur + // We increase the counter of non working day if ($ferie) $nbFerie++; // Increase number of days (on go up into loop) diff --git a/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql b/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql index 312c30210c8..70750494a10 100644 --- a/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql +++ b/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql @@ -31,14 +31,52 @@ -- A lot of countries -INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('NEWYEARDAY1', 0, 0, 0, 1, 1, 1); -INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('LABORDAY1', 0, 0, 0, 5, 1, 1); -INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('CHRISTMASDAY1', 0, 0, 0, 12, 25, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('NEWYEARDAY1', 0, 0, 0, 1, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('LABORDAY1', 0, 0, 0, 5, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('ASSOMPTIONDAY1', 0, 0, 0, 8, 15, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('CHRISTMASDAY1', 0, 0, 0, 12, 25, 1); + +-- France only (1) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-VICTORYDAY', 0, 1, '', 0, 5, 8, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-NATIONALDAY', 0, 1, '', 0, 7, 14, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-ASSOMPTION', 0, 1, '', 0, 8, 15, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-TOUSSAINT', 0, 1, '', 0, 11, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-ARMISTICE', 0, 1, '', 0, 11, 11, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-EASTER', 0, 1, 'eastermonday', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-ASCENSION', 0, 1, 'ascension', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-PENTECOST', 0, 1, 'pentecost', 0, 0, 0, 1); + +-- Italy (3) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-LIBEAZIONE', 0, 3, 0, 4, 25, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-EPIPHANY', 0, 3, 0, 6, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-REPUBBLICA', 0, 3, 0, 6, 2, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-TUTTISANTIT', 0, 3, 0, 11, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-IMMACULE', 0, 3, 0, 12, 8, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-SAINTSTEFAN', 0, 3, 0, 12, 26, 1); + +-- Spain (4) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-EASTER', 0, 4, 'easter', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-REYE', 0, 4, '', 0, 6, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-HISPANIDAD', 0, 4, '', 0, 10, 12, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-TOUSSAINT', 0, 4, '', 0, 11, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-CONSTITUIZION', 0, 4, '', 0, 12, 6, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-IMMACULE', 0, 4, '', 0, 12, 8, 1); + +-- Austria (41) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-EASTER', 0, 41, 'eastermonday', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-ASCENSION', 0, 41, 'ascension', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-PENTECOST', 0, 41, 'pentecost', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-FRONLEICHNAM', 0, 41, 'fronleichnam', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-KONEGIE', 0, 41, '', 0, 6, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-26OKT', 0, 41, '', 0, 10, 26, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-TOUSSAINT', 0, 41, '', 0, 11, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-IMMACULE', 0, 41, '', 0, 12 8, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-24DEC', 0, 41, '', 0, 12, 24, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-SAINTSTEFAN', 0, 41, '', 0, 12, 26, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-Silvester', 0, 41, '', 0, 12, 31, 1); + +-- India (117) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('IN-REPUBLICDAY', 0, 117, '', 0, 1, 26, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('IN-GANDI', 0, 117, '', 0, 10, 2, 1); + --- France only -INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('FRVICTORYDAY', 0, 1, 0, 5, 8, 1); -INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('FRNATIONALDAY', 0, 1, 0, 7, 14, 1); -INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('FRASSOMPTION', 0, 1, 0, 8, 15, 1); -INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('FRTOUSSAINT', 0, 1, 0, 11, 1, 1); -INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('FRARMISTICE', 0, 1, 0, 11, 11, 1); ---INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('EASTER', 0, 1, 'easter', 0, 0, 0, 1); diff --git a/htdocs/install/mysql/migration/10.0.0-11.0.0.sql b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql index 4bf4cef6bba..ec124c8a1a1 100644 --- a/htdocs/install/mysql/migration/10.0.0-11.0.0.sql +++ b/htdocs/install/mysql/migration/10.0.0-11.0.0.sql @@ -114,7 +114,7 @@ create table llx_c_hrm_public_holiday entity integer DEFAULT 0 NOT NULL, -- multi company id, 0 = all fk_country integer, code varchar(62), - dayrule varchar(255) DEFAULT 'date', -- 'date', 'xxx', ... + dayrule varchar(64) DEFAULT '', -- 'easter', 'eastermonday', ... day integer, month integer, year integer, -- 0 for all years @@ -122,6 +122,57 @@ create table llx_c_hrm_public_holiday import_key varchar(14) )ENGINE=innodb; -ALTER TABLE llx_supplier_proposaldet ADD COLUMN date_start datetime DEFAULT NULL; -ALTER TABLE llx_supplier_proposaldet ADD COLUMN date_end datetime DEFAULT NULL; +ALTER TABLE llx_c_hrm_public_holiday ADD UNIQUE INDEX uk_c_hrm_public_holiday(entity, code); +ALTER TABLE llx_c_hrm_public_holiday ADD UNIQUE INDEX uk_c_hrm_public_holiday2(entity, fk_country, dayrule, day, month, year); + + +-- A lot of countries +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('NEWYEARDAY1', 0, 0, 0, 1, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('LABORDAY1', 0, 0, 0, 5, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('ASSOMPTIONDAY1', 0, 0, 0, 8, 15, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('CHRISTMASDAY1', 0, 0, 0, 12, 25, 1); + +-- France only (1) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-VICTORYDAY', 0, 1, '', 0, 5, 8, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-NATIONALDAY', 0, 1, '', 0, 7, 14, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-ASSOMPTION', 0, 1, '', 0, 8, 15, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-TOUSSAINT', 0, 1, '', 0, 11, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-ARMISTICE', 0, 1, '', 0, 11, 11, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-EASTER', 0, 1, 'eastermonday', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-ASCENSION', 0, 1, 'ascension', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('FR-PENTECOST', 0, 1, 'pentecost', 0, 0, 0, 1); + +-- Italy (3) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-LIBEAZIONE', 0, 3, 0, 4, 25, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-EPIPHANY', 0, 3, 0, 6, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-REPUBBLICA', 0, 3, 0, 6, 2, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-TUTTISANTIT', 0, 3, 0, 11, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-IMMACULE', 0, 3, 0, 12, 8, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, year, month, day, active) VALUES('IT-SAINTSTEFAN', 0, 3, 0, 12, 26, 1); + +-- Spain (4) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-EASTER', 0, 4, 'easter', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-REYE', 0, 4, '', 0, 6, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-HISPANIDAD', 0, 4, '', 0, 10, 12, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-TOUSSAINT', 0, 4, '', 0, 11, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-CONSTITUIZION', 0, 4, '', 0, 12, 6, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('ES-IMMACULE', 0, 4, '', 0, 12, 8, 1); + +-- Austria (41) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-EASTER', 0, 41, 'eastermonday', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-ASCENSION', 0, 41, 'ascension', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-PENTECOST', 0, 41, 'pentecost', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-FRONLEICHNAM', 0, 41, 'fronleichnam', 0, 0, 0, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-KONEGIE', 0, 41, '', 0, 6, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-26OKT', 0, 41, '', 0, 10, 26, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-TOUSSAINT', 0, 41, '', 0, 11, 1, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-IMMACULE', 0, 41, '', 0, 12, 8, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-24DEC', 0, 41, '', 0, 12, 24, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-SAINTSTEFAN', 0, 41, '', 0, 12, 26, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-Silvester', 0, 41, '', 0, 12, 31, 1); + +-- India (117) +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('IN-REPUBLICDAY', 0, 117, '', 0, 1, 26, 1); +INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('IN-GANDI', 0, 117, '', 0, 10, 2, 1); + diff --git a/htdocs/install/mysql/tables/llx_c_hrm_public_holiday.key.sql b/htdocs/install/mysql/tables/llx_c_hrm_public_holiday.key.sql index 23dcbf355b4..453eda6b4c3 100644 --- a/htdocs/install/mysql/tables/llx_c_hrm_public_holiday.key.sql +++ b/htdocs/install/mysql/tables/llx_c_hrm_public_holiday.key.sql @@ -17,5 +17,5 @@ -- ======================================================================== ALTER TABLE llx_c_hrm_public_holiday ADD UNIQUE INDEX uk_c_hrm_public_holiday(entity, code); -ALTER TABLE llx_c_hrm_public_holiday ADD UNIQUE INDEX uk_c_hrm_public_holiday2(entity, day, month, year); +ALTER TABLE llx_c_hrm_public_holiday ADD UNIQUE INDEX uk_c_hrm_public_holiday2(entity, fk_country, dayrule, day, month, year); diff --git a/htdocs/install/mysql/tables/llx_c_hrm_public_holiday.sql b/htdocs/install/mysql/tables/llx_c_hrm_public_holiday.sql index 7efbe314875..e26d6ee4772 100644 --- a/htdocs/install/mysql/tables/llx_c_hrm_public_holiday.sql +++ b/htdocs/install/mysql/tables/llx_c_hrm_public_holiday.sql @@ -22,7 +22,7 @@ create table llx_c_hrm_public_holiday entity integer DEFAULT 0 NOT NULL, -- multi company id, 0 = all fk_country integer, code varchar(62), - dayrule varchar(255) DEFAULT 'date', -- 'date', 'xxx', ... + dayrule varchar(64) DEFAULT '', -- 'easter', 'eastermonday', ... day integer, month integer, year integer, -- 0 for all years diff --git a/test/phpunit/DateLibTest.php b/test/phpunit/DateLibTest.php index cc4f50705e0..29b34297a38 100644 --- a/test/phpunit/DateLibTest.php +++ b/test/phpunit/DateLibTest.php @@ -185,16 +185,33 @@ class DateLibTest extends PHPUnit\Framework\TestCase // With same hours - Tuesday/Wednesday jan 2013 $date1=dol_mktime(0, 0, 0, 1, 1, 2013); $date2=dol_mktime(0, 0, 0, 1, 2, 2013); + $date3=dol_mktime(0, 0, 0, 1, 3, 2013); $result=num_public_holiday($date1, $date2, 'FR', 1); print __METHOD__." result=".$result."\n"; - $this->assertEquals(1, $result, 'NumPublicHoliday for Tuesday/Wednesday jan 2013 for FR'); // 1 closed days + $this->assertEquals(1, $result, 'NumPublicHoliday for Tuesday 1 - Wednesday 2 jan 2013 for FR'); // 1 closed days (country france) $result=num_public_holiday($date1, $date2, 'XX', 1); print __METHOD__." result=".$result."\n"; - $this->assertEquals(0, $result, 'NumPublicHoliday for Tuesday/Wednesday jan 2013 for XX'); // no closed days (country unknown) + $this->assertEquals(1, $result, 'NumPublicHoliday for Tuesday 1 - Wednesday 2 jan 2013 for XX'); // 1 closed days (country unknown) - // With same hours - Friday/Sunday jan 2013 + $result=num_public_holiday($date2, $date3, 'FR', 1); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(0, $result, 'NumPublicHoliday for Wednesday 2 - Thursday 3 jan 2013 for FR'); // no closed days + + // Check with easter monday + $date1=dol_mktime(0, 0, 0, 4, 21, 2019); + $date2=dol_mktime(0, 0, 0, 4, 23, 2019); + + $result=num_public_holiday($date1, $date2, 'XX', 1); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(1, $result, 'NumPublicHoliday including eastermonday for XX'); // 2 opened day, 1 closed days (sunday) + + $result=num_public_holiday($date1, $date2, 'FR', 1); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(2, $result, 'NumPublicHoliday including eastermonday for FR'); // 1 opened day, 2 closed days (sunday + easter monday) + + // Check for sunday/saturday - Friday 4 - Sunday 6 jan 2013 $date1=dol_mktime(0, 0, 0, 1, 4, 2013); $date2=dol_mktime(0, 0, 0, 1, 6, 2013); @@ -202,10 +219,25 @@ class DateLibTest extends PHPUnit\Framework\TestCase print __METHOD__." result=".$result."\n"; $this->assertEquals(2, $result, 'NumPublicHoliday for FR'); // 1 opened day, 2 closed days + $result=num_public_holiday($date1, $date2, 'FR', 1, 1, 1); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(2, $result, 'NumPublicHoliday for FR'); // 1 opened day, 2 closed days + + $result=num_public_holiday($date1, $date2, 'FR', 1, 1, 0); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(1, $result, 'NumPublicHoliday for FR'); // 2 opened day, 1 closed days + + $result=num_public_holiday($date1, $date2, 'FR', 1, 0, 0); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(0, $result, 'NumPublicHoliday for FR'); // 3 opened day, 0 closed days + $result=num_public_holiday($date1, $date2, 'XX', 1); print __METHOD__." result=".$result."\n"; $this->assertEquals(2, $result, 'NumPublicHoliday for XX'); // 1 opened day, 2 closed days (even if country unknown) + + + // Add more holiday with constant HOLIDAY_MORE_PUBLIC_HOLIDAYS $conf->global->HOLIDAY_MORE_PUBLIC_HOLIDAYS='12-13,2019-12-14'; $date1=dol_mktime(0, 0, 0, 12, 13, 2018); @@ -243,14 +275,19 @@ class DateLibTest extends PHPUnit\Framework\TestCase // With same hours - Tuesday/Wednesday jan 2013 $date1=dol_mktime(0, 0, 0, 1, 1, 2013); $date2=dol_mktime(0, 0, 0, 1, 2, 2013); + $date3=dol_mktime(0, 0, 0, 1, 3, 2013); $result=num_open_day($date1, $date2, 0, 1, 0, 'FR'); print __METHOD__." result=".$result."\n"; - $this->assertEquals(1, $result, 'NumOpenDay Tuesday/Wednesday jan 2013 for FR'); // 1 opened days + $this->assertEquals(1, $result, 'NumOpenDay Tuesday 1 - Wednesday 2 jan 2013 for FR'); // 1 opened days (country france) $result=num_open_day($date1, $date2, 0, 1, 0, 'XX'); print __METHOD__." result=".$result."\n"; - $this->assertEquals(2, $result, 'NumOpenDay Tuesday/Wednesday jan 2013 for XX'); // 2 opened days (country unknown) + $this->assertEquals(1, $result, 'NumOpenDay Tuesday 1 - Wednesday 2 jan 2013 for XX'); // 1 opened days (country unknown) + + $result=num_open_day($date2, $date3, 0, 1, 0, 'FR'); + print __METHOD__." result=".$result."\n"; + $this->assertEquals(2, $result, 'NumOpenDay Wednesday 2 - Thursday 3 jan 2013 for FR'); // 2 opened days // With same hours - Friday/Sunday jan 2013 $date1=dol_mktime(0, 0, 0, 1, 4, 2013);