From 8393fb0a3ad801e00580fb17949f706720fa5d27 Mon Sep 17 00:00:00 2001 From: Ryan Higgins Date: Sun, 3 Aug 2008 20:37:51 -0500 Subject: [PATCH] Serials planning: Update subscription edit to properly deal with date changes. ( patch 3 / 3 ) Previously subscription-add.pl allowed modification of 'firstacquidate', which changed the subscription definition, but did not affect prediction. This patch adds two fuctions to Serials.pm to get/set the current expected issue date (note that all date calculations in prediction patterns are based on the current expected date, and there's only one serial issue per subscription in the 'expected' status at any time). Subscription editing now allows you to edit the next expected date, but not the first acqui date (unless you haven't received any issues yet), thus allowing for adjustments in the prediction pattern. This patch also updates fixes some discrepancies in irregularities / prediction display. Signed-off-by: Joshua Ferraro --- C4/Serials.pm | 71 ++++++- .../en/modules/serials/subscription-add.tmpl | 192 ++++++++++-------- serials/subscription-add.pl | 60 +++--- 3 files changed, 203 insertions(+), 120 deletions(-) diff --git a/C4/Serials.pm b/C4/Serials.pm index ade4103bb3..8e17b73095 100644 --- a/C4/Serials.pm +++ b/C4/Serials.pm @@ -47,7 +47,7 @@ BEGIN { &GetLatestSerials &ModSerialStatus &GetNextDate &GetSerials2 &ReNewSubscription &GetLateIssues &GetLateOrMissingIssues &GetSerialInformation &AddItem2Serial - &PrepareSerialsData + &PrepareSerialsData &GetNextExpected &ModNextExpected &UpdateClaimdateIssues &GetSuppliersWithLateIssues &getsupplierbyserialid @@ -722,6 +722,7 @@ this function get every serial not arrived for a given subscription as well as the number of issues registered in the database (all types) this number is used to see if a subscription can be deleted (=it must have only 1 issue) +FIXME: We should return \@serials. =back =cut @@ -1215,6 +1216,63 @@ sub ModSerialStatus { } } +=head2 GetNextExpected + +=over 4 + +$nextexpected = GetNextExpected($subscriptionid) + +Get the planneddate for the current expected issue of the subscription. + +returns a hashref: + +$nextexepected = { + serialid => int + planneddate => C4::Dates object + } + +=back + +=cut + +sub GetNextExpected($) { + my ($subscriptionid) = @_; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare('SELECT serialid, planneddate FROM serial WHERE subscriptionid=? AND status=?'); + # Each subscription has only one 'expected' issue, with serial.status==1. + $sth->execute( $subscriptionid, 1 ); + my ( $nextissue ) = $sth->fetchrow_hashref; + $nextissue->{planneddate} = C4::Dates->new($nextissue->{planneddate},'iso'); + return $nextissue; +} +=head2 ModNextExpected + +=over 4 + +ModNextExpected($subscriptionid,$date) + +Update the planneddate for the current expected issue of the subscription. +This will modify all future prediction results. + +C<$date> is a C4::Dates object. + +=back + +=cut + +sub ModNextExpected($$) { + my ($subscriptionid,$date) = @_; + warn $subscriptionid; + warn $date->output('iso'); + my $dbh = C4::Context->dbh; + #FIXME: Would expect to only set planneddate, but we set both on new issue creation, so updating it here + my $sth = $dbh->prepare('UPDATE serial SET planneddate=?,publisheddate=? WHERE subscriptionid=? AND status=?'); + # Each subscription has only one 'expected' issue, with serial.status==1. + $sth->execute( $date->output('iso'),$date->output('iso'), $subscriptionid, 1); + return 0; + +} + =head2 ModSubscription =over 4 @@ -2593,10 +2651,13 @@ sub GetNextDate(@) { my @resultdate; # warn "DOW $dayofweek"; - if ( $subscription->{periodicity} % 16 == 0 ) { + if ( $subscription->{periodicity} % 16 == 0 ) { # 'without regularity' || 'irregular' return 0; } - if ( $subscription->{periodicity} == 1 ) { + # daily : n / week + # Since we're interpreting irregularity here as which days of the week to skip an issue, + # renaming this pattern from 1/day to " n / week ". + if ( $subscription->{periodicity} == 1 ) { my $dayofweek = eval{Day_of_Week( $year,$month, $day )}; if ($@){warn "year month day : $year $month $day $subscription->{subscriptionid} : $@";} else { @@ -2610,11 +2671,13 @@ sub GetNextDate(@) { @resultdate = Add_Delta_Days($year,$month, $day , 1 ); } } + # 1 week if ( $subscription->{periodicity} == 2 ) { my ($wkno,$year) = eval {Week_of_Year( $year,$month, $day )}; if ($@){warn "year month day : $year $month $day $subscription->{subscriptionid} : $@";} else { for ( my $i = 0 ; $i < @irreg ; $i++ ) { + #FIXME: if two consecutive irreg, do we only skip one? if ( $irreg[$i] == (($wkno!=51)?($wkno +1) % 52 :52)) { ($year,$month,$day) = Add_Delta_Days($year,$month, $day , 7 ); $wkno=(($wkno!=51)?($wkno +1) % 52 :52); @@ -2623,6 +2686,7 @@ sub GetNextDate(@) { @resultdate = Add_Delta_Days( $year,$month, $day, 7); } } + # 1 / 2 weeks if ( $subscription->{periodicity} == 3 ) { my ($wkno,$year) = eval {Week_of_Year( $year,$month, $day )}; if ($@){warn "year month day : $year $month $day $subscription->{subscriptionid} : $@";} @@ -2637,6 +2701,7 @@ sub GetNextDate(@) { @resultdate = Add_Delta_Days($year,$month, $day , 14 ); } } + # 1 / 3 weeks if ( $subscription->{periodicity} == 4 ) { my ($wkno,$year) = eval {Week_of_Year( $year,$month, $day )}; if ($@){warn "année mois jour : $year $month $day $subscription->{subscriptionid} : $@";} diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-add.tmpl b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-add.tmpl index f9573585c6..2274624629 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-add.tmpl +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-add.tmpl @@ -9,14 +9,11 @@ // the english words used in display purposes var text = new Array(_("Number"),_("Volume"),_("Issue"),_("Month"),_("Week"),_("Starting with:"),_("Rollover at:"),_("Choose Hemisphere:"),_("Northern"),_("Southern"), _("Autumn"),_("Winter"),_("Spring"),_("Summer"),_("Fall"),_("Season"),_("Year")); +var weekno_label = _("Week # "); var is_season = 0; var is_hemisphere = 1; var irregular_issues; // will hold irregularity object. - - var weeks = new Array(); - - function formatDate(myDate) { var d = new Array( myDate.getFullYear(), myDate.getMonth() + 1 ,myDate.getDate()); if(d[1].toString().length == 1) { d[1] = '0'+d[1] }; @@ -34,13 +31,22 @@ Date.prototype.addDays = function(days) { this.setDate(this.getDate()+days); } -function getWeeksArray(startDate) { -// returns a 52 element array with dates starting with startDate. +function getWeeksArray(startDate,periodicity) { +// returns an array of syspref-formatted dates starting at the first day of startDate's year. +// This prediction method will not accurately predict irregularites beyond the first year. +// FIXME : Should replace with ajax query to get the first Monday of the year so that week numbers have correct dates. + var incr=1; + if(periodicity==3) { // 1/2 wks + incr=2; + } else if(periodicity == 4) { // 1/3 wks + incr=3; + } var weeksArray = new Array; - var myDate = new Date; + startDate.setDate(1); + startDate.setMonth(0); for(var i=0;i<52;i++) { + weeksArray[i] = formatDate(startDate) + ' ' + weekno_label + (i + 1); startDate.addDays( 7 ); - weeksArray[i] = formatDate(startDate); } return weeksArray; } @@ -71,13 +77,18 @@ function IrregularPattern() { this.months = new Array(_("January"),_("February"),_("March"),_("April"),_("May"),_("June"),_("July"),_("August"),_("September"),_("October"),_("November"),_("December")); this.seasons = new Array(_("Autumn"),_("Winter"),_("Spring"),_("Summer"),_("Fall")); this.daynames = new Array(_("Monday"),_("Tuesday"),_("Wednesday"),_("Thursday"),_("Friday"),_("Saturday"),_("Sunday")); - - this.weeks = new Array(); - - this.numskipped = 0; + // create weeks irregularity selection array: + this.firstissue = new Date(); + this.firstissue.setDate(1); + this.firstissue.setMonth(0); + // it's a mod, we already have a start date. + this.firstissue.setFullYear( ); + + this.weeks = getWeeksArray(this.firstissue); + + this.numskipped = 0; // init: var irregular = ''; - // var periodicity = document.f.periodicity.value; this.skipped = irregular.split(','); } @@ -85,7 +96,8 @@ IrregularPattern.prototype.update = function() { this.skipped= new Array; var cnt = 0; // daily periodicity, we interpret irregular array as which days of week to skip. - // else irregular array is list of issues to skip + // else if weekly periodicity, week numbers (starting from 01 Jan) to skip. + // else irregular array is list of issues to skip var summary_str = ''; this.numskipped = 0; if(document.f.irregularity_select) { @@ -100,7 +112,7 @@ IrregularPattern.prototype.update = function() { var summary = document.getElementById("irregularity_summary"); if(summary) { summary.value = summary_str; - summary.rows= ( cnt > 6 ) ? cnt : 6 ; + summary.rows= ( cnt > 6 ) ? cnt : 6 ; // textarea will bre resized, but not more than 6 lines will show. } } } @@ -119,7 +131,7 @@ function init_pattern() { } function reset_pattern() { document.getElementById("numberpattern").value = ''; -// document.getElementById("numberpattern").value = ''; + document.getElementById("irregularity").innerHTML = ''; init_pattern(); reset_num_pattern(); @@ -225,10 +237,10 @@ var patternchoice = document.getElementById("numberpattern").value; document.f.setto1.value=0; document.f.setto2.value='1'; document.f.setto3.value=''; - document.f.lastvalue1temp.value=sYear; document.f.periodicity.value='8'; document.f.numberingmethod.value=_("{Y} {X}"); moreoptions_seasons(text[15],sYear); + document.f.lastvalue1temp.value=document.f.lastvalue1.value=sYear; display_table(0); is_season = 1; break; @@ -237,8 +249,8 @@ var patternchoice = document.getElementById("numberpattern").value; document.getElementById("more_options").innerHTML = ''; document.f.irreg_check.value=1; break; - case "8": - var d = new Date(document.f.startdate.value); + case "8": // Year/Number + var d = (document.f.firstacquidate.value) ? new Date( document.f.firstacquidate.value) : new Date() ; var sYear = d.getFullYear(); document.f.add1.value=1; document.f.add2.value=1; @@ -252,29 +264,22 @@ var patternchoice = document.getElementById("numberpattern").value; document.f.setto1.value=0; document.f.setto2.value=1; document.f.setto3.value=''; - if (document.f.lastvalue1.value==0){document.f.lastvalue1.value=sYear}; - if (document.f.lastvalue2.value==0 ||document.f.lastvalue2.value=='' ){ + document.f.lastvalue1.value=sYear; switch (document.f.periodicity.value){ case 1: var doy = dayofyear(d); - //var Weeknumber=YWDA[1]; document.f.lastvalue2.value=doy; + document.f.whenmorethan2.value=365; break; case 12: var doy = dayofyear(d); - //var Weeknumber=YWDA[1]; document.f.lastvalue2.value=doy*2; - break; - case 13: - var doy = dayofyear(d); - //var Weeknumber=YWDA[1]; - document.f.lastvalue2.value=doy/3; + document.f.whenmorethan2.value=730; break; case 2: case 3: case 4: var YWDa = YMDaToYWDa(d); - //var Weeknumber=YWDA[1]; document.f.lastvalue2.value=YWDA[1]/(document.f.periodicity.value-1); break; case 5: @@ -284,23 +289,26 @@ var patternchoice = document.getElementById("numberpattern").value; case 6: var smonth = d.getMonth(); document.f.lastvalue2.value=smonth/2; + document.f.whenmorethan2.value=6; break; case 7: case 8: var smonth = d.getMonth(); document.f.lastvalue2.value=smonth/3; + document.f.whenmorethan2.value=4; break; case 9: var smonth = d.getMonth(); document.f.lastvalue2.value=smonth/6; + document.f.whenmorethan2.value=2; break; default: } - } - // document.f.lastvalue2.value=document.f.lastvalue2temp.value; document.f.lastvalue3.value=''; - document.f.numberingmethod.value=_("{X}/{Y}"); + document.f.numberingmethod.value=_("{X} / {Y}"); moreoptions(text[16],text[0]); + // document.f.lastvalue1temp.value=sYear; + // document.f.lastvalue2temp.value=document.f.lastvalue2.value; display_table(0); break; default: @@ -385,7 +393,7 @@ function set_num_pattern_from_template_vars() { } // a pre check with more options to see if 'number' and '1/day' are chosen - + // to dispaly the more options section @@ -413,7 +422,7 @@ document.getElementById("more_options").innerHTML = ''; var textbox = ''; // alert("X: "+x+"Y: "+y+"Z: "+z); if(x){ - textbox +="\n
 <\/th>"+x+"<\/th>"; + textbox +="\n
 <\/th>"+x+"<\/th>"; if(y){ textbox +=""+y+"<\/th>"; if(z){ @@ -473,6 +482,7 @@ var selbox = document.getElementById("season1"); // to display the more options section for seasons function moreoptions_seasons(x,y){ +// x = 'Season'. y = 'Year'. document.getElementById("irregularity").innerHTML = ''; document.getElementById("more_options").innerHTML = ''; var textbox = ''; @@ -488,18 +498,16 @@ var textbox = ''; textbox +=">"+text[i+7]+"<\/option>"; } textbox +="<\/li>\n"; - textbox +="
 <\/th>"+x+"<\/th>"; + textbox +="
 <\/th>"+x+"<\/th>"; textbox +=""+text[16]+"<\/th>"; textbox +="<\/tr>\n"; textbox +="
"+text[5]+"<\/th>" + irregular_issues.firstissue.getFullYear() + "<\/td><\/tr>\n"; textbox +="
"+text[6]+"<\/th>"; textbox +="<\/td>\n"; textbox +="<\/tr><\/table>\n"; @@ -542,13 +550,6 @@ function irregularity_check(){ toobig=1; } break; - case "13": - if(rollover < 156) expected =156; - if(rollover > 156) { - expectedover=156; - toobig=1; - } - break; case "2": if(rollover < 52) expected =52; if(rollover > 52){ @@ -631,7 +632,7 @@ function irregularity_check(){ error=errortext; } if(toobig){ - errortext +=expectedover+_(" issues expected, ")+rollover+_(" were entered.
You seem to have indicated more issues per year than expected."); + errortext +=expectedover+_(" issues expected, ")+rollover+_(" were entered.

You seem to have indicated more issues per year than expected.

"); error=errortext; } if(error.length ==0){ @@ -647,23 +648,23 @@ function irregular_options(periodicity){ var count; var errortext=''; if(periodicity == 1) { - expected = 366; - titles = "Day"; + expected = 7; + titles = irregular_issues.daynames; count = 1; } if(periodicity == 2 || periodicity == 3 || periodicity == 4) { - expected = 52; titles = irregular_issues.weeks; - - count = 1; // This doesn't make sense given the behavior of the script. - // we should count from the first serial date, not from this week! - // ; - count = 1; - + if(periodicity==3) { // 1/2 wks + expected = 26; + } else if(periodicity == 4) { // 1/3 wks + expected = 17; + } else { + expected = 52; + } } if(periodicity == 5 || periodicity == 6 || periodicity == 7 || periodicity == 8 || periodicity == 9) { - if(periodicity == 8) { + if(periodicity == 8 && numberpattern==8) { is_season = 1; // setting up from edit page } if(is_season){ @@ -683,7 +684,7 @@ function irregular_options(periodicity){ if( !expected) { return ''; // don't know how to deal with irregularity. } - for(var j=1;j<=expected;j++){ + for(var j=0;jexpected){ count = count-expected; @@ -694,12 +695,18 @@ function irregular_options(periodicity){ } else if(is_season && is_hemisphere == 2){ errortext +="