Bug 7688: Change subscription numbering pattern and frequencies
authorJulian Maurice <julian.maurice@biblibre.com>
Thu, 8 Mar 2012 16:12:55 +0000 (17:12 +0100)
committerJared Camins-Esakov <jcamins@cpbibliography.com>
Sat, 23 Mar 2013 02:14:28 +0000 (22:14 -0400)
Serials numbering pattern and frequencies are no more hard-coded. Now
it's possible to create, edit and delete numbering patterns (and
frequencies). This implies new sql tables (subscription_numberpatterns
and subscription_frequencies)

Numbering patterns behave almost as before, there are still the same
values to configure (addX, everyX, settoX, whenmorethanX). lastvalueX
and innerloopX remain in subscription tables.

There is a new value in numbering patterns: numberingX. For each
"column" (X, Y or Z) you can tell how to format the number. Actually
numberingX can be set to:
 - 'dayname' (name of the day) (0-6 or 1-7 depending on which day is the
   first of the week)
 - 'monthname' (name of the month) (0-11)
 - 'season' (name of the season) (0-3) (0 is Spring)

These names are localized by using POSIX::setlocale and POSIX::strftime
and setting a 'locale' value to the subscription. Locale have to be
installed on the system.
Note that season names are not localized using POSIX::strftime (it can't
do this), so names are hardcoded into the code (available languages: en,
fr). This could be fixed in the future by using a Perl localization
framework.

Frequencies can be configured using 3 parameters:
 - 'unit': one of 'day', 'week', 'month', 'year'
 - 'issuesperunit': integer >= 1, the number of received issues per
   'unit'
 - 'unitsperissue': integer >= 1, the number of 'unit' between two
   issues
One of 'issuesperunit' and 'unitsperissue' must be equal to 1.
Examples:
  unit = 'day', issuesperunit=3, unitsperissue=1 => 3 issues per day
  unit = 'week', issuesperunit=1, unitsperissue=3 => 1 issue each 3
  weeks

Prediction pattern is now computed server-side and is more consistent
with what Koha will do. The publication date is displayed alongside the
serial number.
Irregularities can now be checked one by one, in the prediction pattern
table, or if frequency is 'day-based' (unit is 'day'), there is the
possibility to check all issues for a week day at once.

When an irregularity is found, there is the possibility to keep the
serial number unchanged, or to skip it. It is configured at subscription
creation or modification.
For instance, with a daily subscription you can have:
  skip serial number  |  keep serial number
----------------------+----------------------
 2012-01-01  ¦  No 1  | 2012-01-01  ¦  No 1
 2012-01-03  ¦  No 3  | 2012-01-03  ¦  No 2

To lighten the subscription modification page, manual history has been
moved in its own page subscription-history.pl which is accessible on
subscription-detail.pl, tab 'Planning'.

Important note: updatedatabase.pl script takes into account existing
subscriptions and create appropriate numbering patterns for them (it
tries to create as few patterns as possible). Frequency is
mapped to the correct entry in subscription_frequencies table.

This patch includes kohastructure.sql and updatedatabase.pl changes
+ sample frequencies data and sample numberpatterns data for fresh
installs (sample data is included in updatedatabase.pl)

=== TEST PLAN: ===

Create a new subscription:

  - Go to Serials module and click "New subscription" button
  - On the first page, choose a biblio and click next to go to the
    second page
  - Pick a first issue publication date
  - Choose frequency '1/day'
  - Choose a subscription length of 15 issues
  - Choose a subscription start date
  - Choose numbering pattern 'Volume, Number'
  - A table appears, fill 'Begins with' cells with '1'
  - Click on 'Test prediction pattern' button

The prediction pattern is displayed at the right of the page. You can
see in it the serial number, the publication date and a checkbox to
allow you to choose which serials will not be received (irregularities).

You can see that serial number start from "Vol 1, No 1" continue to "Vol
1, No 12" and then restart with "Vol 2, No 1".

Frequency is '1/day' so you can see that publication date is incremented
by one day line after line.

  - Now you can play a little with frequencies and numbering patterns,
    change one of them (or both) and click again on 'Test prediction
    pattern'
  - For example, choose frequency '3/weeks' and click on 'Test
    prediction pattern' button'.

There is a little behaviour change compared with current master.
Publication date will not be guessed within the week. Koha can't know
when you will receive issues. So the publication date stay the same
(monday of each week) for 3 consecutive issues and then jump to the next
week.

  - Now choose frequency '1/3 months' and numbering pattern 'Seasonal'
  - Fill 'Begins with' cells with '2012' for Year and '0' for Season
  - Click on 'Test prediction pattern'
  - You should have something like 'Spring 2012', 'Summer 2012', ...,
    'Winter 2012', 'Spring 2013'
  - Note that you can have seasons for south hemisphere by entering '2'
    in 'Year/Inner counter'
  - 2nd note: if you have some locales installed on your system, you can
    type its name in the 'Locale' field (actually it does not work for
    seasons name, only for month names and day names)

If you want to modify the numbering pattern you can still do it here:

 - Click on 'Show/Hide advanced pattern' link. The advanced pattern
   table is shown but all fields are readonly
 - Click on 'Modify pattern' button. All readonly fields are now
   editable. Note that 'Begins with' and 'Inner counter' line are
   repeated here and any modifications in the small table will be
   replicated in the big table, and vice versa.
 - Pattern name is emptied, if you type a new name, a new pattern will
   be created, and if you type the same name as an existing numbering
   pattern, this one will be modified (with a confirmation message)
 - There is two new lines in this table:
   - Label: it's what is displayed in the smaller table headers above
   - Numbering: used to format numbers in different ways. can be
     'seasons', 'monthname' or 'dayname'. Month name and day name can be
     localized using the 'Locale' field. Seasons can't (values for
     english and french are hard-coded in Serials.pm)
 - You can modify what you want in the table and click on 'Test
   prediction pattern' button each time you want to see your
   modifications. (Note that checkboxes for irregularities aren't displayed
   in this mode, and you can't save the subscription until you have saved
   or cancelled your changes).
 - To cancel your modifications, just click on 'Cancel modifications'
   button.
 - To save them, click on 'Save as new pattern'. If the pattern name is
   already existing, a confirmation box will ask you if you want to
   modify the existing numbering pattern. Otherwise a new pattern will be
   created and automatically selected.

Once you have finished modifying numbering pattern. You can click again
on 'Test prediction pattern' to define irregularities, and then click on
'Save subscription'.

Now you can check the serials module still works correctly:

 - Check the subscription detail page to confirm that nothing is
   missing. Especially the 'Frequency' and 'Number pattern' infos
 - Try to receive some issues. Check that the serial number is correctly
   generated and if irregularities you have defined are taken into
   account (if you have defined some).
 - Check that receiving is blocked once you have reached the number of
   issues you have defined in subscription length (or once you have
   reached the subscription end date)

In serials menu (to the left of almost each page of serials menu) you
have two new links: 'Manage frequencies' and 'Manage numbering
patterns'.

'Manage numbering patterns' lead to a page which list all numbering
patterns and allow you to create, edit or delete them. The interface is
almost the same as numbering pattern modification in subscription-add.pl

'Manage frequencies' lead to a page which list all frequencies and allow
you to create, edit or delete them.

Try to create a new frequency:
 - Click on 'Manage frequencies' link in the serials menu and then click
   on 'New frequency':
 - Fill in the description (mandatory).
 - Unit is one of 'day', 'week', 'month', year' or 'None' ('None' is for
   an irregular subscription)
 - If unit is different from 'None' you have to fill the two following
   fields (Issues per unit, and Units per issue)
 - Note that at least one of those must be equal to 1
 - Issues per unit is the number of received issues by 'unit' and Units
   per issue is the number of 'unit' between two issues
 - Display order is used to build the drop-down list. Leave empty and it
   will be set to 0 (top of the list)
 - Then click on 'Save'
 - Check that this new frequency appears in the frequencies table and in
   the drop-down list in subscription-add.pl

Subscription history has been moved in its own page. To test if it still
works, choose a subscription with manual history enabled (or modify an
existing subscription to turn on manual history).

 - On the detail page, tab 'Planning', you should have a link 'Edit history'.
 - Click on it
 - Modify history and click on Save
 - In tab 'Summary' you should have the infos you just entered

And finally, you can check that old subscriptions (by old I mean
subscriptions that existed before the update) are correctly linked to an
existing numbering pattern and an existing frequency. Numbering patterns
should be named 'Backup pattern X' where X is a number.

Signed-off-by: Frédéric Demians <f.demians@tamil.fr>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>
Comment: Great development! Work as described. No koha-qa errors
(with all patches applied). Please QA this fast.

Signed-off-by: Paul Poulain <paul.poulain@biblibre.com>
Signed-off-by: Jared Camins-Esakov <jcamins@cpbibliography.com>
60 files changed:
C4/Serials.pm
C4/Serials/Frequency.pm [new file with mode: 0644]
C4/Serials/Numberpattern.pm [new file with mode: 0644]
installer/data/mysql/de-DE/optional/sample_frequencies.sql [new file with mode: 0644]
installer/data/mysql/de-DE/optional/sample_frequencies.txt [new file with mode: 0644]
installer/data/mysql/de-DE/optional/sample_numberpatterns.sql [new file with mode: 0644]
installer/data/mysql/de-DE/optional/sample_numberpatterns.txt [new file with mode: 0644]
installer/data/mysql/en/optional/sample_frequencies.sql [new file with mode: 0644]
installer/data/mysql/en/optional/sample_frequencies.txt [new file with mode: 0644]
installer/data/mysql/en/optional/sample_numberpatterns.sql [new file with mode: 0644]
installer/data/mysql/en/optional/sample_numberpatterns.txt [new file with mode: 0644]
installer/data/mysql/es-ES/optional/sample_frequencies.sql [new file with mode: 0644]
installer/data/mysql/es-ES/optional/sample_frequencies.txt [new file with mode: 0644]
installer/data/mysql/es-ES/optional/sample_numberpatterns.sql [new file with mode: 0644]
installer/data/mysql/es-ES/optional/sample_numberpatterns.txt [new file with mode: 0644]
installer/data/mysql/fr-FR/2-Optionel/sample_frequencies.sql [new file with mode: 0644]
installer/data/mysql/fr-FR/2-Optionel/sample_frequencies.txt [new file with mode: 0644]
installer/data/mysql/fr-FR/2-Optionel/sample_numberpatterns.sql [new file with mode: 0644]
installer/data/mysql/fr-FR/2-Optionel/sample_numberpatterns.txt [new file with mode: 0644]
installer/data/mysql/it-IT/optional/sample_frequencies.sql [new file with mode: 0644]
installer/data/mysql/it-IT/optional/sample_frequencies.txt [new file with mode: 0644]
installer/data/mysql/it-IT/optional/sample_numberpatterns.sql [new file with mode: 0644]
installer/data/mysql/it-IT/optional/sample_numberpatterns.txt [new file with mode: 0644]
installer/data/mysql/kohastructure.sql
installer/data/mysql/nb-NO/2-Valgfritt/sample_frequencies.sql [new file with mode: 0644]
installer/data/mysql/nb-NO/2-Valgfritt/sample_frequencies.txt [new file with mode: 0644]
installer/data/mysql/nb-NO/2-Valgfritt/sample_numberpatterns.sql [new file with mode: 0644]
installer/data/mysql/nb-NO/2-Valgfritt/sample_numberpatterns.txt [new file with mode: 0644]
installer/data/mysql/pl-PL/optional/sample_frequencies.sql [new file with mode: 0644]
installer/data/mysql/pl-PL/optional/sample_frequencies.txt [new file with mode: 0644]
installer/data/mysql/pl-PL/optional/sample_numberpatterns.sql [new file with mode: 0644]
installer/data/mysql/pl-PL/optional/sample_numberpatterns.txt [new file with mode: 0644]
installer/data/mysql/ru-RU/optional/sample_frequencies.sql [new file with mode: 0644]
installer/data/mysql/ru-RU/optional/sample_frequencies.txt [new file with mode: 0644]
installer/data/mysql/ru-RU/optional/sample_numberpatterns.sql [new file with mode: 0644]
installer/data/mysql/ru-RU/optional/sample_numberpatterns.txt [new file with mode: 0644]
installer/data/mysql/uk-UA/optional/sample_frequencies.sql [new file with mode: 0644]
installer/data/mysql/uk-UA/optional/sample_frequencies.txt [new file with mode: 0644]
installer/data/mysql/uk-UA/optional/sample_numberpatterns.sql [new file with mode: 0644]
installer/data/mysql/uk-UA/optional/sample_numberpatterns.txt [new file with mode: 0644]
installer/data/mysql/updatedatabase.pl
koha-tmpl/intranet-tmpl/prog/en/includes/serials-menu.inc
koha-tmpl/intranet-tmpl/prog/en/modules/serials/serials-collection.tt
koha-tmpl/intranet-tmpl/prog/en/modules/serials/showpredictionpattern.tt [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-add.tt
koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-detail.tt
koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-frequencies.tt [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-history.tt [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-numberpatterns.tt [new file with mode: 0644]
serials/create-numberpattern.pl [new file with mode: 0755]
serials/serials-collection.pl
serials/serials-recieve.pl
serials/showpredictionpattern.pl [new file with mode: 0755]
serials/subscription-add.pl
serials/subscription-detail.pl
serials/subscription-frequencies.pl [new file with mode: 0755]
serials/subscription-frequency.pl [new file with mode: 0755]
serials/subscription-history.pl [new file with mode: 0755]
serials/subscription-numberpattern.pl [new file with mode: 0755]
serials/subscription-numberpatterns.pl [new file with mode: 0755]

index 0b31a2b..3cbd042 100644 (file)
@@ -18,14 +18,16 @@ package C4::Serials;
 # with Koha; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-use strict;
-use warnings;
+use Modern::Perl;
+
 use C4::Dates qw(format_date format_date_in_iso);
 use Date::Calc qw(:all);
-use POSIX qw(strftime);
+use POSIX qw(strftime setlocale LC_TIME);
 use C4::Biblio;
 use C4::Log;    # logaction
 use C4::Debug;
+use C4::Serials::Frequency;
+use C4::Serials::Numberpattern;
 
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
 
@@ -39,8 +41,9 @@ BEGIN {
       &SearchSubscriptions
       &GetFullSubscriptionsFromBiblionumber   &GetFullSubscription &ModSubscriptionHistory
       &HasSubscriptionStrictlyExpired &HasSubscriptionExpired &GetExpirationDate &abouttoexpire
+      &GetSubscriptionHistoryFromSubscriptionId
 
-      &GetNextSeq         &NewIssue           &ItemizeSerials    &GetSerials
+      &GetNextSeq &GetSeq &NewIssue           &ItemizeSerials    &GetSerials
       &GetLatestSerials   &ModSerialStatus    &GetNextDate       &GetSerials2
       &ReNewSubscription  &GetLateIssues      &GetLateOrMissingIssues
       &GetSerialInformation                   &AddItem2Serial
@@ -162,20 +165,29 @@ sub GetLateIssues {
 
 =head2 GetSubscriptionHistoryFromSubscriptionId
 
-$sth = GetSubscriptionHistoryFromSubscriptionId()
-this function prepares the SQL request and returns the statement handle
-After this function, don't forget to execute it by using $sth->execute($subscriptionid)
+$history = GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
+
+This function returns the subscription history as a hashref
 
 =cut
 
 sub GetSubscriptionHistoryFromSubscriptionId {
+    my ($subscriptionid) = @_;
+
+    return unless $subscriptionid;
+
     my $dbh   = C4::Context->dbh;
     my $query = qq|
         SELECT *
         FROM   subscriptionhistory
         WHERE  subscriptionid = ?
     |;
-    return $dbh->prepare($query);
+    my $sth = $dbh->prepare($query);
+    $sth->execute($subscriptionid);
+    my $results = $sth->fetchrow_hashref;
+    $sth->finish;
+
+    return $results;
 }
 
 =head2 GetSerialStatusFromSerialId
@@ -569,7 +581,7 @@ sub GetSubscriptions {
     my $dbh = C4::Context->dbh;
     my $sth;
     my $sql = qq(
-            SELECT subscription.*, subscriptionhistory.*, biblio.title,biblioitems.issn,biblio.biblionumber
+            SELECT subscriptionhistory.*, subscription.*, biblio.title,biblioitems.issn,biblio.biblionumber
             FROM   subscription
             LEFT JOIN subscriptionhistory USING(subscriptionid)
             LEFT JOIN biblio ON biblio.biblionumber = subscription.biblionumber
@@ -885,85 +897,87 @@ a list containing all the input params updated.
 
 =cut
 
-# sub GetNextSeq {
-#     my ($val) =@_;
-#     my ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
-#     $calculated = $val->{numberingmethod};
-# # calculate the (expected) value of the next issue recieved.
-#     $newlastvalue1 = $val->{lastvalue1};
-# # check if we have to increase the new value.
-#     $newinnerloop1 = $val->{innerloop1}+1;
-#     $newinnerloop1=0 if ($newinnerloop1 >= $val->{every1});
-#     $newlastvalue1 += $val->{add1} if ($newinnerloop1<1); # <1 to be true when 0 or empty.
-#     $newlastvalue1=$val->{setto1} if ($newlastvalue1>$val->{whenmorethan1}); # reset counter if needed.
-#     $calculated =~ s/\{X\}/$newlastvalue1/g;
-#
-#     $newlastvalue2 = $val->{lastvalue2};
-# # check if we have to increase the new value.
-#     $newinnerloop2 = $val->{innerloop2}+1;
-#     $newinnerloop2=0 if ($newinnerloop2 >= $val->{every2});
-#     $newlastvalue2 += $val->{add2} if ($newinnerloop2<1); # <1 to be true when 0 or empty.
-#     $newlastvalue2=$val->{setto2} if ($newlastvalue2>$val->{whenmorethan2}); # reset counter if needed.
-#     $calculated =~ s/\{Y\}/$newlastvalue2/g;
-#
-#     $newlastvalue3 = $val->{lastvalue3};
-# # check if we have to increase the new value.
-#     $newinnerloop3 = $val->{innerloop3}+1;
-#     $newinnerloop3=0 if ($newinnerloop3 >= $val->{every3});
-#     $newlastvalue3 += $val->{add3} if ($newinnerloop3<1); # <1 to be true when 0 or empty.
-#     $newlastvalue3=$val->{setto3} if ($newlastvalue3>$val->{whenmorethan3}); # reset counter if needed.
-#     $calculated =~ s/\{Z\}/$newlastvalue3/g;
-#     return ($calculated,$newlastvalue1,$newlastvalue2,$newlastvalue3,$newinnerloop1,$newinnerloop2,$newinnerloop3);
-# }
-
 sub GetNextSeq {
-    my ($val) = @_;
-    my ( $calculated, $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3 );
-    my $pattern          = $val->{numberpattern};
-    my @seasons          = ( 'nothing', 'Winter', 'Spring', 'Summer', 'Autumn' );
-    my @southern_seasons = ( '', 'Summer', 'Autumn', 'Winter', 'Spring' );
-    $calculated    = $val->{numberingmethod};
-    $newlastvalue1 = $val->{lastvalue1};
-    $newlastvalue2 = $val->{lastvalue2};
-    $newlastvalue3 = $val->{lastvalue3};
-    $newlastvalue1 = $val->{lastvalue1};
-
-    # check if we have to increase the new value.
-    $newinnerloop1 = $val->{innerloop1} + 1;
-    $newinnerloop1 = 0 if ( $newinnerloop1 >= $val->{every1} );
-    $newlastvalue1 += $val->{add1} if ( $newinnerloop1 < 1 );    # <1 to be true when 0 or empty.
-    $newlastvalue1 = $val->{setto1} if ( $newlastvalue1 > $val->{whenmorethan1} );    # reset counter if needed.
-    $calculated =~ s/\{X\}/$newlastvalue1/g;
-
-    $newlastvalue2 = $val->{lastvalue2};
-
-    # check if we have to increase the new value.
-    $newinnerloop2 = $val->{innerloop2} + 1;
-    $newinnerloop2 = 0 if ( $newinnerloop2 >= $val->{every2} );
-    $newlastvalue2 += $val->{add2} if ( $newinnerloop2 < 1 );                         # <1 to be true when 0 or empty.
-    $newlastvalue2 = $val->{setto2} if ( $newlastvalue2 > $val->{whenmorethan2} );    # reset counter if needed.
-    if ( $pattern == 6 ) {
-        if ( $val->{hemisphere} == 2 ) {
-            my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
-            $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
-        } else {
-            my $newlastvalue2seq = $seasons[$newlastvalue2];
-            $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
+    my ($val, $planneddate) = @_;
+    my ( $calculated, $newlastvalue1, $newlastvalue2, $newlastvalue3,
+    $newinnerloop1, $newinnerloop2, $newinnerloop3 );
+    my $count = 1;
+
+    if($val->{'skip_serialseq'}) {
+        my @irreg = split /;/, $val->{'irregularity'};
+        if(@irreg > 0) {
+            my $irregularities = {};
+            $irregularities->{$_} = 1 foreach(@irreg);
+            my $issueno = GetFictiveIssueNumber($val, $planneddate) + 1;
+            while($irregularities->{$issueno}) {
+                $count++;
+                $issueno++;
+            }
         }
-    } else {
-        $calculated =~ s/\{Y\}/$newlastvalue2/g;
     }
 
-    $newlastvalue3 = $val->{lastvalue3};
-
-    # check if we have to increase the new value.
-    $newinnerloop3 = $val->{innerloop3} + 1;
-    $newinnerloop3 = 0 if ( $newinnerloop3 >= $val->{every3} );
-    $newlastvalue3 += $val->{add3} if ( $newinnerloop3 < 1 );    # <1 to be true when 0 or empty.
-    $newlastvalue3 = $val->{setto3} if ( $newlastvalue3 > $val->{whenmorethan3} );    # reset counter if needed.
-    $calculated =~ s/\{Z\}/$newlastvalue3/g;
+    my $pattern = $val->{numberpattern};
+    $calculated    = $val->{numberingmethod};
+    my $locale = $val->{locale};
+    $newlastvalue1 = $val->{lastvalue1} || 0;
+    $newlastvalue2 = $val->{lastvalue2} || 0;
+    $newlastvalue3 = $val->{lastvalue3} || 0;
+    $newinnerloop1 = $val->{innerloop1} || 0;
+    $newinnerloop2 = $val->{innerloop2} || 0;
+    $newinnerloop3 = $val->{innerloop3} || 0;
+    my %calc;
+    foreach(qw/X Y Z/) {
+        $calc{$_} = 1 if ($val->{'numberingmethod'} =~ /\{$_\}/);
+    }
+
+    for(my $i = 0; $i < $count; $i++) {
+        if($calc{'X'}) {
+            # check if we have to increase the new value.
+            $newinnerloop1 += 1;
+            if ($newinnerloop1 >= $val->{every1}) {
+                $newinnerloop1  = 0;
+                $newlastvalue1 += $val->{add1};
+            }
+            # reset counter if needed.
+            $newlastvalue1 = $val->{setto1} if ($newlastvalue1 > $val->{whenmorethan1});
+        }
+        if($calc{'Y'}) {
+            # check if we have to increase the new value.
+            $newinnerloop2 += 1;
+            if ($newinnerloop2 >= $val->{every2}) {
+                $newinnerloop2  = 0;
+                $newlastvalue2 += $val->{add2};
+            }
+            # reset counter if needed.
+            $newlastvalue2 = $val->{setto2} if ($newlastvalue2 > $val->{whenmorethan2});
+        }
+        if($calc{'Z'}) {
+            # check if we have to increase the new value.
+            $newinnerloop3 += 1;
+            if ($newinnerloop3 >= $val->{every3}) {
+                $newinnerloop3  = 0;
+                $newlastvalue3 += $val->{add3};
+            }
+            # reset counter if needed.
+            $newlastvalue3 = $val->{setto3} if ($newlastvalue3 > $val->{whenmorethan3});
+        }
+    }
+    if($calc{'X'}) {
+        my $newlastvalue1string = _numeration( $newlastvalue1, $val->{numbering1}, $locale );
+        $calculated =~ s/\{X\}/$newlastvalue1string/g;
+    }
+    if($calc{'Y'}) {
+        my $newlastvalue2string = _numeration( $newlastvalue2, $val->{numbering2}, $locale );
+        $calculated =~ s/\{Y\}/$newlastvalue2string/g;
+    }
+    if($calc{'Z'}) {
+        my $newlastvalue3string = _numeration( $newlastvalue3, $val->{numbering3}, $locale );
+        $calculated =~ s/\{Z\}/$newlastvalue3string/g;
+    }
 
-    return ( $calculated, $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3 );
+    return ($calculated,
+            $newlastvalue1, $newlastvalue2, $newlastvalue3,
+            $newinnerloop1, $newinnerloop2, $newinnerloop3);
 }
 
 =head2 GetSeq
@@ -978,27 +992,22 @@ the sequence in integer format
 
 sub GetSeq {
     my ($val) = @_;
+    my $locale = $val->{locale};
+
     my $pattern = $val->{numberpattern};
-    my @seasons          = ( 'nothing', 'Winter', 'Spring', 'Summer', 'Autumn' );
-    my @southern_seasons = ( '',        'Summer', 'Autumn', 'Winter', 'Spring' );
-    my $calculated       = $val->{numberingmethod};
-    my $x                = $val->{'lastvalue1'};
-    $calculated =~ s/\{X\}/$x/g;
-    my $newlastvalue2 = $val->{'lastvalue2'};
-
-    if ( $pattern == 6 ) {
-        if ( $val->{hemisphere} == 2 ) {
-            my $newlastvalue2seq = $southern_seasons[$newlastvalue2];
-            $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
-        } else {
-            my $newlastvalue2seq = $seasons[$newlastvalue2];
-            $calculated =~ s/\{Y\}/$newlastvalue2seq/g;
-        }
-    } else {
-        $calculated =~ s/\{Y\}/$newlastvalue2/g;
-    }
-    my $z = $val->{'lastvalue3'};
-    $calculated =~ s/\{Z\}/$z/g;
+    my $calculated = $val->{numberingmethod};
+
+    my $newlastvalue1 = $val->{'lastvalue1'} || 0;
+    $newlastvalue1 = _numeration($newlastvalue1, $val->{numbering1}, $locale) if ($val->{numbering1}); # reset counter if needed.
+    $calculated =~ s/\{X\}/$newlastvalue1/g;
+
+    my $newlastvalue2 = $val->{'lastvalue2'} || 0;
+    $newlastvalue2 = _numeration($newlastvalue2, $val->{numbering2}, $locale) if ($val->{numbering2}); # reset counter if needed.
+    $calculated =~ s/\{Y\}/$newlastvalue2/g;
+
+    my $newlastvalue3 = $val->{'lastvalue3'} || 0;
+    $newlastvalue3 = _numeration($newlastvalue3, $val->{numbering3}, $locale) if ($val->{numbering3}); # reset counter if needed.
+    $calculated =~ s/\{Z\}/$newlastvalue3/g;
     return $calculated;
 }
 
@@ -1023,14 +1032,15 @@ sub GetExpirationDate {
     $enddate = $startdate || $subscription->{startdate};
     my @date = split( /-/, $enddate );
     return if ( scalar(@date) != 3 || not check_date(@date) );
-    if ( ( $subscription->{periodicity} % 16 ) > 0 ) {
+    my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
+    if ( $frequency and $frequency->{unit} ) {
 
         # If Not Irregular
         if ( my $length = $subscription->{numberlength} ) {
 
             #calculate the date of the last issue.
             for ( my $i = 1 ; $i <= $length ; $i++ ) {
-                $enddate = GetNextDate( $enddate, $subscription );
+                $enddate = GetNextDate( $subscription, $enddate );
             }
         } elsif ( $subscription->{monthlength} ) {
             if ( $$subscription{startdate} ) {
@@ -1043,10 +1053,12 @@ sub GetExpirationDate {
                 my @enddate = Add_Delta_Days( $date[0], $date[1], $date[2], $subscription->{weeklength} * 7 );
                 $enddate = sprintf( "%04d-%02d-%02d", $enddate[0], $enddate[1], $enddate[2] );
             }
+        } else {
+            $enddate = $subscription->{enddate};
         }
         return $enddate;
     } else {
-        return;
+        return $subscription->{enddate};
     }
 }
 
@@ -1079,20 +1091,64 @@ returns the number of rows affected
 =cut
 
 sub ModSubscriptionHistory {
-    my ( $subscriptionid, $histstartdate, $enddate, $recievedlist, $missinglist, $opacnote, $librariannote ) = @_;
+    my ( $subscriptionid, $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote ) = @_;
     my $dbh   = C4::Context->dbh;
     my $query = "UPDATE subscriptionhistory 
                     SET histstartdate=?,histenddate=?,recievedlist=?,missinglist=?,opacnote=?,librariannote=?
                     WHERE subscriptionid=?
                 ";
     my $sth = $dbh->prepare($query);
-    $recievedlist =~ s/^; //;
-    $missinglist  =~ s/^; //;
-    $opacnote     =~ s/^; //;
-    $sth->execute( $histstartdate, $enddate, $recievedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
+    $receivedlist =~ s/^; // if $receivedlist;
+    $missinglist  =~ s/^; // if $missinglist;
+    $opacnote     =~ s/^; // if $opacnote;
+    $sth->execute( $histstartdate, $enddate, $receivedlist, $missinglist, $opacnote, $librariannote, $subscriptionid );
     return $sth->rows;
 }
 
+# Update missinglist field, used by ModSerialStatus
+sub _update_missinglist {
+    my $subscriptionid = shift;
+
+    my $dbh = C4::Context->dbh;
+    my @missingserials = GetSerials2($subscriptionid, "4,5");
+    my $missinglist;
+    foreach (@missingserials) {
+        if($_->{'status'} == 4) {
+            $missinglist .= $_->{'serialseq'} . "; ";
+        } elsif($_->{'status'} == 5) {
+            $missinglist .= "not issued " . $_->{'serialseq'} . "; ";
+        }
+    }
+    $missinglist =~ s/; $//;
+    my $query = qq{
+        UPDATE subscriptionhistory
+        SET missinglist = ?
+        WHERE subscriptionid = ?
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute($missinglist, $subscriptionid);
+}
+
+# Update recievedlist field, used by ModSerialStatus
+sub _update_receivedlist {
+    my $subscriptionid = shift;
+
+    my $dbh = C4::Context->dbh;
+    my @receivedserials = GetSerials2($subscriptionid, "2");
+    my $receivedlist;
+    foreach (@receivedserials) {
+        $receivedlist .= $_->{'serialseq'} . "; ";
+    }
+    $receivedlist =~ s/; $//;
+    my $query = qq{
+        UPDATE subscriptionhistory
+        SET recievedlist = ?
+        WHERE subscriptionid = ?
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute($receivedlist, $subscriptionid);
+}
+
 =head2 ModSerialStatus
 
 ModSerialStatus($serialid,$serialseq, $planneddate,$publisheddate,$status,$notes)
@@ -1105,22 +1161,30 @@ Note : if we change from "waited" to something else,then we will have to create
 sub ModSerialStatus {
     my ( $serialid, $serialseq, $planneddate, $publisheddate, $status, $notes ) = @_;
 
+
     #It is a usual serial
     # 1st, get previous status :
     my $dbh   = C4::Context->dbh;
-    my $query = "SELECT subscriptionid,status FROM serial WHERE  serialid=?";
+    my $query = "SELECT serial.subscriptionid,serial.status,subscription.periodicity
+        FROM serial, subscription
+        WHERE serial.subscriptionid=subscription.subscriptionid
+            AND serialid=?";
     my $sth   = $dbh->prepare($query);
     $sth->execute($serialid);
-    my ( $subscriptionid, $oldstatus ) = $sth->fetchrow;
+    my ( $subscriptionid, $oldstatus, $periodicity ) = $sth->fetchrow;
+    my $frequency = GetSubscriptionFrequency($periodicity);
 
     # change status & update subscriptionhistory
     my $val;
     if ( $status == 6 ) {
-        DelIssue( {'serialid'=>$serialid, 'subscriptionid'=>$subscriptionid,'serialseq'=>$serialseq} );
-    }
-    else {
-        my $query =
-'UPDATE serial SET serialseq=?,publisheddate=?,planneddate=?,status=?,notes=? WHERE  serialid = ?';
+        DelIssue( { 'serialid' => $serialid, 'subscriptionid' => $subscriptionid, 'serialseq' => $serialseq } );
+    } else {
+
+        unless ($frequency->{'unit'}) {
+            if ( not $planneddate or $planneddate eq '0000-00-00' ) { $planneddate = C4::Dates->new()->output('iso') };
+            if ( not $publisheddate or $publisheddate eq '0000-00-00' ) { $publisheddate = C4::Dates->new()->output('iso') };
+        }
+        my $query = 'UPDATE serial SET serialseq=?,publisheddate=?,planneddate=?,status=?,notes=? WHERE  serialid = ?';
         $sth = $dbh->prepare($query);
         $sth->execute( $serialseq, $publisheddate, $planneddate, $status, $notes, $serialid );
         $query = "SELECT * FROM   subscription WHERE  subscriptionid = ?";
@@ -1128,58 +1192,50 @@ sub ModSerialStatus {
         $sth->execute($subscriptionid);
         my $val = $sth->fetchrow_hashref;
         unless ( $val->{manualhistory} ) {
-            $query = "SELECT missinglist,recievedlist FROM subscriptionhistory WHERE  subscriptionid=?";
-            $sth   = $dbh->prepare($query);
-            $sth->execute($subscriptionid);
-            my ( $missinglist, $recievedlist ) = $sth->fetchrow;
-            if ( $status == 2 ) {
-
-                $recievedlist .= "; $serialseq"
-                  unless ( index( "$recievedlist", "$serialseq" ) >= 0 );
+            if ( $status == 2 || ($oldstatus == 2 && $status != 2) ) {
+                  _update_receivedlist($subscriptionid);
+            }
+            if($status == 4 || $status == 5
+              || ($oldstatus == 4 && $status != 4)
+              || ($oldstatus == 5 && $status != 5)) {
+                _update_missinglist($subscriptionid);
             }
-
-            #         warn "missinglist : $missinglist serialseq :$serialseq, ".index("$missinglist","$serialseq");
-            $missinglist .= "; $serialseq"
-              if ( $status == 4
-                and not index( "$missinglist", "$serialseq" ) >= 0 );
-            $missinglist .= "; not issued $serialseq"
-              if ( $status == 5
-                and index( "$missinglist", "$serialseq" ) >= 0 );
-            $query = "UPDATE subscriptionhistory SET recievedlist=?, missinglist=? WHERE  subscriptionid=?";
-            $sth   = $dbh->prepare($query);
-            $recievedlist =~ s/^; //;
-            $missinglist  =~ s/^; //;
-            $sth->execute( $recievedlist, $missinglist, $subscriptionid );
         }
     }
 
     # create new waited entry if needed (ie : was a "waited" and has changed)
     if ( $oldstatus == 1 && $status != 1 ) {
-        my $query = "SELECT * FROM   subscription WHERE  subscriptionid = ?";
+        my $query = qq{
+            SELECT subscription.*, subscription_numberpatterns.*,
+                   subscription_frequencies.*
+            FROM subscription
+            LEFT JOIN subscription_numberpatterns ON subscription.numberpattern = subscription_numberpatterns.id
+            LEFT JOIN subscription_frequencies ON subscription.periodicity = subscription_frequencies.id
+            WHERE subscriptionid = ?
+        };
         $sth = $dbh->prepare($query);
         $sth->execute($subscriptionid);
         my $val = $sth->fetchrow_hashref;
 
         # next issue number
-        my (
-            $newserialseq,  $newlastvalue1, $newlastvalue2, $newlastvalue3,
-            $newinnerloop1, $newinnerloop2, $newinnerloop3
-        ) = GetNextSeq($val);
+        my ( $newserialseq, $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3 ) = GetNextSeq($val, $publisheddate);
 
         # next date (calculated from actual date & frequency parameters)
-        my $nextpublisheddate = GetNextDate( $publisheddate, $val );
-        NewIssue( $newserialseq, $subscriptionid, $val->{'biblionumber'}, 1, $nextpublisheddate, $nextpublisheddate );
+        my $nextpublisheddate = GetNextDate($val, $publisheddate, 1);
+        my $nextpubdate = $nextpublisheddate;
+        NewIssue( $newserialseq, $subscriptionid, $val->{'biblionumber'}, 1, $nextpubdate, $nextpubdate );
         $query = "UPDATE subscription SET lastvalue1=?, lastvalue2=?, lastvalue3=?, innerloop1=?, innerloop2=?, innerloop3=?
                     WHERE  subscriptionid = ?";
         $sth = $dbh->prepare($query);
         $sth->execute( $newlastvalue1, $newlastvalue2, $newlastvalue3, $newinnerloop1, $newinnerloop2, $newinnerloop3, $subscriptionid );
 
-# check if an alert must be sent... (= a letter is defined & status became "arrived"
+        # check if an alert must be sent... (= a letter is defined & status became "arrived"
         if ( $val->{letter} && $status == 2 && $oldstatus != 2 ) {
             require C4::Letters;
             C4::Letters::SendAlerts( 'issue', $val->{subscriptionid}, $val->{letter} );
         }
     }
+
     return;
 }
 
@@ -1193,31 +1249,50 @@ returns a hashref:
 
 $nextexepected = {
     serialid => int
-    planneddate => C4::Dates object
+    planneddate => ISO date
     }
 
 =cut
 
 sub GetNextExpected {
     my ($subscriptionid) = @_;
-    my $dbh              = C4::Context->dbh;
-    my $sth              = $dbh->prepare('SELECT serialid, planneddate FROM serial WHERE subscriptionid=? AND status=?');
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        SELECT *
+        FROM serial
+        WHERE subscriptionid = ?
+          AND status = ?
+        LIMIT 1
+    };
+    my $sth = $dbh->prepare($query);
 
     # Each subscription has only one 'expected' issue, with serial.status==1.
     $sth->execute( $subscriptionid, 1 );
-    my ( $nextissue ) = $sth->fetchrow_hashref;
-    if( !$nextissue){
-         $sth = $dbh->prepare('SELECT serialid,planneddate FROM serial WHERE subscriptionid  = ? ORDER BY planneddate DESC LIMIT 1');
-         $sth->execute( $subscriptionid );  
-         $nextissue = $sth->fetchrow_hashref;       
+    my $nextissue = $sth->fetchrow_hashref;
+    if ( !$nextissue ) {
+        $query = qq{
+            SELECT *
+            FROM serial
+            WHERE subscriptionid = ?
+            ORDER BY planneddate DESC
+            LIMIT 1
+        };
+        $sth = $dbh->prepare($query);
+        $sth->execute($subscriptionid);
+        $nextissue = $sth->fetchrow_hashref;
     }
-    if (!defined $nextissue->{planneddate}) {
-        # or should this default to 1st Jan ???
-        $nextissue->{planneddate} = strftime('%Y-%m-%d',localtime);
+    foreach(qw/planneddate publisheddate/) {
+        if ( !defined $nextissue->{$_} ) {
+            # or should this default to 1st Jan ???
+            $nextissue->{$_} = strftime( '%Y-%m-%d', localtime );
+        }
+        $nextissue->{$_} = ($nextissue->{$_} ne '0000-00-00')
+                         ? $nextissue->{$_}
+                         : undef;
     }
-    $nextissue->{planneddate} = C4::Dates->new($nextissue->{planneddate},'iso');
-    return $nextissue;
 
+    return $nextissue;
 }
 
 =head2 ModNextExpected
@@ -1227,7 +1302,7 @@ 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.
+C<$date> is an ISO date.
 
 returns 0
 
@@ -1241,11 +1316,42 @@ sub ModNextExpected {
     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 );
+    $sth->execute( $date, $date, $subscriptionid, 1 );
     return 0;
 
 }
 
+=head2 GetSubscriptionIrregularities
+
+=over4
+
+=item @irreg = &GetSubscriptionIrregularities($subscriptionid);
+get the list of irregularities for a subscription
+
+=back
+
+=cut
+
+sub GetSubscriptionIrregularities {
+    my $subscriptionid = shift;
+
+    return undef unless $subscriptionid;
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        SELECT irregularity
+        FROM subscription
+        WHERE subscriptionid = ?
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute($subscriptionid);
+
+    my ($result) = $sth->fetchrow_array;
+    my @irreg = split /;/, $result;
+
+    return @irreg;
+}
+
 =head2 ModSubscription
 
 this function modifies a subscription. Put all new values on input args.
@@ -1254,43 +1360,41 @@ returns the number of rows affected
 =cut
 
 sub ModSubscription {
-    my ($auser,           $branchcode,      $aqbooksellerid,    $cost,             $aqbudgetid,    $startdate,   $periodicity,   $firstacquidate,
-        $dow,             $irregularity,    $numberpattern,     $numberlength,     $weeklength,    $monthlength, $add1,          $every1,
-        $whenmorethan1,   $setto1,          $lastvalue1,        $innerloop1,       $add2,          $every2,      $whenmorethan2, $setto2,
-        $lastvalue2,      $innerloop2,      $add3,              $every3,           $whenmorethan3, $setto3,      $lastvalue3,    $innerloop3,
-        $numberingmethod, $status,          $biblionumber,      $callnumber,       $notes,         $letter,      $hemisphere,    $manualhistory,
-        $internalnotes,   $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,   $location,    $enddate,       $subscriptionid
+    my (
+    $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate,
+    $periodicity, $firstacquidate, $irregularity, $numberpattern, $locale,
+    $numberlength, $weeklength, $monthlength, $lastvalue1, $innerloop1,
+    $lastvalue2, $innerloop2, $lastvalue3, $innerloop3, $status,
+    $biblionumber, $callnumber, $notes, $letter, $manualhistory,
+    $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
+    $graceperiod, $location, $enddate, $subscriptionid, $skip_serialseq
     ) = @_;
 
-    #     warn $irregularity;
     my $dbh   = C4::Context->dbh;
     my $query = "UPDATE subscription
-                    SET librarian=?, branchcode=?,aqbooksellerid=?,cost=?,aqbudgetid=?,startdate=?,
-                        periodicity=?,firstacquidate=?,dow=?,irregularity=?, numberpattern=?, numberlength=?,weeklength=?,monthlength=?,
-                        add1=?,every1=?,whenmorethan1=?,setto1=?,lastvalue1=?,innerloop1=?,
-                        add2=?,every2=?,whenmorethan2=?,setto2=?,lastvalue2=?,innerloop2=?,
-                        add3=?,every3=?,whenmorethan3=?,setto3=?,lastvalue3=?,innerloop3=?,
-                        numberingmethod=?, status=?, biblionumber=?, callnumber=?, notes=?, 
-                                               letter=?, hemisphere=?,manualhistory=?,internalnotes=?,serialsadditems=?,
-                                               staffdisplaycount = ?,opacdisplaycount = ?, graceperiod = ?, location = ?
-                                               ,enddate=?
-                    WHERE subscriptionid = ?";
-
-    #warn "query :".$query;
+        SET librarian=?, branchcode=?, aqbooksellerid=?, cost=?, aqbudgetid=?,
+            startdate=?, periodicity=?, firstacquidate=?, irregularity=?,
+            numberpattern=?, locale=?, numberlength=?, weeklength=?, monthlength=?,
+            lastvalue1=?, innerloop1=?, lastvalue2=?, innerloop2=?,
+            lastvalue3=?, innerloop3=?, status=?, biblionumber=?,
+            callnumber=?, notes=?, letter=?, manualhistory=?,
+            internalnotes=?, serialsadditems=?, staffdisplaycount=?,
+            opacdisplaycount=?, graceperiod=?, location = ?, enddate=?,
+            skip_serialseq=?
+        WHERE subscriptionid = ?";
+
     my $sth = $dbh->prepare($query);
     $sth->execute(
         $auser,           $branchcode,     $aqbooksellerid, $cost,
         $aqbudgetid,      $startdate,      $periodicity,    $firstacquidate,
-        $dow,             "$irregularity", $numberpattern,  $numberlength,
-        $weeklength,      $monthlength,    $add1,           $every1,
-        $whenmorethan1,   $setto1,         $lastvalue1,     $innerloop1,
-        $add2,            $every2,         $whenmorethan2,  $setto2,
-        $lastvalue2,      $innerloop2,     $add3,           $every3,
-        $whenmorethan3,   $setto3,         $lastvalue3,     $innerloop3,
-        $numberingmethod, $status,         $biblionumber,   $callnumber,
-        $notes, $letter, $hemisphere, ( $manualhistory ? $manualhistory : 0 ),
+        $irregularity,    $numberpattern,  $locale,         $numberlength,
+        $weeklength,      $monthlength,    $lastvalue1,     $innerloop1,
+        $lastvalue2,      $innerloop2,     $lastvalue3,     $innerloop3,
+        $status,          $biblionumber,   $callnumber,     $notes,
+        $letter,          ($manualhistory ? $manualhistory : 0),
         $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount,
-        $graceperiod,   $location,        $enddate,           $subscriptionid
+        $graceperiod,     $location,       $enddate,        $skip_serialseq,
+        $subscriptionid
     );
     my $rows = $sth->rows;
 
@@ -1302,11 +1406,10 @@ sub ModSubscription {
 
 $subscriptionid = &NewSubscription($auser,branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
     $startdate,$periodicity,$dow,$numberlength,$weeklength,$monthlength,
-    $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
-    $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
-    $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
-    $numberingmethod, $status, $notes, $serialsadditems,
-    $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate);
+    $lastvalue1,$innerloop1,$lastvalue2,$innerloop2,$lastvalue3,$innerloop3,
+    $status, $notes, $letter, $firstacquidate, $irregularity, $numberpattern,
+    $callnumber, $hemisphere, $manualhistory, $internalnotes, $serialsadditems,
+    $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq);
 
 Create a new subscription with value given on input args.
 
@@ -1316,42 +1419,44 @@ the id of this new subscription
 =cut
 
 sub NewSubscription {
-    my ($auser,         $branchcode,      $aqbooksellerid,    $cost,             $aqbudgetid,    $biblionumber, $startdate,       $periodicity,
-        $dow,           $numberlength,    $weeklength,        $monthlength,      $add1,          $every1,       $whenmorethan1,   $setto1,
-        $lastvalue1,    $innerloop1,      $add2,              $every2,           $whenmorethan2, $setto2,       $lastvalue2,      $innerloop2,
-        $add3,          $every3,          $whenmorethan3,     $setto3,           $lastvalue3,    $innerloop3,   $numberingmethod, $status,
-        $notes,         $letter,          $firstacquidate,    $irregularity,     $numberpattern, $callnumber,   $hemisphere,      $manualhistory,
-        $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,   $location,     $enddate
+    my (
+    $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
+    $startdate, $periodicity, $numberlength, $weeklength, $monthlength,
+    $lastvalue1, $innerloop1, $lastvalue2, $innerloop2, $lastvalue3,
+    $innerloop3, $status, $notes, $letter, $firstacquidate, $irregularity,
+    $numberpattern, $locale, $callnumber, $manualhistory, $internalnotes,
+    $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,
+    $location, $enddate, $skip_serialseq
     ) = @_;
     my $dbh = C4::Context->dbh;
 
     #save subscription (insert into database)
     my $query = qq|
         INSERT INTO subscription
-            (librarian,branchcode,aqbooksellerid,cost,aqbudgetid,biblionumber,
-            startdate,periodicity,dow,numberlength,weeklength,monthlength,
-            add1,every1,whenmorethan1,setto1,lastvalue1,innerloop1,
-            add2,every2,whenmorethan2,setto2,lastvalue2,innerloop2,
-            add3,every3,whenmorethan3,setto3,lastvalue3,innerloop3,
-            numberingmethod, status, notes, letter,firstacquidate,irregularity,
-            numberpattern, callnumber, hemisphere,manualhistory,internalnotes,serialsadditems,
-            staffdisplaycount,opacdisplaycount,graceperiod,location,enddate)
-        VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
+            (librarian, branchcode, aqbooksellerid, cost, aqbudgetid,
+            biblionumber, startdate, periodicity, numberlength, weeklength,
+            monthlength, lastvalue1, innerloop1, lastvalue2, innerloop2,
+            lastvalue3, innerloop3, status, notes, letter, firstacquidate,
+            irregularity, numberpattern, locale, callnumber,
+            manualhistory, internalnotes, serialsadditems, staffdisplaycount,
+            opacdisplaycount, graceperiod, location, enddate, skip_serialseq)
+        VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
         |;
     my $sth = $dbh->prepare($query);
     $sth->execute(
-        $auser,         $branchcode,      $aqbooksellerid,    $cost,             $aqbudgetid,    $biblionumber, $startdate,       $periodicity,
-        $dow,           $numberlength,    $weeklength,        $monthlength,      $add1,          $every1,       $whenmorethan1,   $setto1,
-        $lastvalue1,    $innerloop1,      $add2,              $every2,           $whenmorethan2, $setto2,       $lastvalue2,      $innerloop2,
-        $add3,          $every3,          $whenmorethan3,     $setto3,           $lastvalue3,    $innerloop3,   $numberingmethod, "$status",
-        $notes,         $letter,          $firstacquidate,    $irregularity,     $numberpattern, $callnumber,   $hemisphere,      $manualhistory,
-        $internalnotes, $serialsadditems, $staffdisplaycount, $opacdisplaycount, $graceperiod,   $location,     $enddate
+        $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
+        $startdate, $periodicity, $numberlength, $weeklength,
+        $monthlength, $lastvalue1, $innerloop1, $lastvalue2, $innerloop2,
+        $lastvalue3, $innerloop3, $status, $notes, $letter,
+        $firstacquidate, $irregularity, $numberpattern, $locale, $callnumber,
+        $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount,
+        $opacdisplaycount, $graceperiod, $location, $enddate, $skip_serialseq
     );
 
     my $subscriptionid = $dbh->{'mysql_insertid'};
-    unless ($enddate){
-       $enddate = GetExpirationDate($subscriptionid,$startdate);
-        $query = q|
+    unless ($enddate) {
+        $enddate = GetExpirationDate( $subscriptionid, $startdate );
+        $query = qq|
             UPDATE subscription
             SET    enddate=?
             WHERE  subscriptionid=?
@@ -1359,7 +1464,8 @@ sub NewSubscription {
         $sth = $dbh->prepare($query);
         $sth->execute( $enddate, $subscriptionid );
     }
-    #then create the 1st waited number
+
+    # then create the 1st expected number
     $query = qq(
         INSERT INTO subscriptionhistory
             (biblionumber, subscriptionid, histstartdate,  opacnote, librariannote)
@@ -1372,6 +1478,7 @@ sub NewSubscription {
     $query = qq(
         SELECT *
         FROM   subscription
+        LEFT JOIN subscription_numberpatterns ON subscription.numberpattern = subscription_numberpatterns.id
         WHERE  subscriptionid = ?
     );
     $sth = $dbh->prepare($query);
@@ -1392,7 +1499,7 @@ sub NewSubscription {
 
     #set serial flag on biblio if not already set.
     my $bib = GetBiblio($biblionumber);
-    if ( !$bib->{'serial'} ) {
+    if ( $bib and !$bib->{'serial'} ) {
         my $record = GetMarcBiblio($biblionumber);
         my ( $tag, $subf ) = GetMarcFromKohaField( 'biblio.serial', $bib->{'frameworkcode'} );
         if ($tag) {
@@ -1710,7 +1817,8 @@ sub HasSubscriptionExpired {
     my ($subscriptionid) = @_;
     my $dbh              = C4::Context->dbh;
     my $subscription     = GetSubscription($subscriptionid);
-    if ( ( $subscription->{periodicity} % 16 ) > 0 ) {
+    my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subscription->{periodicity});
+    if ( $frequency and $frequency->{unit} ) {
         my $expirationdate = $subscription->{enddate} || GetExpirationDate($subscriptionid);
         if (!defined $expirationdate) {
             $expirationdate = q{};
@@ -1734,6 +1842,7 @@ sub HasSubscriptionExpired {
             || ( !$res ) );
         return 0;
     } else {
+        # Irregular
         if ( $subscription->{'numberlength'} ) {
             my $countreceived = countissuesfrom( $subscriptionid, $subscription->{'startdate'} );
             return 1 if ( $countreceived > $subscription->{'numberlength'} );
@@ -2225,29 +2334,17 @@ sub abouttoexpire {
     my $dbh              = C4::Context->dbh;
     my $subscription     = GetSubscription($subscriptionid);
     my $per = $subscription->{'periodicity'};
-    if ($per && $per % 16 > 0){
-        my $expirationdate   = GetExpirationDate($subscriptionid);
+    my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($per);
+    if ($frequency and $frequency->{unit}){
+        my $expirationdate = GetExpirationDate($subscriptionid);
         my ($res) = $dbh->selectrow_array('select max(planneddate) from serial where subscriptionid = ?', undef, $subscriptionid);
-        my @res;
-        if (defined $res) {
-            @res=split (/-/,$res);
-            @res=Date::Calc::Today if ($res[0]*$res[1]==0);
-        } else { # default an undefined value
-            @res=Date::Calc::Today;
+        my $nextdate = GetNextDate($subscription, $res);
+        if(Date::Calc::Delta_Days(
+            split( /-/, $nextdate ),
+            split( /-/, $expirationdate )
+        ) <= 0) {
+            return 1;
         }
-        my @endofsubscriptiondate=split(/-/,$expirationdate);
-        my @per_list = (0, 7, 7, 14, 21, 31, 62, 93, 93, 190, 365, 730, 0, 124, 0, 0);
-        my @datebeforeend;
-        @datebeforeend = Add_Delta_Days(  $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2],
-            - (3 * $per_list[$per])) if (@endofsubscriptiondate && $endofsubscriptiondate[0]*$endofsubscriptiondate[1]*$endofsubscriptiondate[2]);
-        return 1 if ( @res &&
-            (@datebeforeend &&
-                Delta_Days($res[0],$res[1],$res[2],
-                    $datebeforeend[0],$datebeforeend[1],$datebeforeend[2]) <= 0) &&
-            (@endofsubscriptiondate &&
-                Delta_Days($res[0],$res[1],$res[2],
-                    $endofsubscriptiondate[0],$endofsubscriptiondate[1],$endofsubscriptiondate[2]) >= 0) );
-        return 0;
     } elsif ($subscription->{numberlength}>0) {
         return (countissuesfrom($subscriptionid,$subscription->{'startdate'}) >=$subscription->{numberlength}-1);
     }
@@ -2298,170 +2395,277 @@ sub GetSubscriptionsFromBorrower {
     return ( $count, @routinglist );
 }
 
-=head2 GetNextDate
 
-$resultdate = GetNextDate($planneddate,$subscription)
+=head2 GetFictiveIssueNumber
 
-this function it takes the planneddate and will return the next issue's date and will skip dates if there
-exists an irregularity
-- eg if periodicity is monthly and $planneddate is 2007-02-10 but if March and April is to be 
-skipped then the returned date will be 2007-05-10
-
-return :
-$resultdate - then next date in the sequence
+$issueno = GetFictiveIssueNumber($subscription, $publishedate);
 
-Return 0 if periodicity==0
+Get the position of the issue published at $publisheddate, considering the
+first issue (at firstacquidate) is at position 1, the next is at position 2, etc...
+This issuenumber doesn't take into account irregularities, so, for instance, if the 3rd
+issue is declared as 'irregular' (will be skipped at receipt), the next issue number
+will be 4, not 3. It's why it is called 'fictive'. It is NOT a serial seq, and is not
+depending on how many rows are in serial table.
+The issue number calculation is based on subscription frequency, first acquisition
+date, and $publisheddate.
 
 =cut
 
-sub GetNextDate {
-    my ( $planneddate, $subscription ) = @_;
-    my @irreg = split( /\,/, $subscription->{irregularity} );
+sub GetFictiveIssueNumber {
+    my ($subscription, $publisheddate) = @_;
+
+    my $frequency = GetSubscriptionFrequency($subscription->{'periodicity'});
+    my $unit = $frequency->{unit} ? lc $frequency->{'unit'} : undef;
+    my $issueno = 0;
+
+    if($unit) {
+        my ($year, $month, $day) = split /-/, $publisheddate;
+        my ($fa_year, $fa_month, $fa_day) = split /-/, $subscription->{'firstacquidate'};
+        my $wkno;
+        my $delta;
+
+        if($unit eq 'day') {
+            $delta = Delta_Days($fa_year, $fa_month, $fa_day, $year, $month, $day);
+        } elsif($unit eq 'week') {
+            ($wkno, $year) = Week_of_Year($year, $month, $day);
+            my ($fa_wkno, $fa_yr) = Week_of_Year($fa_year, $fa_month, $fa_day);
+            $delta = ($fa_yr == $year) ? ($wkno - $fa_wkno) : ( ($year-$fa_yr-1)*52 + (52-$fa_wkno+$wkno) );
+        } elsif($unit eq 'month') {
+            $delta = ($fa_year == $year)
+                   ? ($month - $fa_month)
+                   : ( ($year-$fa_year-1)*12 + (12-$fa_month+$month) );
+        } elsif($unit eq 'year') {
+            $delta = $year - $fa_year;
+        }
+        if($frequency->{'unitsperissue'} == 1) {
+            $issueno = $delta * $frequency->{'issuesperunit'} + $subscription->{'countissuesperunit'};
+        } else {
+            # Assuming issuesperunit == 1
+            $issueno = int( ($delta + $frequency->{'unitsperissue'}) / $frequency->{'unitsperissue'} );
+        }
+    }
+    return $issueno;
+}
 
-    #date supposed to be in ISO.
+=head2 GetNextDate
 
-    my ( $year, $month, $day ) = split( /-/, $planneddate );
-    $month = 1 unless ($month);
-    $day   = 1 unless ($day);
-    my @resultdate;
+$resultdate = GetNextDate($publisheddate,$subscription)
 
-    #       warn "DOW $dayofweek";
-    if ( $subscription->{periodicity} % 16 == 0 ) {    # 'without regularity' || 'irregular'
-        return 0;
-    }
+this function it takes the publisheddate and will return the next issue's date
+and will skip dates if there exists an irregularity.
+$publisheddate has to be an ISO date
+$subscription is a hashref containing at least 'periodicity', 'firstacquidate', 'irregularity', and 'countissuesperunit'
+$updatecount is a boolean value which, when set to true, update the 'countissuesperunit' in database
+- eg if periodicity is monthly and $publisheddate is 2007-02-10 but if March and April is to be
+skipped then the returned date will be 2007-05-10
 
-    #   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 {
-            for ( my $i = 0 ; $i < @irreg ; $i++ ) {
-                $dayofweek = 0 if ( $dayofweek == 7 );
-                if ( in_array( ( $dayofweek + 1 ), @irreg ) ) {
-                    ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 1 );
-                    $dayofweek++;
-                }
-            }
-            @resultdate = Add_Delta_Days( $year, $month, $day, 1 );
-        }
-    }
+return :
+$resultdate - then next date in the sequence (ISO date)
 
-    #   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++ ) {
+Return $publisheddate if subscription is irregular
 
-                #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 );
-                }
-            }
-            @resultdate = Add_Delta_Days( $year, $month, $day, 7 );
-        }
-    }
+=cut
 
-    #   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} : $@"; }
-        else {
-            for ( my $i = 0 ; $i < @irreg ; $i++ ) {
-                if ( $irreg[$i] == ( ( $wkno != 50 ) ? ( $wkno + 2 ) % 52 : 52 ) ) {
-                    ### BUGFIX was previously +1 ^
-                    ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 14 );
-                    $wkno = ( ( $wkno != 50 ) ? ( $wkno + 2 ) % 52 : 52 );
-                }
-            }
-            @resultdate = Add_Delta_Days( $year, $month, $day, 14 );
+sub GetNextDate {
+    my ( $subscription, $publisheddate, $updatecount ) = @_;
+
+    my $freqdata = GetSubscriptionFrequency($subscription->{'periodicity'});
+
+    if ($freqdata->{'unit'}) {
+        my ( $year, $month, $day ) = split /-/, $publisheddate;
+
+        # Process an irregularity Hash
+        # Suppose that irregularities are stored in a string with this structure
+        # irreg1;irreg2;irreg3
+        # where irregX is the number of issue which will not be received
+        # (the first issue takes the number 1, the 2nd the number 2 and so on)
+        my @irreg = split /;/, $subscription->{'irregularity'} ;
+        my %irregularities;
+        foreach my $irregularity (@irreg) {
+            $irregularities{$irregularity} = 1;
         }
-    }
 
-    #   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} : $@"; }
-        else {
-            for ( my $i = 0 ; $i < @irreg ; $i++ ) {
-                if ( $irreg[$i] == ( ( $wkno != 49 ) ? ( $wkno + 3 ) % 52 : 52 ) ) {
-                    ( $year, $month, $day ) = Add_Delta_Days( $year, $month, $day, 21 );
-                    $wkno = ( ( $wkno != 49 ) ? ( $wkno + 3 ) % 52 : 52 );
+        # Get the 'fictive' next issue number
+        # It is used to check if next issue is an irregular issue.
+        my $issueno = GetFictiveIssueNumber($subscription, $publisheddate) + 1;
+
+        # Then get the next date
+        my $unit = lc $freqdata->{'unit'};
+        if ($unit eq 'day') {
+            while ($irregularities{$issueno}) {
+                if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
+                    ($year,$month,$day) = Add_Delta_Days($year,$month, $day , $freqdata->{'unitsperissue'} );
+                    $subscription->{'countissuesperunit'} = 1;
+                } else {
+                    $subscription->{'countissuesperunit'}++;
                 }
+                $issueno++;
+            }
+            if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
+                ($year,$month,$day) = Add_Delta_Days($year,$month, $day , $freqdata->{"unitsperissue"} );
+                $subscription->{'countissuesperunit'} = 1;
+            } else {
+                $subscription->{'countissuesperunit'}++;
             }
-            @resultdate = Add_Delta_Days( $year, $month, $day, 21 );
         }
-    }
-    my $tmpmonth = $month;
-    if ( $year && $month && $day ) {
-        if ( $subscription->{periodicity} == 5 ) {
-            for ( my $i = 0 ; $i < @irreg ; $i++ ) {
-                if ( $irreg[$i] == ( ( $tmpmonth != 11 ) ? ( $tmpmonth + 1 ) % 12 : 12 ) ) {
-                    ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 1, 0 );
-                    $tmpmonth = ( ( $tmpmonth != 11 ) ? ( $tmpmonth + 1 ) % 12 : 12 );
+        elsif ($unit eq 'week') {
+            my ($wkno, $yr) = Week_of_Year($year, $month, $day);
+            while ($irregularities{$issueno}) {
+                if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
+                    $subscription->{'countissuesperunit'} = 1;
+                    $wkno += $freqdata->{"unitsperissue"};
+                    if($wkno > 52){
+                        $wkno = $wkno % 52;
+                        $yr++;
+                    }
+                    my $dow = Day_of_Week($year, $month, $day);
+                    ($year,$month,$day) = Monday_of_Week($wkno, $yr);
+                    if($freqdata->{'issuesperunit'} == 1) {
+                        ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $dow - 1);
+                    }
+                } else {
+                    $subscription->{'countissuesperunit'}++;
                 }
+                $issueno++;
             }
-            @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 1, 0 );
-        }
-        if ( $subscription->{periodicity} == 6 ) {
-            for ( my $i = 0 ; $i < @irreg ; $i++ ) {
-                if ( $irreg[$i] == ( ( $tmpmonth != 10 ) ? ( $tmpmonth + 2 ) % 12 : 12 ) ) {
-                    ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 2, 0 );
-                    $tmpmonth = ( ( $tmpmonth != 10 ) ? ( $tmpmonth + 2 ) % 12 : 12 );
+            if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
+                $subscription->{'countissuesperunit'} = 1;
+                $wkno += $freqdata->{"unitsperissue"};
+                if($wkno > 52){
+                    $wkno = $wkno % 52 ;
+                    $yr++;
                 }
+                my $dow = Day_of_Week($year, $month, $day);
+                ($year,$month,$day) = Monday_of_Week($wkno, $yr);
+                if($freqdata->{'issuesperunit'} == 1) {
+                    ($year, $month, $day) = Add_Delta_Days($year, $month, $day, $dow - 1);
+                }
+            } else {
+                $subscription->{'countissuesperunit'}++;
             }
-            @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 2, 0 );
         }
-        if ( $subscription->{periodicity} == 7 ) {
-            for ( my $i = 0 ; $i < @irreg ; $i++ ) {
-                if ( $irreg[$i] == ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 ) ) {
-                    ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
-                    $tmpmonth = ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 );
+        elsif ($unit eq 'month') {
+            while ($irregularities{$issueno}) {
+                if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
+                    $subscription->{'countissuesperunit'} = 1;
+                    ($year,$month,$day) = Add_Delta_YM($year,$month,$day, 0,$freqdata->{"unitsperissue"});
+                    unless($freqdata->{'issuesperunit'} == 1) {
+                        $day = 1;   # Jumping to the first day of month, because we don't know what day is expected
+                    }
+                } else {
+                    $subscription->{'countissuesperunit'}++;
                 }
+                $issueno++;
             }
-            @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
-        }
-        if ( $subscription->{periodicity} == 8 ) {
-            for ( my $i = 0 ; $i < @irreg ; $i++ ) {
-                if ( $irreg[$i] == ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 ) ) {
-                    ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
-                    $tmpmonth = ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 );
+            if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
+                $subscription->{'countissuesperunit'} = 1;
+                ($year,$month,$day) = Add_Delta_YM($year,$month,$day, 0,$freqdata->{"unitsperissue"});
+                unless($freqdata->{'issuesperunit'} == 1) {
+                    $day = 1;   # Jumping to the first day of month, because we don't know what day is expected
                 }
+            } else {
+                $subscription->{'countissuesperunit'}++;
             }
-            @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 3, 0 );
         }
-        if ( $subscription->{periodicity} == 13 ) {
-            for ( my $i = 0 ; $i < @irreg ; $i++ ) {
-                if ( $irreg[$i] == ( ( $tmpmonth != 8 ) ? ( $tmpmonth + 4 ) % 12 : 12 ) ) {
-                    ( $year, $month, $day ) = Add_Delta_YMD( $year, $month, $day, 0, 4, 0 );
-                    $tmpmonth = ( ( $tmpmonth != 8 ) ? ( $tmpmonth + 4 ) % 12 : 12 );
+        elsif ($unit eq 'year') {
+            while ($irregularities{$issueno}) {
+                if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
+                    $subscription->{'countissuesperunit'} = 1;
+                    ($year,$month,$day) = Add_Delta_YM($year,$month,$day, $freqdata->{"unitsperissue"},0);
+                    unless($freqdata->{'issuesperunit'} == 1) {
+                        # Jumping to the first day of year, because we don't know what day is expected
+                        $month = 1;
+                        $day = 1;
+                    }
+                } else {
+                    $subscription->{'countissuesperunit'}++;
                 }
+                $issueno++;
             }
-            @resultdate = Add_Delta_YMD( $year, $month, $day, 0, 4, 0 );
-        }
-        if ( $subscription->{periodicity} == 9 ) {
-            for ( my $i = 0 ; $i < @irreg ; $i++ ) {
-                if ( $irreg[$i] == ( ( $tmpmonth != 9 ) ? ( $tmpmonth + 3 ) % 12 : 12 ) ) {
-                    ### BUFIX Seems to need more Than One ?
-                    ( $year, $month, $day ) = Add_Delta_YM( $year, $month, $day, 0, 6 );
-                    $tmpmonth = ( ( $tmpmonth != 6 ) ? ( $tmpmonth + 6 ) % 12 : 12 );
+            if ($subscription->{'countissuesperunit'} + 1 > $freqdata->{'issuesperunit'}){
+                $subscription->{'countissuesperunit'} = 1;
+                ($year,$month,$day) = Add_Delta_YM($year,$month,$day, $freqdata->{"unitsperissue"},0);
+                unless($freqdata->{'issuesperunit'} == 1) {
+                    # Jumping to the first day of year, because we don't know what day is expected
+                    $month = 1;
+                    $day = 1;
                 }
+            } else {
+                $subscription->{'countissuesperunit'}++;
             }
-            @resultdate = Add_Delta_YM( $year, $month, $day, 0, 6 );
         }
-        if ( $subscription->{periodicity} == 10 ) {
-            @resultdate = Add_Delta_YM( $year, $month, $day, 1, 0 );
-        }
-        if ( $subscription->{periodicity} == 11 ) {
-            @resultdate = Add_Delta_YM( $year, $month, $day, 2, 0 );
+        if ($updatecount){
+            my $dbh = C4::Context->dbh;
+            my $query = qq{
+                UPDATE subscription
+                SET countissuesperunit = ?
+                WHERE subscriptionid = ?
+            };
+            my $sth = $dbh->prepare($query);
+            $sth->execute($subscription->{'countissuesperunit'}, $subscription->{'subscriptionid'});
         }
+        return sprintf("%04d-%02d-%02d", $year, $month, $day);
     }
-    my $resultdate = sprintf( "%04d-%02d-%02d", $resultdate[0], $resultdate[1], $resultdate[2] );
+    else {
+        return $publisheddate;
+    }
+}
 
-    return "$resultdate";
+=head2 _numeration
+
+  $string = &_numeration($value,$num_type,$locale);
+
+_numeration returns the string corresponding to $value in the num_type
+num_type can take :
+    -dayname
+    -monthname
+    -season
+=cut
+
+#'
+
+sub _numeration {
+    my ($value, $num_type, $locale) = @_;
+    $value ||= 0;
+    my $initlocale = setlocale(LC_TIME);
+    if($locale and $locale ne $initlocale) {
+        $locale = setlocale(LC_TIME, $locale);
+    }
+    $locale ||= $initlocale;
+    my $string;
+    $num_type //= '';
+    given ($num_type) {
+        when (/^dayname$/) {
+              $value = $value % 7;
+              $string = POSIX::strftime("%A",0,0,0,0,0,0,$value);
+        }
+        when (/^monthname$/) {
+              $value = $value % 12;
+              $string = POSIX::strftime("%B",0,0,0,1,$value,0,0,0,0);
+        }
+        when (/^season$/) {
+              my $seasonlocale = ($locale)
+                               ? (substr $locale,0,2)
+                               : "en";
+              my %seasons=(
+                 "en" =>
+                    [qw(Spring Summer Fall Winter)],
+                 "fr"=>
+                    [qw(Printemps Été Automne Hiver)],
+              );
+              $value = $value % 4;
+              $string = ($seasons{$seasonlocale})
+                      ? $seasons{$seasonlocale}->[$value]
+                      : $seasons{'en'}->[$value];
+        }
+        default {
+            $string = $value;
+        }
+    }
+    if($locale ne $initlocale) {
+        setlocale(LC_TIME, $initlocale);
+    }
+    return $string;
 }
 
 =head2 is_barcode_in_use
diff --git a/C4/Serials/Frequency.pm b/C4/Serials/Frequency.pm
new file mode 100644 (file)
index 0000000..d5c1cbd
--- /dev/null
@@ -0,0 +1,285 @@
+package C4::Serials::Frequency;
+
+# Copyright 2000-2002 Biblibre SARL
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+
+use C4::Context;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+BEGIN {
+    # set the version for version checking
+    $VERSION = 3.01;
+    require Exporter;
+    @ISA    = qw(Exporter);
+    @EXPORT = qw(
+      &GetSubscriptionFrequencies
+      &GetSubscriptionFrequency
+      &AddSubscriptionFrequency
+      &ModSubscriptionFrequency
+      &DelSubscriptionFrequency
+
+      &GetSubscriptionsWithFrequency
+    );
+}
+
+=head3 GetSubscriptionFrequencies
+
+=over 4
+
+=item C<@frequencies> = &GetSubscriptionFrequencies();
+
+gets frequencies restricted on filters
+
+=back
+
+=cut
+
+sub GetSubscriptionFrequencies {
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        SELECT *
+        FROM subscription_frequencies
+        ORDER BY displayorder
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute();
+
+    my $results = $sth->fetchall_arrayref( {} );
+    return @$results;
+}
+
+=head3 GetSubscriptionFrequency
+
+=over 4
+
+=item $frequency = &GetSubscriptionFrequency($frequencyid);
+
+gets frequency where $frequencyid is the identifier
+
+=back
+
+=cut
+
+sub GetSubscriptionFrequency {
+    my ($frequencyid) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        SELECT *
+        FROM subscription_frequencies
+        WHERE id = ?
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute($frequencyid);
+
+    return $sth->fetchrow_hashref;
+}
+
+=head3 AddSubscriptionFrequency
+
+=over 4
+
+=item C<$frequencyid> = &AddSubscriptionFrequency($frequency);
+
+Add a new frequency
+
+=item C<$frequency> is a hashref that can contains the following keys
+
+=over 2
+
+=item * description
+
+=item * unit
+
+=item * issuesperunit
+
+=item * unitsperissue
+
+=item * expectedissuesayear
+
+=item * displayorder
+
+=back
+
+Only description is mandatory.
+
+=back
+
+=cut
+
+sub AddSubscriptionFrequency {
+    my $frequency = shift;
+
+    unless(ref($frequency) eq 'HASH' && defined $frequency->{'description'} && $frequency->{'description'} ne '') {
+        return undef;
+    }
+
+    my @keys;
+    my @values;
+    foreach (qw/ description unit issuesperunit unitsperissue expectedissuesayear displayorder /) {
+        if(exists $frequency->{$_}) {
+            push @keys, $_;
+            push @values, $frequency->{$_};
+        }
+    }
+
+    my $dbh = C4::Context->dbh;
+    my $query = "INSERT INTO subscription_frequencies";
+    $query .= '(' . join(',', @keys) . ')';
+    $query .= ' VALUES (' . ('?,' x (scalar(@keys)-1)) . '?)';
+    my $sth = $dbh->prepare($query);
+    my $rv = $sth->execute(@values);
+
+    if(defined $rv) {
+        return $dbh->last_insert_id(undef, undef, "subscription_frequencies", undef);
+    }
+
+    return $rv;
+}
+
+=head3 ModSubscriptionFrequency
+
+=over 4
+
+=item &ModSubscriptionFrequency($frequency);
+
+Modifies a frequency
+
+=item C<$frequency> is a hashref that can contains the following keys
+
+=over 2
+
+=item * id
+
+=item * description
+
+=item * unit
+
+=item * issuesperunit
+
+=item * unitsperissue
+
+=item * expectedissuesayear
+
+=item * displayorder
+
+=back
+
+Only id is mandatory.
+
+=back
+
+=cut
+
+sub ModSubscriptionFrequency {
+    my $frequency = shift;
+
+    unless(
+      ref($frequency) eq 'HASH'
+      && defined $frequency->{'id'} && $frequency->{'id'} > 0
+      && (
+        (defined $frequency->{'description'}
+        && $frequency->{'description'} ne '')
+        || !defined $frequency->{'description'}
+      )
+    ) {
+        return undef;
+    }
+
+    my @keys;
+    my @values;
+    foreach (qw/ description unit issuesperunit unitsperissue expectedissuesayear displayorder /) {
+        if(exists $frequency->{$_}) {
+            push @keys, $_;
+            push @values, $frequency->{$_};
+        }
+    }
+
+    my $dbh = C4::Context->dbh;
+    my $query = "UPDATE subscription_frequencies";
+    $query .= ' SET ' . join(' = ?,', @keys) . ' = ?';
+    $query .= ' WHERE id = ?';
+    my $sth = $dbh->prepare($query);
+
+    return $sth->execute(@values, $frequency->{'id'});
+}
+
+=head3 DelSubscriptionFrequency
+
+=over 4
+
+=item &DelSubscriptionFrequency($frequencyid);
+
+Delete a frequency
+
+=back
+
+=cut
+
+sub DelSubscriptionFrequency {
+    my $frequencyid = shift;
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        DELETE FROM subscription_frequencies
+        WHERE id = ?
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute($frequencyid);
+}
+
+=head3 GetSubscriptionsWithFrequency
+
+    my @subs = GetSubscriptionsWithFrequency($frequencyid);
+
+Returns all subscriptions that are using a particular frequency
+
+=cut
+
+sub GetSubscriptionsWithFrequency {
+    my ($frequencyid) = @_;
+
+    return unless $frequencyid;
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        SELECT *
+        FROM subscription
+          LEFT JOIN biblio ON subscription.biblionumber = biblio.biblionumber
+        WHERE periodicity = ?
+    };
+    my $sth = $dbh->prepare($query);
+    my @results;
+    if ($sth->execute($frequencyid)) {
+        @results = @{ $sth->fetchall_arrayref({}) };
+    }
+    return @results;
+}
+
+1;
+
+__END__
+
+=head1 AUTHOR
+
+Koha Developement team <info@koha.org>
+
+=cut
diff --git a/C4/Serials/Numberpattern.pm b/C4/Serials/Numberpattern.pm
new file mode 100644 (file)
index 0000000..4e35803
--- /dev/null
@@ -0,0 +1,294 @@
+package C4::Serials::Numberpattern;
+
+# Copyright 2000-2002 Biblibre SARL
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+
+use C4::Context;
+
+use vars qw($VERSION @ISA @EXPORT);
+
+BEGIN {
+
+    # set the version for version checking
+    $VERSION = 3.01;
+    require Exporter;
+    @ISA    = qw(Exporter);
+    @EXPORT = qw(
+        &GetSubscriptionNumberpatterns
+        &GetSubscriptionNumberpattern
+        &GetSubscriptionNumberpatternByName
+        &AddSubscriptionNumberpattern
+        &ModSubscriptionNumberpattern
+        &DelSubscriptionNumberpattern
+
+        &GetSubscriptionsWithNumberpattern
+    );
+}
+
+=head3 GetSubscriptionNumberpatterns
+
+=over 4
+
+@results = GetSubscriptionNumberpatterns;
+this function get all subscription number patterns entered in table
+
+=back
+
+=cut
+
+sub GetSubscriptionNumberpatterns {
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        SELECT *
+        FROM subscription_numberpatterns
+        ORDER by displayorder
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute;
+    my $results = $sth->fetchall_arrayref({});
+
+    return @$results;
+}
+
+=head3 GetSubscriptionNumberpattern
+
+=over 4
+
+$result = GetSubscriptionNumberpattern($numberpatternid);
+this function get the data of the subscription numberpatterns which id is $numberpatternid
+
+=back
+
+=cut
+
+sub GetSubscriptionNumberpattern {
+    my $numberpatternid = shift;
+    my $dbh = C4::Context->dbh;
+    my $query = qq(
+        SELECT *
+        FROM subscription_numberpatterns
+        WHERE id = ?
+    );
+    my $sth = $dbh->prepare($query);
+    $sth->execute($numberpatternid);
+
+    return $sth->fetchrow_hashref;
+}
+
+=head3 GetSubscriptionNumberpatternByName
+
+=over 4
+
+$result = GetSubscriptionNumberpatternByName($name);
+this function get the data of the subscription numberpatterns which name is $name
+
+=back
+
+=cut
+
+sub GetSubscriptionNumberpatternByName {
+    my $name = shift;
+    my $dbh = C4::Context->dbh;
+    my $query = qq(
+        SELECT *
+        FROM subscription_numberpatterns
+        WHERE label = ?
+    );
+    my $sth = $dbh->prepare($query);
+    my $rv = $sth->execute($name);
+
+    return $sth->fetchrow_hashref;
+}
+
+=head3 AddSubscriptionNumberpattern
+
+=over 4
+
+=item C<$numberpatternid> = &AddSubscriptionNumberpattern($numberpattern)
+
+Add a new numberpattern
+
+=item C<$frequency> is a hashref that contains values of the number pattern
+
+=item Only label and numberingmethod are mandatory
+
+=back
+
+=cut
+
+sub AddSubscriptionNumberpattern {
+    my $numberpattern = shift;
+
+    unless(
+      ref($numberpattern) eq 'HASH'
+      && defined $numberpattern->{'label'}
+      && $numberpattern->{'label'} ne ''
+      && defined $numberpattern->{'numberingmethod'}
+      && $numberpattern->{'numberingmethod'} ne ''
+    ) {
+        return undef;
+    }
+
+    my @keys;
+    my @values;
+    foreach (qw/ label description numberingmethod displayorder
+      label1 label2 label3 add1 add2 add3 every1 every2 every3
+      setto1 setto2 setto3 whenmorethan1 whenmorethan2 whenmorethan3
+      numbering1 numbering2 numbering3 /) {
+        if(exists $numberpattern->{$_}) {
+            push @keys, $_;
+            push @values, $numberpattern->{$_};
+        }
+    }
+
+    my $dbh = C4::Context->dbh;
+    my $query = "INSERT INTO subscription_numberpatterns";
+    $query .= '(' . join(',', @keys) . ')';
+    $query .= ' VALUES (' . ('?,' x (scalar(@keys)-1)) . '?)';
+    my $sth = $dbh->prepare($query);
+    my $rv = $sth->execute(@values);
+
+    if(defined $rv) {
+        return $dbh->last_insert_id(undef, undef, "subscription_numberpatterns", undef);
+    }
+
+    return $rv;
+}
+
+=head3 ModSubscriptionNumberpattern
+
+=over 4
+
+=item &ModSubscriptionNumberpattern($numberpattern)
+
+Modifies a numberpattern
+
+=item C<$frequency> is a hashref that contains values of the number pattern
+
+=item Only id is mandatory
+
+=back
+
+=cut
+
+sub ModSubscriptionNumberpattern {
+    my $numberpattern = shift;
+
+    unless(
+      ref($numberpattern) eq 'HASH'
+      && defined $numberpattern->{'id'}
+      && $numberpattern->{'id'} > 0
+      && (
+        (defined $numberpattern->{'label'}
+        && $numberpattern->{'label'} ne '')
+        || !defined $numberpattern->{'label'}
+      )
+      && (
+        (defined $numberpattern->{'numberingmethod'}
+        && $numberpattern->{'numberingmethod'} ne '')
+        || !defined $numberpattern->{'numberingmethod'}
+      )
+    ) {
+        return undef;
+    }
+
+    my @keys;
+    my @values;
+    foreach (qw/ label description numberingmethod displayorder
+      label1 label2 label3 add1 add2 add3 every1 every2 every3
+      setto1 setto2 setto3 whenmorethan1 whenmorethan2 whenmorethan3
+      numbering1 numbering2 numbering3 /) {
+        if(exists $numberpattern->{$_}) {
+            push @keys, $_;
+            push @values, $numberpattern->{$_};
+        }
+    }
+
+    my $dbh = C4::Context->dbh;
+    my $query = "UPDATE subscription_numberpatterns";
+    $query .= ' SET ' . join(' = ?,', @keys) . ' = ?';
+    $query .= ' WHERE id = ?';
+    my $sth = $dbh->prepare($query);
+
+    return $sth->execute(@values, $numberpattern->{'id'});
+}
+
+=head3 DelSubscriptionNumberpattern
+
+=over 4
+
+=item &DelSubscriptionNumberpattern($numberpatternid)
+
+Delete a number pattern
+
+=back
+
+=cut
+
+sub DelSubscriptionNumberpattern {
+    my $numberpatternid = shift;
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        DELETE FROM subscription_numberpatterns
+        WHERE id = ?
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute($numberpatternid);
+}
+
+=head3 GetSubscriptionsWithNumberpattern
+
+    my @subs = GetSubscriptionsWithNumberpattern($numberpatternid);
+
+Returns all subscriptions that are using a particular numbering pattern
+
+=cut
+
+sub GetSubscriptionsWithNumberpattern {
+    my ($numberpatternid) = @_;
+
+    return unless $numberpatternid;
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        SELECT *
+        FROM subscription
+          LEFT JOIN biblio ON subscription.biblionumber = biblio.biblionumber
+        WHERE numberpattern = ?
+    };
+    my $sth = $dbh->prepare($query);
+    my @results;
+    if ($sth->execute($numberpatternid)) {
+        @results = @{ $sth->fetchall_arrayref({}) };
+    }
+    return @results;
+}
+
+
+1;
+
+__END__
+
+=head1 AUTHOR
+
+Koha Developement team <info@koha.org>
+
+=cut
diff --git a/installer/data/mysql/de-DE/optional/sample_frequencies.sql b/installer/data/mysql/de-DE/optional/sample_frequencies.sql
new file mode 100644 (file)
index 0000000..f09c8a2
--- /dev/null
@@ -0,0 +1,16 @@
+INSERT INTO subscription_frequencies
+    (description, unit, unitsperissue, issuesperunit, displayorder)
+VALUES
+    ('2/day', 'day', 1, 2, 1),
+    ('1/day', 'day', 1, 1, 2),
+    ('3/week', 'week', 1, 3, 3),
+    ('1/week', 'week', 1, 1, 4),
+    ('1/2 weeks', 'week', 2, 1, 5),
+    ('1/3 weeks', 'week', 3, 1, 6),
+    ('1/month', 'month', 1, 1, 7),
+    ('1/2 months', 'month', 2, 1, 8),
+    ('1/3 months', 'month', 3, 1, 9),
+    ('2/year', 'month', 6, 1, 10),
+    ('1/year', 'year', 1, 1, 11),
+    ('1/2 year', 'year', 2, 1, 12),
+    ('Irregular', NULL, 1, 1, 13);
diff --git a/installer/data/mysql/de-DE/optional/sample_frequencies.txt b/installer/data/mysql/de-DE/optional/sample_frequencies.txt
new file mode 100644 (file)
index 0000000..8754f46
--- /dev/null
@@ -0,0 +1 @@
+Sample frequencies for subscriptions
diff --git a/installer/data/mysql/de-DE/optional/sample_numberpatterns.sql b/installer/data/mysql/de-DE/optional/sample_numberpatterns.sql
new file mode 100644 (file)
index 0000000..6b59300
--- /dev/null
@@ -0,0 +1,25 @@
+INSERT INTO subscription_numberpatterns
+    (label, displayorder, description, numberingmethod,
+    label1, add1, every1, whenmorethan1, setto1, numbering1,
+    label2, add2, every2, whenmorethan2, setto2, numbering2,
+    label3, add3, every3, whenmorethan3, setto3, numbering3)
+VALUES
+    ('Number', 1, 'Simple Numbering method', 'No.{X}',
+    'Number', 1, 1, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+    'Volume', 1, 48, 99999, 1, NULL,
+    'Number', 1, 4, 12, 1, NULL,
+    'Issue', 1, 1, 4, 1, NULL),
+
+    ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+    'Volume', 1, 12, 99999, 1, NULL,
+    'Number', 1, 1, 12, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Seasonal', 4, 'Season Year', '{X} {Y}',
+    'Season', 1, 1, 3, 0, 'season',
+    'Year', 1, 4, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/installer/data/mysql/de-DE/optional/sample_numberpatterns.txt b/installer/data/mysql/de-DE/optional/sample_numberpatterns.txt
new file mode 100644 (file)
index 0000000..853db0f
--- /dev/null
@@ -0,0 +1 @@
+Sample numbering patterns for subscriptions
diff --git a/installer/data/mysql/en/optional/sample_frequencies.sql b/installer/data/mysql/en/optional/sample_frequencies.sql
new file mode 100644 (file)
index 0000000..f09c8a2
--- /dev/null
@@ -0,0 +1,16 @@
+INSERT INTO subscription_frequencies
+    (description, unit, unitsperissue, issuesperunit, displayorder)
+VALUES
+    ('2/day', 'day', 1, 2, 1),
+    ('1/day', 'day', 1, 1, 2),
+    ('3/week', 'week', 1, 3, 3),
+    ('1/week', 'week', 1, 1, 4),
+    ('1/2 weeks', 'week', 2, 1, 5),
+    ('1/3 weeks', 'week', 3, 1, 6),
+    ('1/month', 'month', 1, 1, 7),
+    ('1/2 months', 'month', 2, 1, 8),
+    ('1/3 months', 'month', 3, 1, 9),
+    ('2/year', 'month', 6, 1, 10),
+    ('1/year', 'year', 1, 1, 11),
+    ('1/2 year', 'year', 2, 1, 12),
+    ('Irregular', NULL, 1, 1, 13);
diff --git a/installer/data/mysql/en/optional/sample_frequencies.txt b/installer/data/mysql/en/optional/sample_frequencies.txt
new file mode 100644 (file)
index 0000000..8754f46
--- /dev/null
@@ -0,0 +1 @@
+Sample frequencies for subscriptions
diff --git a/installer/data/mysql/en/optional/sample_numberpatterns.sql b/installer/data/mysql/en/optional/sample_numberpatterns.sql
new file mode 100644 (file)
index 0000000..6b59300
--- /dev/null
@@ -0,0 +1,25 @@
+INSERT INTO subscription_numberpatterns
+    (label, displayorder, description, numberingmethod,
+    label1, add1, every1, whenmorethan1, setto1, numbering1,
+    label2, add2, every2, whenmorethan2, setto2, numbering2,
+    label3, add3, every3, whenmorethan3, setto3, numbering3)
+VALUES
+    ('Number', 1, 'Simple Numbering method', 'No.{X}',
+    'Number', 1, 1, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+    'Volume', 1, 48, 99999, 1, NULL,
+    'Number', 1, 4, 12, 1, NULL,
+    'Issue', 1, 1, 4, 1, NULL),
+
+    ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+    'Volume', 1, 12, 99999, 1, NULL,
+    'Number', 1, 1, 12, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Seasonal', 4, 'Season Year', '{X} {Y}',
+    'Season', 1, 1, 3, 0, 'season',
+    'Year', 1, 4, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/installer/data/mysql/en/optional/sample_numberpatterns.txt b/installer/data/mysql/en/optional/sample_numberpatterns.txt
new file mode 100644 (file)
index 0000000..853db0f
--- /dev/null
@@ -0,0 +1 @@
+Sample numbering patterns for subscriptions
diff --git a/installer/data/mysql/es-ES/optional/sample_frequencies.sql b/installer/data/mysql/es-ES/optional/sample_frequencies.sql
new file mode 100644 (file)
index 0000000..f09c8a2
--- /dev/null
@@ -0,0 +1,16 @@
+INSERT INTO subscription_frequencies
+    (description, unit, unitsperissue, issuesperunit, displayorder)
+VALUES
+    ('2/day', 'day', 1, 2, 1),
+    ('1/day', 'day', 1, 1, 2),
+    ('3/week', 'week', 1, 3, 3),
+    ('1/week', 'week', 1, 1, 4),
+    ('1/2 weeks', 'week', 2, 1, 5),
+    ('1/3 weeks', 'week', 3, 1, 6),
+    ('1/month', 'month', 1, 1, 7),
+    ('1/2 months', 'month', 2, 1, 8),
+    ('1/3 months', 'month', 3, 1, 9),
+    ('2/year', 'month', 6, 1, 10),
+    ('1/year', 'year', 1, 1, 11),
+    ('1/2 year', 'year', 2, 1, 12),
+    ('Irregular', NULL, 1, 1, 13);
diff --git a/installer/data/mysql/es-ES/optional/sample_frequencies.txt b/installer/data/mysql/es-ES/optional/sample_frequencies.txt
new file mode 100644 (file)
index 0000000..8754f46
--- /dev/null
@@ -0,0 +1 @@
+Sample frequencies for subscriptions
diff --git a/installer/data/mysql/es-ES/optional/sample_numberpatterns.sql b/installer/data/mysql/es-ES/optional/sample_numberpatterns.sql
new file mode 100644 (file)
index 0000000..6b59300
--- /dev/null
@@ -0,0 +1,25 @@
+INSERT INTO subscription_numberpatterns
+    (label, displayorder, description, numberingmethod,
+    label1, add1, every1, whenmorethan1, setto1, numbering1,
+    label2, add2, every2, whenmorethan2, setto2, numbering2,
+    label3, add3, every3, whenmorethan3, setto3, numbering3)
+VALUES
+    ('Number', 1, 'Simple Numbering method', 'No.{X}',
+    'Number', 1, 1, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+    'Volume', 1, 48, 99999, 1, NULL,
+    'Number', 1, 4, 12, 1, NULL,
+    'Issue', 1, 1, 4, 1, NULL),
+
+    ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+    'Volume', 1, 12, 99999, 1, NULL,
+    'Number', 1, 1, 12, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Seasonal', 4, 'Season Year', '{X} {Y}',
+    'Season', 1, 1, 3, 0, 'season',
+    'Year', 1, 4, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/installer/data/mysql/es-ES/optional/sample_numberpatterns.txt b/installer/data/mysql/es-ES/optional/sample_numberpatterns.txt
new file mode 100644 (file)
index 0000000..853db0f
--- /dev/null
@@ -0,0 +1 @@
+Sample numbering patterns for subscriptions
diff --git a/installer/data/mysql/fr-FR/2-Optionel/sample_frequencies.sql b/installer/data/mysql/fr-FR/2-Optionel/sample_frequencies.sql
new file mode 100644 (file)
index 0000000..f09c8a2
--- /dev/null
@@ -0,0 +1,16 @@
+INSERT INTO subscription_frequencies
+    (description, unit, unitsperissue, issuesperunit, displayorder)
+VALUES
+    ('2/day', 'day', 1, 2, 1),
+    ('1/day', 'day', 1, 1, 2),
+    ('3/week', 'week', 1, 3, 3),
+    ('1/week', 'week', 1, 1, 4),
+    ('1/2 weeks', 'week', 2, 1, 5),
+    ('1/3 weeks', 'week', 3, 1, 6),
+    ('1/month', 'month', 1, 1, 7),
+    ('1/2 months', 'month', 2, 1, 8),
+    ('1/3 months', 'month', 3, 1, 9),
+    ('2/year', 'month', 6, 1, 10),
+    ('1/year', 'year', 1, 1, 11),
+    ('1/2 year', 'year', 2, 1, 12),
+    ('Irregular', NULL, 1, 1, 13);
diff --git a/installer/data/mysql/fr-FR/2-Optionel/sample_frequencies.txt b/installer/data/mysql/fr-FR/2-Optionel/sample_frequencies.txt
new file mode 100644 (file)
index 0000000..8754f46
--- /dev/null
@@ -0,0 +1 @@
+Sample frequencies for subscriptions
diff --git a/installer/data/mysql/fr-FR/2-Optionel/sample_numberpatterns.sql b/installer/data/mysql/fr-FR/2-Optionel/sample_numberpatterns.sql
new file mode 100644 (file)
index 0000000..6b59300
--- /dev/null
@@ -0,0 +1,25 @@
+INSERT INTO subscription_numberpatterns
+    (label, displayorder, description, numberingmethod,
+    label1, add1, every1, whenmorethan1, setto1, numbering1,
+    label2, add2, every2, whenmorethan2, setto2, numbering2,
+    label3, add3, every3, whenmorethan3, setto3, numbering3)
+VALUES
+    ('Number', 1, 'Simple Numbering method', 'No.{X}',
+    'Number', 1, 1, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+    'Volume', 1, 48, 99999, 1, NULL,
+    'Number', 1, 4, 12, 1, NULL,
+    'Issue', 1, 1, 4, 1, NULL),
+
+    ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+    'Volume', 1, 12, 99999, 1, NULL,
+    'Number', 1, 1, 12, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Seasonal', 4, 'Season Year', '{X} {Y}',
+    'Season', 1, 1, 3, 0, 'season',
+    'Year', 1, 4, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/installer/data/mysql/fr-FR/2-Optionel/sample_numberpatterns.txt b/installer/data/mysql/fr-FR/2-Optionel/sample_numberpatterns.txt
new file mode 100644 (file)
index 0000000..853db0f
--- /dev/null
@@ -0,0 +1 @@
+Sample numbering patterns for subscriptions
diff --git a/installer/data/mysql/it-IT/optional/sample_frequencies.sql b/installer/data/mysql/it-IT/optional/sample_frequencies.sql
new file mode 100644 (file)
index 0000000..f09c8a2
--- /dev/null
@@ -0,0 +1,16 @@
+INSERT INTO subscription_frequencies
+    (description, unit, unitsperissue, issuesperunit, displayorder)
+VALUES
+    ('2/day', 'day', 1, 2, 1),
+    ('1/day', 'day', 1, 1, 2),
+    ('3/week', 'week', 1, 3, 3),
+    ('1/week', 'week', 1, 1, 4),
+    ('1/2 weeks', 'week', 2, 1, 5),
+    ('1/3 weeks', 'week', 3, 1, 6),
+    ('1/month', 'month', 1, 1, 7),
+    ('1/2 months', 'month', 2, 1, 8),
+    ('1/3 months', 'month', 3, 1, 9),
+    ('2/year', 'month', 6, 1, 10),
+    ('1/year', 'year', 1, 1, 11),
+    ('1/2 year', 'year', 2, 1, 12),
+    ('Irregular', NULL, 1, 1, 13);
diff --git a/installer/data/mysql/it-IT/optional/sample_frequencies.txt b/installer/data/mysql/it-IT/optional/sample_frequencies.txt
new file mode 100644 (file)
index 0000000..8754f46
--- /dev/null
@@ -0,0 +1 @@
+Sample frequencies for subscriptions
diff --git a/installer/data/mysql/it-IT/optional/sample_numberpatterns.sql b/installer/data/mysql/it-IT/optional/sample_numberpatterns.sql
new file mode 100644 (file)
index 0000000..6b59300
--- /dev/null
@@ -0,0 +1,25 @@
+INSERT INTO subscription_numberpatterns
+    (label, displayorder, description, numberingmethod,
+    label1, add1, every1, whenmorethan1, setto1, numbering1,
+    label2, add2, every2, whenmorethan2, setto2, numbering2,
+    label3, add3, every3, whenmorethan3, setto3, numbering3)
+VALUES
+    ('Number', 1, 'Simple Numbering method', 'No.{X}',
+    'Number', 1, 1, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+    'Volume', 1, 48, 99999, 1, NULL,
+    'Number', 1, 4, 12, 1, NULL,
+    'Issue', 1, 1, 4, 1, NULL),
+
+    ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+    'Volume', 1, 12, 99999, 1, NULL,
+    'Number', 1, 1, 12, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Seasonal', 4, 'Season Year', '{X} {Y}',
+    'Season', 1, 1, 3, 0, 'season',
+    'Year', 1, 4, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/installer/data/mysql/it-IT/optional/sample_numberpatterns.txt b/installer/data/mysql/it-IT/optional/sample_numberpatterns.txt
new file mode 100644 (file)
index 0000000..853db0f
--- /dev/null
@@ -0,0 +1 @@
+Sample numbering patterns for subscriptions
index 0a2d4e4..68a5715 100644 (file)
@@ -1854,6 +1854,53 @@ DROP TABLE IF EXISTS `stopwords`;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
+-- Table structure for table subscription_frequencies
+--
+
+DROP TABLE IF EXISTS subscription_frequencies;
+CREATE TABLE subscription_frequencies (
+    id INTEGER NOT NULL AUTO_INCREMENT,
+    description TEXT NOT NULL,
+    displayorder INT DEFAULT NULL,
+    unit ENUM('day','week','month','year') DEFAULT NULL,
+    unitsperissue INTEGER NOT NULL DEFAULT '1',
+    issuesperunit INTEGER NOT NULL DEFAULT '1',
+    PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table subscription_numberpatterns
+--
+
+DROP TABLE IF EXISTS subscription_numberpatterns;
+CREATE TABLE subscription_numberpatterns (
+    id INTEGER NOT NULL AUTO_INCREMENT,
+    label VARCHAR(255) NOT NULL,
+    displayorder INTEGER DEFAULT NULL,
+    description TEXT NOT NULL,
+    numberingmethod VARCHAR(255) NOT NULL,
+    label1 VARCHAR(255) DEFAULT NULL,
+    add1 INTEGER DEFAULT NULL,
+    every1 INTEGER DEFAULT NULL,
+    whenmorethan1 INTEGER DEFAULT NULL,
+    setto1 INTEGER DEFAULT NULL,
+    numbering1 VARCHAR(255) DEFAULT NULL,
+    label2 VARCHAR(255) DEFAULT NULL,
+    add2 INTEGER DEFAULT NULL,
+    every2 INTEGER DEFAULT NULL,
+    whenmorethan2 INTEGER DEFAULT NULL,
+    setto2 INTEGER DEFAULT NULL,
+    numbering2 VARCHAR(255) DEFAULT NULL,
+    label3 VARCHAR(255) DEFAULT NULL,
+    add3 INTEGER DEFAULT NULL,
+    every3 INTEGER DEFAULT NULL,
+    whenmorethan3 INTEGER DEFAULT NULL,
+    setto3 INTEGER DEFAULT NULL,
+    numbering3 VARCHAR(255) DEFAULT NULL,
+    PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
 -- Table structure for table `subscription`
 --
 
@@ -1870,40 +1917,27 @@ CREATE TABLE `subscription` (
   `monthlength` int(11) default 0,
   `numberlength` int(11) default 0,
   `periodicity` tinyint(4) default 0,
-  `dow` varchar(100) default '',
-  `numberingmethod` varchar(100) default '',
+  countissuesperunit INTEGER NOT NULL DEFAULT 1,
   `notes` mediumtext,
   `status` varchar(100) NOT NULL default '',
-  `add1` int(11) default 0,
-  `every1` int(11) default 0,
-  `whenmorethan1` int(11) default 0,
-  `setto1` int(11) default NULL,
   `lastvalue1` int(11) default NULL,
-  `add2` int(11) default 0,
-  `every2` int(11) default 0,
-  `whenmorethan2` int(11) default 0,
-  `setto2` int(11) default NULL,
-  `lastvalue2` int(11) default NULL,
-  `add3` int(11) default 0,
-  `every3` int(11) default 0,
   `innerloop1` int(11) default 0,
+  `lastvalue2` int(11) default NULL,
   `innerloop2` int(11) default 0,
-  `innerloop3` int(11) default 0,
-  `whenmorethan3` int(11) default 0,
-  `setto3` int(11) default NULL,
   `lastvalue3` int(11) default NULL,
-  `issuesatonce` tinyint(3) NOT NULL default 1,
+  `innerloop3` int(11) default 0,
   `firstacquidate` date default NULL,
   `manualhistory` tinyint(1) NOT NULL default 0,
   `irregularity` text,
+  skip_serialseq BOOLEAN NOT NULL DEFAULT 0,
   `letter` varchar(20) default NULL,
   `numberpattern` tinyint(3) default 0,
+  locale VARCHAR(80) DEFAULT NULL,
   `distributedto` text,
   `internalnotes` longtext,
   `callnumber` text,
   `location` varchar(80) NULL default '',
   `branchcode` varchar(10) NOT NULL default '',
-  `hemisphere` tinyint(3) default 0,
   `lastbranch` varchar(10),
   `serialsadditems` tinyint(1) NOT NULL default '0',
   `staffdisplaycount` VARCHAR(10) NULL,
@@ -1911,7 +1945,9 @@ CREATE TABLE `subscription` (
   `graceperiod` int(11) NOT NULL default '0',
   `enddate` date default NULL,
   `closed` INT(1) NOT NULL DEFAULT 0,
-  PRIMARY KEY  (`subscriptionid`)
+  PRIMARY KEY  (`subscriptionid`),
+  CONSTRAINT subscription_ibfk_1 FOREIGN KEY (periodicity) REFERENCES subscription_frequencies (id) ON DELETE SET NULL ON UPDATE CASCADE,
+  CONSTRAINT subscription_ibfk_2 FOREIGN KEY (numberpattern) REFERENCES subscription_numberpatterns (id) ON DELETE SET NULL ON UPDATE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
diff --git a/installer/data/mysql/nb-NO/2-Valgfritt/sample_frequencies.sql b/installer/data/mysql/nb-NO/2-Valgfritt/sample_frequencies.sql
new file mode 100644 (file)
index 0000000..f09c8a2
--- /dev/null
@@ -0,0 +1,16 @@
+INSERT INTO subscription_frequencies
+    (description, unit, unitsperissue, issuesperunit, displayorder)
+VALUES
+    ('2/day', 'day', 1, 2, 1),
+    ('1/day', 'day', 1, 1, 2),
+    ('3/week', 'week', 1, 3, 3),
+    ('1/week', 'week', 1, 1, 4),
+    ('1/2 weeks', 'week', 2, 1, 5),
+    ('1/3 weeks', 'week', 3, 1, 6),
+    ('1/month', 'month', 1, 1, 7),
+    ('1/2 months', 'month', 2, 1, 8),
+    ('1/3 months', 'month', 3, 1, 9),
+    ('2/year', 'month', 6, 1, 10),
+    ('1/year', 'year', 1, 1, 11),
+    ('1/2 year', 'year', 2, 1, 12),
+    ('Irregular', NULL, 1, 1, 13);
diff --git a/installer/data/mysql/nb-NO/2-Valgfritt/sample_frequencies.txt b/installer/data/mysql/nb-NO/2-Valgfritt/sample_frequencies.txt
new file mode 100644 (file)
index 0000000..8754f46
--- /dev/null
@@ -0,0 +1 @@
+Sample frequencies for subscriptions
diff --git a/installer/data/mysql/nb-NO/2-Valgfritt/sample_numberpatterns.sql b/installer/data/mysql/nb-NO/2-Valgfritt/sample_numberpatterns.sql
new file mode 100644 (file)
index 0000000..6b59300
--- /dev/null
@@ -0,0 +1,25 @@
+INSERT INTO subscription_numberpatterns
+    (label, displayorder, description, numberingmethod,
+    label1, add1, every1, whenmorethan1, setto1, numbering1,
+    label2, add2, every2, whenmorethan2, setto2, numbering2,
+    label3, add3, every3, whenmorethan3, setto3, numbering3)
+VALUES
+    ('Number', 1, 'Simple Numbering method', 'No.{X}',
+    'Number', 1, 1, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+    'Volume', 1, 48, 99999, 1, NULL,
+    'Number', 1, 4, 12, 1, NULL,
+    'Issue', 1, 1, 4, 1, NULL),
+
+    ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+    'Volume', 1, 12, 99999, 1, NULL,
+    'Number', 1, 1, 12, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Seasonal', 4, 'Season Year', '{X} {Y}',
+    'Season', 1, 1, 3, 0, 'season',
+    'Year', 1, 4, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/installer/data/mysql/nb-NO/2-Valgfritt/sample_numberpatterns.txt b/installer/data/mysql/nb-NO/2-Valgfritt/sample_numberpatterns.txt
new file mode 100644 (file)
index 0000000..853db0f
--- /dev/null
@@ -0,0 +1 @@
+Sample numbering patterns for subscriptions
diff --git a/installer/data/mysql/pl-PL/optional/sample_frequencies.sql b/installer/data/mysql/pl-PL/optional/sample_frequencies.sql
new file mode 100644 (file)
index 0000000..f09c8a2
--- /dev/null
@@ -0,0 +1,16 @@
+INSERT INTO subscription_frequencies
+    (description, unit, unitsperissue, issuesperunit, displayorder)
+VALUES
+    ('2/day', 'day', 1, 2, 1),
+    ('1/day', 'day', 1, 1, 2),
+    ('3/week', 'week', 1, 3, 3),
+    ('1/week', 'week', 1, 1, 4),
+    ('1/2 weeks', 'week', 2, 1, 5),
+    ('1/3 weeks', 'week', 3, 1, 6),
+    ('1/month', 'month', 1, 1, 7),
+    ('1/2 months', 'month', 2, 1, 8),
+    ('1/3 months', 'month', 3, 1, 9),
+    ('2/year', 'month', 6, 1, 10),
+    ('1/year', 'year', 1, 1, 11),
+    ('1/2 year', 'year', 2, 1, 12),
+    ('Irregular', NULL, 1, 1, 13);
diff --git a/installer/data/mysql/pl-PL/optional/sample_frequencies.txt b/installer/data/mysql/pl-PL/optional/sample_frequencies.txt
new file mode 100644 (file)
index 0000000..8754f46
--- /dev/null
@@ -0,0 +1 @@
+Sample frequencies for subscriptions
diff --git a/installer/data/mysql/pl-PL/optional/sample_numberpatterns.sql b/installer/data/mysql/pl-PL/optional/sample_numberpatterns.sql
new file mode 100644 (file)
index 0000000..6b59300
--- /dev/null
@@ -0,0 +1,25 @@
+INSERT INTO subscription_numberpatterns
+    (label, displayorder, description, numberingmethod,
+    label1, add1, every1, whenmorethan1, setto1, numbering1,
+    label2, add2, every2, whenmorethan2, setto2, numbering2,
+    label3, add3, every3, whenmorethan3, setto3, numbering3)
+VALUES
+    ('Number', 1, 'Simple Numbering method', 'No.{X}',
+    'Number', 1, 1, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+    'Volume', 1, 48, 99999, 1, NULL,
+    'Number', 1, 4, 12, 1, NULL,
+    'Issue', 1, 1, 4, 1, NULL),
+
+    ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+    'Volume', 1, 12, 99999, 1, NULL,
+    'Number', 1, 1, 12, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Seasonal', 4, 'Season Year', '{X} {Y}',
+    'Season', 1, 1, 3, 0, 'season',
+    'Year', 1, 4, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/installer/data/mysql/pl-PL/optional/sample_numberpatterns.txt b/installer/data/mysql/pl-PL/optional/sample_numberpatterns.txt
new file mode 100644 (file)
index 0000000..853db0f
--- /dev/null
@@ -0,0 +1 @@
+Sample numbering patterns for subscriptions
diff --git a/installer/data/mysql/ru-RU/optional/sample_frequencies.sql b/installer/data/mysql/ru-RU/optional/sample_frequencies.sql
new file mode 100644 (file)
index 0000000..f09c8a2
--- /dev/null
@@ -0,0 +1,16 @@
+INSERT INTO subscription_frequencies
+    (description, unit, unitsperissue, issuesperunit, displayorder)
+VALUES
+    ('2/day', 'day', 1, 2, 1),
+    ('1/day', 'day', 1, 1, 2),
+    ('3/week', 'week', 1, 3, 3),
+    ('1/week', 'week', 1, 1, 4),
+    ('1/2 weeks', 'week', 2, 1, 5),
+    ('1/3 weeks', 'week', 3, 1, 6),
+    ('1/month', 'month', 1, 1, 7),
+    ('1/2 months', 'month', 2, 1, 8),
+    ('1/3 months', 'month', 3, 1, 9),
+    ('2/year', 'month', 6, 1, 10),
+    ('1/year', 'year', 1, 1, 11),
+    ('1/2 year', 'year', 2, 1, 12),
+    ('Irregular', NULL, 1, 1, 13);
diff --git a/installer/data/mysql/ru-RU/optional/sample_frequencies.txt b/installer/data/mysql/ru-RU/optional/sample_frequencies.txt
new file mode 100644 (file)
index 0000000..8754f46
--- /dev/null
@@ -0,0 +1 @@
+Sample frequencies for subscriptions
diff --git a/installer/data/mysql/ru-RU/optional/sample_numberpatterns.sql b/installer/data/mysql/ru-RU/optional/sample_numberpatterns.sql
new file mode 100644 (file)
index 0000000..6b59300
--- /dev/null
@@ -0,0 +1,25 @@
+INSERT INTO subscription_numberpatterns
+    (label, displayorder, description, numberingmethod,
+    label1, add1, every1, whenmorethan1, setto1, numbering1,
+    label2, add2, every2, whenmorethan2, setto2, numbering2,
+    label3, add3, every3, whenmorethan3, setto3, numbering3)
+VALUES
+    ('Number', 1, 'Simple Numbering method', 'No.{X}',
+    'Number', 1, 1, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+    'Volume', 1, 48, 99999, 1, NULL,
+    'Number', 1, 4, 12, 1, NULL,
+    'Issue', 1, 1, 4, 1, NULL),
+
+    ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+    'Volume', 1, 12, 99999, 1, NULL,
+    'Number', 1, 1, 12, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Seasonal', 4, 'Season Year', '{X} {Y}',
+    'Season', 1, 1, 3, 0, 'season',
+    'Year', 1, 4, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/installer/data/mysql/ru-RU/optional/sample_numberpatterns.txt b/installer/data/mysql/ru-RU/optional/sample_numberpatterns.txt
new file mode 100644 (file)
index 0000000..853db0f
--- /dev/null
@@ -0,0 +1 @@
+Sample numbering patterns for subscriptions
diff --git a/installer/data/mysql/uk-UA/optional/sample_frequencies.sql b/installer/data/mysql/uk-UA/optional/sample_frequencies.sql
new file mode 100644 (file)
index 0000000..f09c8a2
--- /dev/null
@@ -0,0 +1,16 @@
+INSERT INTO subscription_frequencies
+    (description, unit, unitsperissue, issuesperunit, displayorder)
+VALUES
+    ('2/day', 'day', 1, 2, 1),
+    ('1/day', 'day', 1, 1, 2),
+    ('3/week', 'week', 1, 3, 3),
+    ('1/week', 'week', 1, 1, 4),
+    ('1/2 weeks', 'week', 2, 1, 5),
+    ('1/3 weeks', 'week', 3, 1, 6),
+    ('1/month', 'month', 1, 1, 7),
+    ('1/2 months', 'month', 2, 1, 8),
+    ('1/3 months', 'month', 3, 1, 9),
+    ('2/year', 'month', 6, 1, 10),
+    ('1/year', 'year', 1, 1, 11),
+    ('1/2 year', 'year', 2, 1, 12),
+    ('Irregular', NULL, 1, 1, 13);
diff --git a/installer/data/mysql/uk-UA/optional/sample_frequencies.txt b/installer/data/mysql/uk-UA/optional/sample_frequencies.txt
new file mode 100644 (file)
index 0000000..8754f46
--- /dev/null
@@ -0,0 +1 @@
+Sample frequencies for subscriptions
diff --git a/installer/data/mysql/uk-UA/optional/sample_numberpatterns.sql b/installer/data/mysql/uk-UA/optional/sample_numberpatterns.sql
new file mode 100644 (file)
index 0000000..6b59300
--- /dev/null
@@ -0,0 +1,25 @@
+INSERT INTO subscription_numberpatterns
+    (label, displayorder, description, numberingmethod,
+    label1, add1, every1, whenmorethan1, setto1, numbering1,
+    label2, add2, every2, whenmorethan2, setto2, numbering2,
+    label3, add3, every3, whenmorethan3, setto3, numbering3)
+VALUES
+    ('Number', 1, 'Simple Numbering method', 'No.{X}',
+    'Number', 1, 1, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+    'Volume', 1, 48, 99999, 1, NULL,
+    'Number', 1, 4, 12, 1, NULL,
+    'Issue', 1, 1, 4, 1, NULL),
+
+    ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+    'Volume', 1, 12, 99999, 1, NULL,
+    'Number', 1, 1, 12, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL),
+
+    ('Seasonal', 4, 'Season Year', '{X} {Y}',
+    'Season', 1, 1, 3, 0, 'season',
+    'Year', 1, 4, 99999, 1, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL);
diff --git a/installer/data/mysql/uk-UA/optional/sample_numberpatterns.txt b/installer/data/mysql/uk-UA/optional/sample_numberpatterns.txt
new file mode 100644 (file)
index 0000000..853db0f
--- /dev/null
@@ -0,0 +1 @@
+Sample numbering patterns for subscriptions
index 4e207a7..76db89e 100755 (executable)
@@ -6723,6 +6723,227 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
     SetVersion ($DBversion);
 }
 
+$DBversion = "3.11.00.XXX";
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(qq|
+        DROP TABLE IF EXISTS subscription_frequencies
+    |);
+    $dbh->do(qq|
+        CREATE TABLE subscription_frequencies (
+            id INTEGER NOT NULL AUTO_INCREMENT,
+            description TEXT NOT NULL,
+            displayorder INT DEFAULT NULL,
+            unit ENUM('day','week','month','year') DEFAULT NULL,
+            unitsperissue INTEGER NOT NULL DEFAULT '1',
+            issuesperunit INTEGER NOT NULL DEFAULT '1',
+            PRIMARY KEY (id)
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8
+    |);
+
+    $dbh->do(qq|
+        DROP TABLE IF EXISTS subscription_numberpatterns
+    |);
+    $dbh->do(qq|
+        CREATE TABLE subscription_numberpatterns (
+            id INTEGER NOT NULL AUTO_INCREMENT,
+            label VARCHAR(255) NOT NULL,
+            displayorder INTEGER DEFAULT NULL,
+            description TEXT NOT NULL,
+            numberingmethod VARCHAR(255) NOT NULL,
+            label1 VARCHAR(255) DEFAULT NULL,
+            add1 INTEGER DEFAULT NULL,
+            every1 INTEGER DEFAULT NULL,
+            whenmorethan1 INTEGER DEFAULT NULL,
+            setto1 INTEGER DEFAULT NULL,
+            numbering1 VARCHAR(255) DEFAULT NULL,
+            label2 VARCHAR(255) DEFAULT NULL,
+            add2 INTEGER DEFAULT NULL,
+            every2 INTEGER DEFAULT NULL,
+            whenmorethan2 INTEGER DEFAULT NULL,
+            setto2 INTEGER DEFAULT NULL,
+            numbering2 VARCHAR(255) DEFAULT NULL,
+            label3 VARCHAR(255) DEFAULT NULL,
+            add3 INTEGER DEFAULT NULL,
+            every3 INTEGER DEFAULT NULL,
+            whenmorethan3 INTEGER DEFAULT NULL,
+            setto3 INTEGER DEFAULT NULL,
+            numbering3 VARCHAR(255) DEFAULT NULL,
+            PRIMARY KEY (id)
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8
+    |);
+
+    $dbh->do(qq|
+        INSERT INTO subscription_frequencies (description, unit, unitsperissue, issuesperunit, displayorder)
+        VALUES
+            ('2/day', 'day', 1, 2, 1),
+            ('1/day', 'day', 1, 1, 2),
+            ('3/week', 'week', 1, 3, 3),
+            ('1/week', 'week', 1, 1, 4),
+            ('1/2 weeks', 'week', 2, 1, 5),
+            ('1/3 weeks', 'week', 3, 1, 6),
+            ('1/month', 'month', 1, 1, 7),
+            ('1/2 months', 'month', 2, 1, 8),
+            ('1/3 months', 'month', 3, 1, 9),
+            ('2/year', 'month', 6, 1, 10),
+            ('1/year', 'year', 1, 1, 11),
+            ('1/2 year', 'year', 2, 1, 12),
+            ('Irregular', NULL, 1, 1, 13)
+    |);
+
+    # Used to link existing subscription to newly created frequencies
+    my $frequencies_mapping = {     # keys are old frequency numbers, values are the new ones
+        1 => 2,     # daily (n/week)
+        2 => 4,     # 1/week
+        3 => 5,     # 1/2 weeks
+        4 => 6,     # 1/3 weeks
+        5 => 7,     # 1/month
+        6 => 8,     # 1/2 months (6/year)
+        7 => 9,     # 1/3 months (1/quarter)
+        8 => 9,    # 1/quarter (seasonal)
+        9 => 10,    # 2/year
+        10 => 11,   # 1/year
+        11 => 12,   # 1/2 years
+        12 => 1,    # 2/day
+        16 => 13,   # Without periodicity
+        32 => 13,   # Irregular
+        48 => 13    # Unknown
+    };
+
+    $dbh->do(qq|
+        INSERT INTO subscription_numberpatterns
+            (label, displayorder, description, numberingmethod,
+            label1, add1, every1, whenmorethan1, setto1, numbering1,
+            label2, add2, every2, whenmorethan2, setto2, numbering2,
+            label3, add3, every3, whenmorethan3, setto3, numbering3)
+        VALUES
+            ('Number', 1, 'Simple Numbering method', 'No.{X}',
+            'Number', 1, 1, 99999, 1, NULL,
+            NULL, NULL, NULL, NULL, NULL, NULL,
+            NULL, NULL, NULL, NULL, NULL, NULL),
+
+            ('Volume, Number, Issue', 2, 'Volume Number Issue 1', 'Vol.{X}, Number {Y}, Issue {Z}',
+            'Volume', 1, 48, 99999, 1, NULL,
+            'Number', 1, 4, 12, 1, NULL,
+            'Issue', 1, 1, 4, 1, NULL),
+
+            ('Volume, Number', 3, 'Volume Number 1', 'Vol {X}, No {Y}',
+            'Volume', 1, 12, 99999, 1, NULL,
+            'Number', 1, 1, 12, 1, NULL,
+            NULL, NULL, NULL, NULL, NULL, NULL),
+
+            ('Seasonal', 4, 'Season Year', '{X} {Y}',
+            'Season', 1, 1, 3, 0, 'season',
+            'Year', 1, 4, 99999, 1, NULL,
+            NULL, NULL, NULL, NULL, NULL, NULL)
+    |);
+
+    $dbh->do(qq|
+        ALTER TABLE subscription
+        MODIFY COLUMN numberpattern INTEGER DEFAULT NULL,
+        MODIFY COLUMN periodicity INTEGER DEFAULT NULL
+    |);
+
+    # Update existing subscriptions
+
+    my $query = qq|
+        SELECT subscriptionid, periodicity, numberingmethod,
+            add1, every1, whenmorethan1, setto1,
+            add2, every2, whenmorethan2, setto2,
+            add3, every3, whenmorethan3, setto3
+        FROM subscription
+        ORDER BY subscriptionid
+    |;
+    my $sth = $dbh->prepare($query);
+    $sth->execute;
+    my $insert_numberpatterns_sth = $dbh->prepare(qq|
+        INSERT INTO subscription_numberpatterns
+             (label, displayorder, description, numberingmethod,
+            label1, add1, every1, whenmorethan1, setto1, numbering1,
+            label2, add2, every2, whenmorethan2, setto2, numbering2,
+            label3, add3, every3, whenmorethan3, setto3, numbering3)
+        VALUES
+            (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+    |);
+    my $check_numberpatterns_sth = $dbh->prepare(qq|
+        SELECT * FROM subscription_numberpatterns
+        WHERE add1 = ? AND add2 = ? AND add3 = ?
+          AND every1 = ? AND every2 = ? AND every3 = ?
+          AND whenmorethan1 = ? AND whenmorethan2 = ? AND whenmorethan3 = ?
+          AND setto1 = ? AND setto2 = ? AND setto3 = ?
+          AND numberingmethod = ?
+        LIMIT 1
+    |);
+    my $update_subscription_sth = $dbh->prepare(qq|
+        UPDATE subscription
+        SET numberpattern = ?,
+            periodicity = ?
+        WHERE subscriptionid = ?
+    |);
+
+    my $i = 1;
+    while(my $sub = $sth->fetchrow_hashref) {
+        $check_numberpatterns_sth->execute(
+            $sub->{add1}, $sub->{add2}, $sub->{add3},
+            $sub->{every1}, $sub->{every2}, $sub->{every3},
+            $sub->{whenmorethan1}, $sub->{whenmorethan2}, $sub->{whenmorethan3},
+            $sub->{setto1}, $sub->{setto2}, $sub->{setto3},
+            $sub->{numberingmethod}
+        );
+        my $p = $check_numberpatterns_sth->fetchrow_hashref;
+        if (defined $p) {
+            # Pattern already exists, link to it
+            $update_subscription_sth->execute($p->{id},
+                $frequencies_mapping->{$sub->{periodicity}},
+                $sub->{subscriptionid});
+        } else {
+            # Create a new numbering pattern for this subscription
+            my $ok = $insert_numberpatterns_sth->execute(
+                "Backup pattern $i", 4+$i, "Automatically created pattern by updatedatabase", $sub->{numberingmethod},
+                "X", $sub->{add1}, $sub->{every1}, $sub->{whenmorethan1}, $sub->{setto1}, undef,
+                "Y", $sub->{add2}, $sub->{every2}, $sub->{whenmorethan2}, $sub->{setto2}, undef,
+                "Z", $sub->{add3}, $sub->{every3}, $sub->{whenmorethan3}, $sub->{setto3}, undef
+            );
+            if($ok) {
+                my $id = $dbh->last_insert_id(undef, undef, 'subscription_numberpatterns', undef);
+                # Link to subscription_numberpatterns and subscription_frequencies
+                $update_subscription_sth->execute($id,
+                    $frequencies_mapping->{$sub->{periodicity}},
+                    $sub->{subscriptionid});
+            }
+            $i++;
+        }
+    }
+
+    # Remove now useless columns
+    $dbh->do(qq|
+        ALTER TABLE subscription
+        DROP COLUMN numberingmethod,
+        DROP COLUMN add1,
+        DROP COLUMN every1,
+        DROP COLUMN whenmorethan1,
+        DROP COLUMN setto1,
+        DROP COLUMN add2,
+        DROP COLUMN every2,
+        DROP COLUMN whenmorethan2,
+        DROP COLUMN setto2,
+        DROP COLUMN add3,
+        DROP COLUMN every3,
+        DROP COLUMN whenmorethan3,
+        DROP COLUMN setto3,
+        DROP COLUMN dow,
+        DROP COLUMN issuesatonce,
+        DROP COLUMN hemisphere,
+        ADD COLUMN countissuesperunit INTEGER NOT NULL DEFAULT 1 AFTER periodicity,
+        ADD COLUMN skip_serialseq BOOLEAN NOT NULL DEFAULT 0 AFTER irregularity,
+        ADD COLUMN locale VARCHAR(80) DEFAULT NULL AFTER numberpattern,
+        ADD CONSTRAINT subscription_ibfk_1 FOREIGN KEY (periodicity) REFERENCES subscription_frequencies (id) ON DELETE SET NULL ON UPDATE CASCADE,
+        ADD CONSTRAINT subscription_ibfk_2 FOREIGN KEY (numberpattern) REFERENCES subscription_numberpatterns (id) ON DELETE SET NULL ON UPDATE CASCADE
+    |);
+
+    print "Upgrade to $DBversion done (Bug 7688: Add subscription_frequencies and subscription_numberpatterns tables)\n";
+    SetVersion($DBversion);
+}
+
 =head1 FUNCTIONS
 
 =head2 TableExists($table)
index 8083192..b6c4b32 100644 (file)
     [% IF ( CAN_user_serials_check_expiration ) %]
        <li><a href="/cgi-bin/koha/serials/checkexpiration.pl">Check expiration</a></li>
     [% END %]
+    <li>
+        <a href="/cgi-bin/koha/serials/subscription-frequencies.pl">
+            Manage frequencies
+        </a>
+    </li>
+    <li>
+        <a href="/cgi-bin/koha/serials/subscription-numberpatterns.pl">
+            Manage numbering patterns
+        </a>
+    </li>
 </ul>
index eeb9262..2bac863 100644 (file)
@@ -118,64 +118,11 @@ $(document).ready(function() {
 </tr>
 [% FOREACH subscription IN subscriptions %]
     [% UNLESS ( loop.odd ) %]<tr class="highlight">[% ELSE %]<tr>[% END %]
-      <td><a href="subscription-detail.pl?subscriptionid=[% subscription.subscriptionid %]"># [% subscription.subscriptionid %]</a> </td>
-      <td>         [% IF ( subscription.periodicity1 ) %]
-                        1/day
-                [% END %]
-                [% IF ( subscription.periodicity2 ) %]
-                        1/week
-                [% END %]
-                [% IF ( subscription.periodicity3 ) %]
-                        1/2 weeks
-                [% END %]
-                [% IF ( subscription.periodicity4 ) %]
-                        1/3 weeks
-                [% END %]
-                [% IF ( subscription.periodicity5 ) %]
-                        1/Month
-                [% END %]
-                [% IF ( subscription.periodicity6 ) %]
-                        1/2 Months (6/year)
-                [% END %]
-                [% IF ( subscription.periodicity7 ) %]
-                        1/quarter
-                [% END %]
-                [% IF ( subscription.periodicity8 ) %]
-                        1/quarter
-                [% END %]
-                [% IF ( subscription.periodicity9 ) %]
-                        2/year
-                [% END %]
-                [% IF ( subscription.periodicity10 ) %]
-                        1/year
-                [% END %]
-                [% IF ( subscription.periodicity11 ) %]
-                        1/2 years
-                [% END %]</td>
-           <td>
-                [% IF ( subscription.numberpattern1 ) %]
-                    Number
-                [% END %]
-                [% IF ( subscription.numberpattern2 ) %]
-                    Volume, number, issue
-                [% END %]
-                [% IF ( subscription.numberpattern3 ) %]
-                    Volume, number
-                [% END %]
-                [% IF ( subscription.numberpattern4 ) %]
-                    Volume, issue
-                [% END %]
-                [% IF ( subscription.numberpattern5 ) %]
-                    Number, issue
-                [% END %]
-                [% IF ( subscription.numberpattern6 ) %]
-                    Seasonal only
-                [% END %]
-                [% IF ( subscription.numberpattern7 ) %]
-                    None of the above
-                [% END %]</td>
-            <td> [% subscription.branchcode %]</td>
-            <td> [% subscription.callnumber %]</td>
+        <td><a href="subscription-detail.pl?subscriptionid=[% subscription.subscriptionid %]"># [% subscription.subscriptionid %]</a> </td>
+        <td>[% subscription.frequency.description %]</td>
+        <td>[% subscription.numberpattern.label %]</td>
+        <td> [% subscription.branchcode %]</td>
+        <td> [% subscription.callnumber %]</td>
         <td> [% subscription.notes %]
             [% UNLESS subscription.closed %]
                 [% IF ( subscription.subscriptionexpired ) %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/showpredictionpattern.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/showpredictionpattern.tt
new file mode 100644 (file)
index 0000000..5a12652
--- /dev/null
@@ -0,0 +1,82 @@
+[% USE KohaDates %]
+
+<h2>Prediction pattern</h1>
+[% IF (not_consistent_end_date) %]
+  <p><em>End date is not consistent with subscription length.</em></p>
+[% END %]
+[% IF (ask_for_irregularities) %]
+    <p><em>Please check issues that are NOT published (irregularities)</em></p>
+    [% IF (daily_options) %]
+        <script type="text/javascript">
+        //<![CDATA[
+        function Check_boxes(dow) {
+            if($(":checkbox[data-dow='"+dow+"']:first").attr("checked") == 'checked') {
+                $("#predictionst :checkbox[data-dow='"+dow+"']").each(function(){
+                    $(this).attr('checked', true);
+                });
+            } else {
+                $("#predictionst :checkbox[data-dow='"+dow+"']").each(function(){
+                    $(this).attr('checked', false);
+                });
+            }
+        }
+        //]]>
+        </script>
+        <p><em>
+            If there is a day (or more) in the week where issues are never
+            published, you can check corresponding boxes below.
+        </em></p>
+        <input type="checkbox" id="monday" data-dow="1" onchange="Check_boxes(1);" />
+        <label for="monday">Monday</label>
+        <input type="checkbox" id="tuesday" data-dow="2" onchange="Check_boxes(2);" />
+        <label for="tuesday">Tuesday</label>
+        <input type="checkbox" id="wednesday" data-dow="3" onchange="Check_boxes(3);" />
+        <label for="wednesday">Wednesday</label>
+        <input type="checkbox" id="thursday" data-dow="4" onchange="Check_boxes(4);" />
+        <label for="thursday">Thursday</label>
+        <input type="checkbox" id="friday" data-dow="5" onchange="Check_boxes(5);" />
+        <label for="friday">Friday</label>
+        <input type="checkbox" id="saturday" data-dow="6" onchange="Check_boxes(6);" />
+        <label for="saturday">Saturday</label>
+        <input type="checkbox" id="sunday" data-dow="7" onchange="Check_boxes(7);" />
+        <label for="sunday">Sunday</label>
+    [% END %]
+[% END %]
+[% IF (predictions_loop) %]
+<table id="predictionst">
+  <thead>
+    <tr>
+      <th>Number</th>
+      <th>Publication Date</th>
+      [% IF (ask_for_irregularities) %]
+      <th>Not published</th>
+      [% END %]
+    </tr>
+  </thead>
+  <tbody>
+    [% FOREACH prediction IN predictions_loop %]
+      <tr>
+        <td>[% prediction.number %]</td>
+        <td>
+          [% IF (prediction.publicationdate) %]
+            [% prediction.publicationdate | $KohaDates %]
+          [% ELSE %]
+            unknown
+          [% END %]
+        </td>
+        [% IF (ask_for_irregularities) %]
+         <td style="text-align:center">
+         [% UNLESS (loop.first) %]
+          [% IF (prediction.not_published) %]
+            <input type="checkbox" name="irregularity" value="[% prediction.issuenumber %]" data-dow="[% prediction.dow %]" checked="checked" />
+          [% ELSE %]
+            <input type="checkbox" name="irregularity" value="[% prediction.issuenumber %]" data-dow="[% prediction.dow %]" />
+          [% END %]
+         </td>
+         [% END %]
+        [% END %]
+      </tr>
+    [% END %]
+  </tbody>
+</table>
+[% END %]
index 35d4187..30e8627 100644 (file)
@@ -1,3 +1,5 @@
+[% USE KohaDates %]
+
 [% INCLUDE 'doc-head-open.inc' %]
 <title>Koha &rsaquo; Serials &rsaquo; [% IF ( modify ) %][% bibliotitle |html %] &rsaquo; Modify subscription[% ELSE %]New subscription[% END %]</title>
 [% INCLUDE 'doc-head-close.inc' %]
@@ -11,953 +13,441 @@ fieldset.rows li.radio { width: 100%; } /* override staff-global.css */
 <script type="text/javascript">
 //<![CDATA[
 
-// 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.
-
-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] };
-    if(d[2].toString().length == 1) { d[2] = '0'+d[2] };
-    [% IF ( dateformat_us ) %]
-        return(d[1] + '/' + d[2] + '/' + d[0]) ;
-    [% ELSIF ( dateformat_metric ) %]
-        return(d[2] + '/' + d[1] + '/' + d[0]) ;
-    [% ELSE %]
-        return(''+d[0] + '-' + d[1] + '-' + d[2]) ;
-    [% END %]    
-}
-
-Date.prototype.addDays = function(days) {
-    this.setDate(this.getDate()+days);
-}
-
-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 jan01 = new Date();
-    jan01.setDate(1);
-    jan01.setMonth(0);
-    jan01.setFullYear(startDate.getFullYear());
-    for(var i=0;i<52;i++) {
-        weeksArray[i] = formatDate(jan01) + ' ' + weekno_label + (i + 1);
-        jan01.addDays( 7 ); 
+var globalnumpatterndata;
+var globalfreqdata;
+var advancedpatternlocked;
+var patternneedtobetested = 0;
+
+function check_issues(){
+    if (globalfreqdata.unit.length >0) {
+        if (document.f.subtype.value == globalfreqdata.unit){
+            document.f.issuelengthcount.value=(document.f.sublength.value*globalfreqdata.issuesperunit)/globalfreqdata.unitsperissue;
+        } else if (document.f.subtype.value != "issues"){
+            alert(_("Frequency and subscription length provided doesn't combine well. Please consider entering an issue count rather than a time period."));
+        }
     }
-    return weeksArray;
 }
 
-function YMDaToYWDa(S) {
-    with (new Date(Date.UTC(S[0], S[1] - 1, S[2]))) {
-        var DoW = getUTCDay();
-        setUTCDate(getUTCDate() - (DoW + 6) % 7 + 3);
-        var ms = valueOf();
-        setUTCMonth(0, 4);
-        var WN = Math.round((ms - valueOf()) / 604800000) + 1;
-        return [getUTCFullYear(), WN, DoW == 0 ? 7 : DoW];
+function addbiblioPopup(biblionumber) {
+    var destination = "/cgi-bin/koha/cataloguing/addbiblio.pl?mode=popup";
+    if(biblionumber){
+        destination += "&biblionumber="+biblionumber;
     }
+    window.open(destination,'AddBiblioPopup','width=1024,height=768,toolbar=no,scrollbars=yes');
 }
-function dayofyear(d) { // d is a Date object
-var yn = d.getFullYear();
-var mn = d.getMonth();
-var dn = d.getDate();
-var d1 = new Date(yn,0,1,12,0,0); // noon on Jan. 1
-var d2 = new Date(yn,mn,dn,12,0,0); // noon on input date
-var ddiff = Math.round((d2-d1)/864e5);
-return ddiff+1;
-}
-
 
-// create irregularity object.
-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"));
-    // create weeks irregularity selection array:
-    this.firstissue = new Date();
-    this.firstissue.setDate(1);
-    this.firstissue.setMonth(0);
-    [% IF ( firstacquiyear ) %] // it's a mod, we already have a start date.
-        this.firstissue.setFullYear( [% firstacquiyear %] );
-    [% END %]
-       this.weeks = getWeeksArray(this.firstissue); 
-
-    this.numskipped = 0;
-    // init:
-       var irregular = '[% irregularity %]';
-    this.skipped = irregular.split(',');
+function Plugin(f)
+{
+    window.open('subscription-bib-search.pl','FindABibIndex','width=800,height=400,toolbar=no,scrollbars=yes');
 }
 
-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 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) {
-            //$("#irregularity_select option:selected").each(...); //jquery can combine both conditionals and the for loop
-            for( var i in document.f.irregularity_select.options ) {
-                if( document.f.irregularity_select.options[i].selected ) {
-                    this.skipped[cnt] = document.f.irregularity_select.options[i].value ;
-                    summary_str += document.f.irregularity_select.options[i].text + "\n" ;
-                                   cnt++;
-                                   this.numskipped++;
-                           }
-                   }
-                   var summary = document.getElementById("irregularity_summary");
-                   if(summary) {
-                           summary.value = summary_str;
-                           summary.rows= ( cnt > 6 ) ? cnt : 6 ; // textarea will bre resized, but not more than 6 lines will show.
-                   }
-        }
+function FindAcqui(f)
+{
+    window.open('acqui-search.pl','FindASupplier','width=800,height=400,toolbar=no,scrollbars=yes');
 }
 
-IrregularPattern.prototype.irregular = function(index) { 
-       for( var i in this.skipped) {
-                       if( this.skipped[i] == index) {
-                               return true;
-                       }
-       }
-       return false;
+function Find_ISSN(f)
+{
+    window.open('issn-search.pl','FindABibIndex','width=800,height=400,toolbar=no,scrollbars=yes');
 }
 
-function init_pattern() {
-       irregular_issues = new IrregularPattern();
-}
-function reset_pattern() {
-       document.getElementById("numberpattern").value = '';
-    document.getElementById("irregularity").innerHTML = '';
-       init_pattern();
-       reset_num_pattern();
+function Clear(id) {
+    $("#"+id).val('');
 }
 
-// common pre defined number patterns
-function reset_num_pattern() {
-var patternchoice = document.getElementById("numberpattern").value;
-    switch(patternchoice){
-    case "2":
-        document.f.add1.value=1;
-        document.f.add2.value=1;
-        document.f.add3.value=1;
-        document.f.every1.value=12;
-        document.f.every2.value=1;
-        document.f.every3.value=1;
-        document.f.whenmorethan1.value=9999999;
-        document.f.whenmorethan2.value=12;
-        document.f.whenmorethan3.value=4;
-        document.f.setto1.value=0;
-        document.f.setto2.value=1;
-        document.f.setto3.value=1;
-        document.f.lastvalue1.value=1;
-        document.f.lastvalue2.value=1;
-        document.f.lastvalue3.value=1;
-        document.f.numberingmethod.value=_("Vol {X}, No {Y}, Issue {Z}");
-        moreoptions(text[1],text[0],text[2]);
-        display_table(0); // toggle info box on (1) or off (0)
-        break;
-    case "3":
-        document.f.add1.value=1;
-        document.f.add2.value=1;
-        document.f.add3.value='';
-        document.f.every1.value=12;
-        document.f.every2.value=1;
-        document.f.every3.value='';
-        document.f.whenmorethan1.value=9999999;
-        document.f.whenmorethan2.value=12;
-        document.f.whenmorethan3.value='';
-        document.f.setto1.value=0;
-        document.f.setto2.value=1;
-        document.f.setto3.value='';
-        document.f.lastvalue1.value=1;
-        document.f.lastvalue2.value=1;
-        document.f.lastvalue3.value='';
-        document.f.numberingmethod.value=_("Vol {X}, No {Y}");
-        moreoptions(text[1],text[0]);
-        display_table(0);
-        break;
-    case "4":
-        document.f.add1.value=1;
-        document.f.add2.value=1;
-        document.f.add3.value='';
-        document.f.every1.value=12;
-        document.f.every2.value=1;
-        document.f.every3.value='';
-        document.f.whenmorethan1.value=9999999;
-        document.f.whenmorethan2.value=12;
-        document.f.whenmorethan3.value='';
-        document.f.setto1.value=0;
-        document.f.setto2.value=1;
-        document.f.setto3.value='';
-        document.f.lastvalue1.value=1;
-        document.f.lastvalue2.value=1;
-        document.f.lastvalue3.value='';
-        document.f.numberingmethod.value=_("Vol {X}, Issue {Y}");
-        moreoptions(text[1],text[2]);
-        display_table(0);
-        break;
-    case "5":
-//        var d = new Date(document.f.firstacquidate.value);
-//        var smonth = d.getMonth();
-        document.f.add1.value=1;
-        document.f.add2.value=1;
-        document.f.add3.value='';
-        document.f.every1.value=12;
-        document.f.every2.value=1;
-        document.f.every3.value='';
-        document.f.whenmorethan1.value=9999999;
-        document.f.whenmorethan2.value=12;
-        document.f.whenmorethan3.value='';
-        document.f.setto1.value=0;
-        document.f.setto2.value=1;
-        document.f.setto3.value='';
-        document.f.numberingmethod.value=_("No {X}, Issue {Y}");
-        moreoptions(text[0],text[2]);
-        display_table(0);
-        break;
-    case "6":
-        var d = new Date(document.f.firstacquidate.value);
-        var sYear = d.getFullYear();
-        moreoptions_seasons(text[15],sYear);
-        var d = new Date(document.f.firstacquidate.value);
-        var sYear = d.getFullYear();
-        document.f.add1.value=1;
-        document.f.add2.value='1';
-        document.f.add3.value='';
-        document.f.every1.value=4;
-        document.f.every2.value='1';
-        document.f.every3.value='';
-        document.f.whenmorethan1.value=9999999;
-        document.f.whenmorethan2.value='4';
-        document.f.whenmorethan3.value='';
-        document.f.setto1.value=0;
-        document.f.setto2.value='1';
-        document.f.setto3.value='';
-        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;
-    case "7":
-        display_table(1);
-        document.getElementById("more_options").innerHTML = '';
-        document.f.irreg_check.value=1; 
-        break;
-    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;
-        document.f.add3.value='';
-        document.f.every1.value=12;
-        document.f.every2.value=1;
-        document.f.every3.value='';
-        document.f.whenmorethan1.value=9999999;
-        document.f.whenmorethan2.value=12;
-        document.f.whenmorethan3.value='';
-        document.f.setto1.value=0;
-        document.f.setto2.value=1;
-        document.f.setto3.value='';
-        document.f.lastvalue1.value=sYear;
-          switch (document.f.periodicity.value){
-            case 1:              
-              var doy = dayofyear(d);
-              document.f.lastvalue2.value=doy; 
-              document.f.whenmorethan2.value=365; 
-              break;      
-            case 12:     
-              var doy = dayofyear(d);
-              document.f.lastvalue2.value=doy*2; 
-              document.f.whenmorethan2.value=730; 
-              break;      
-            case 2:
-            case 3:
-            case 4:
-              var YWDa = YMDaToYWDa(d);
-              document.f.lastvalue2.value=YWDA[1]/(document.f.periodicity.value-1); 
-              break;      
-            case 5:
-              var smonth = d.getMonth();
-              document.f.lastvalue2.value=smonth;
-              break;      
-            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.lastvalue3.value='';
-        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:
-        document.f.add1.value=1;
-        document.f.add2.value='';
-        document.f.add3.value='';
-        document.f.every1.value=1;
-        document.f.every2.value='';
-        document.f.every3.value='';
-        document.f.whenmorethan1.value=9999999;
-        document.f.whenmorethan2.value='';
-        document.f.whenmorethan3.value='';
-        document.f.setto1.value=0;
-        document.f.setto2.value='';
-        document.f.setto3.value='';
-        document.f.lastvalue1.value=1;
-        document.f.lastvalue2.value='';
-        document.f.lastvalue3.value='';
-        document.f.numberingmethod.value='{X}';
-//        moreoptions_daily_check(text[0]);
-        moreoptions(text[0]);
-        document.f.irreg_check.value=1;
-        display_table(0);
-        break;
+function Check_page1() {
+    if ( $("#aqbooksellerid").val().length == 0) {
+        input_box = confirm(_("If you wish to claim late or missing issues you must link this subscription to a vendor. Click OK to ignore or Cancel to return and enter a vendor"));
+        if (input_box==false) {
+            return false;
+        }
+    }
+    if ($("#biblionumber").val().length == 0) {
+        alert(_("You must choose or create a biblio"));
+        return false;
     }
-}
 
-function display_table(n) {
-    if(n==1){
-        document.getElementById("basetable").style.display = 'block';
-    } else if(n==0){
-        document.getElementById("basetable").style.display = 'none';
-    } else {
-               var disp_val = ( document.getElementById("basetable").style.display == 'none' ) ? 'block' : 'none' ;
-                       document.getElementById("basetable").style.display = disp_val;
-       }
+    return true;
 }
 
-function set_num_pattern_from_template_vars() {
-       if(!document.getElementById("numberpattern")){ return false; }
-    document.getElementById("numberpattern").value = '[% numberpattern %]';
-    reset_num_pattern();
-    
-    document.f.add1.value='[% add1 %]';
-    document.f.add2.value='[% add2 %]';
-    document.f.add3.value='[% add3 %]';
-    document.f.every1.value='[% every1 %]';
-    document.f.every2.value='[% every2 %]';
-    document.f.every3.value='[% every3 %]';
-    document.f.whenmorethan1.value='[% whenmorethan1 %]';
-    document.f.whenmorethan2.value='[% whenmorethan2 %]';
-    document.f.whenmorethan3.value='[% whenmorethan3 %]';
-    document.f.setto1.value='[% setto1 %]';
-    document.f.setto2.value='[% setto2 %]';
-    document.f.setto3.value='[% setto3 %]';
-    document.f.lastvalue1.value='[% lastvalue1 %]';
-    document.f.lastvalue2.value='[% lastvalue2 %]';
-    document.f.lastvalue3.value='[% lastvalue3 %]';
-    document.f.numberingmethod.value='[% numberingmethod %]';
-
-    var more_strY;
-    var more_strZ;
-    [% IF ( add2 ) %]
-    if([% add2 %] > 0){
-        more_strY="Y";
-    }
+function Check_page2(){
+    [% UNLESS (more_than_one_serial) %]
+      if($("#acqui_date").val().length == 0){
+          alert(_("You must choose a first publication date"));
+          return false;
+      }
     [% END %]
-    [% IF ( add3 ) %]
-    if([% add3 %] > 0){
-        more_strZ="Z";
+    if($("#frequency").val().length == 0){
+        alert(_("You must choose a frequency"));
+        return false;
     }
-    [% END %]
-    document.f.lastvalue1temp.value='[% lastvalue1 %]';
-    if(more_strY){
-        document.f.lastvalue2temp.value='[% lastvalue2 %]';
-    document.f.whenmorethan2temp.value='[% whenmorethan2 %]';
+    if($("input[name='startdate']").val().length == 0){
+        alert(_("You must choose a start date"));
+        return false;
     }
-    if(more_strZ){
-        document.f.lastvalue3temp.value='[% lastvalue3 %]';
-    document.f.whenmorethan3temp.value='[% whenmorethan3 %]';
+    if($("#sublength").val().length == 0 && $("input[name='enddate']").val().length == 0){
+        alert(_("You must choose a subscription length or an end date."));
+        return false;
     }
-}
-
-// a pre check with more options to see if 'number' and '1/day' are chosen
-function moreoptions_daily_check(x) {
-    var periodicity = document.f.periodicity.value;
-    var errortext='';
-    if(periodicity == 1){ // i.e. daily
-        document.getElementById("irregularity").innerHTML = '';
-        errortext =_("Please indicate which days of the week you DO NOT expect to receive issues.")+"<br \/>";
-        for(var j=0;j<irregular_issues.daynames.length;j++){
-            errortext +="<input type='checkbox' name='irregular' id='irregular"+(j+1)+"' value='"+(j+1)+"' />"+irregular_issues.daynames[j]+" &nbsp; ";
-        }
-        var error = errortext;
-        moreoptions(x);
-        document.getElementById("irregularity").innerHTML = error;
-    } else {
-        document.getElementById("irregularity").innerHTML = '';
-        document.getElementById("more_options").innerHTML = '';
-        moreoptions(x);
+    if($("#numberpattern").val().length == 0){
+        alert(_("You must choose a numbering pattern"));
+        return false;
     }
-}
-
-// to dispaly the more options section
-function moreoptions(x,y,z){
-document.getElementById("irregularity").innerHTML = '';
-document.getElementById("more_options").innerHTML = '';
-var textbox = '';
-    // alert("X: "+x+"Y: "+y+"Z: "+z);
-    if(x){
-        textbox +="<table id='irregularity_table'>\n<tr><th>&nbsp;<\/th><th>"+x+"<\/th>";
-        if(y){
-            textbox +="<th>"+y+"<\/th>";
-            if(z){
-                textbox +="<th>"+z+"<\/th>";
-            }
-        }
-        textbox +="<\/tr>\n";
-        textbox +="<tr><th scope=\"row\">"+text[5]+"<\/td><td><input type='text' name='lastvalue1temp' id='lastvalue1temp' size='4' onkeyup='moreoptionsupdate(this)' value=\"" + document.f.lastvalue1.value +  "\" /><\/td>\n";
-        if(y){
-            textbox +="<td><input type=\"text\" name=\"lastvalue2temp\" id=\"lastvalue2temp\" size=\"4\" onkeyup=\"moreoptionsupdate(this)\" value=\"" + document.f.lastvalue2.value + "\" /><\/td>\n";
-            if(z){
-                textbox +="<td><input type=\"text\" name=\"lastvalue3temp\" id=\"lastvalue3temp\" size=\"4\" onkeyup=\"moreoptionsupdate(this)\" value=\"" + document.f.lastvalue3.value + "\" /><\/td>\n";
-            }
-        }
-        textbox +="<\/tr>\n";
-        if(y){
-            textbox +="<tr><th scope=\"row\">"+text[6]+"<\/th>";
-            textbox +="<td>&nbsp;<\/td>\n";
-            textbox +="<td><input type=\"text\" name=\"whenmorethan2temp\" id=\"whenmorethan2temp\" size=\"4\" onkeyup=\"moreoptionsupdate(this,1)\"><\/td>\n";
-            if(z){
-                textbox +="<td><input type=\"text\" name=\"whenmorethan3temp\" id=\"whenmorethan3temp\" size=\"4\" onkeyup=\"moreoptionsupdate(this,1)\"><\/td>\n";
-            }
-            textbox +="<\/tr>";
-        } else {
-          textbox +="<tr> <td>"+_("issues expected")+"<\/td><td><input type=\"text\" name=\"issuesexpected1temp\" id=\"issuesexpected1temp\" size=\"4\" onkeyup=\"moreoptionsupdate(this,0)\" value=\"" + document.f.issuesexpected1.value + "\" ><\/td><\/tr>";
-        }
-        textbox +="<\/table>\n";
+    if(advancedpatternlocked == 0){
+        alert(_("You have modified the advanced prediction pattern. Please save your work or cancel modifications."));
+        return false;
     }
-    document.getElementById("more_options").innerHTML = textbox;
-}
-
-function hemispheres(chosen){
-var selbox = document.getElementById("season1");
-    if(selbox){
-    var selboxselected = selbox.options[selbox.selectedIndex].value;
-    selbox.options.length = 0;
-
-    if ( (chosen == "1") || ( ! (chosen) && is_hemisphere == 1 )) {
-        selbox.options[selbox.options.length] = new Option(text[11],'1');
-        selbox.options[selbox.options.length] = new Option(text[12],'2');
-        selbox.options[selbox.options.length] = new Option(text[13],'3');
-        selbox.options[selbox.options.length] = new Option(text[14],'4');
-        is_hemisphere = 1;
-        selbox.options[selboxselected-1].selected = true;
+    if(patternneedtobetested){
+        alert(_("Please click on 'Test prediction pattern' before saving subscription."));
+        return false;
     }
 
-    if ( (chosen == "2") || ( ! (chosen) && is_hemisphere == 2 )) {
-        selbox.options[selbox.options.length] = new Option(text[13],'1');
-        selbox.options[selbox.options.length] = new Option(text[10],'2');
-        selbox.options[selbox.options.length] = new Option(text[11],'3');
-        selbox.options[selbox.options.length] = new Option(text[12],'4');
-        is_hemisphere = 2;
-        selbox.options[selboxselected-1].selected = true;
-    }
-    }
+    return true;
 }
 
-// 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 = '';
-    //alert("X: "+x+"Year: "+y);
-    if(x){
-        var hemi_select = parseInt('[% hemisphere %]');
-        textbox +="<li><label for=\"hemisphere\">"+ text[7]  +"<\/label><select name=\"hemisphere\" id=\"hemisphere\" onchange=\"hemispheres(this.options[this.selectedIndex].value)\">";
-        for(var i = 1; i <= 2; i++){
-            textbox +="<option value='"+i+"'";
-            if(i == hemi_select){
-                textbox += " selected "
+function frequencyload(){
+    $.getJSON("subscription-frequency.pl",{"frequency_id":document.f.frequency.value,ajax:'true'},
+        function(freqdata){
+            globalfreqdata=freqdata;
+            if ( globalfreqdata.unit.length == 0 ) {
+                var option = $("#subtype option[value='issues']");
+                $(option).attr('selected', 'selected');
+                $("#subtype option[value!='issues']").attr('disabled', 'disabled')
+            } else {
+                $("#subtype option").attr('disabled', false)
             }
-            textbox +=">"+text[i+7]+"<\/option>";
-        }
-        textbox +="<\/li>\n";
-        textbox +="<table id=\"seasonal_irregularity\"><tr><th>&nbsp;<\/th><th>"+x+"<\/th>";
-        textbox +="<th>"+text[16]+"<\/th>";
-        textbox +="<\/tr>\n";
-        textbox +="<tr><th scope=\"row\">"+text[5]+"<\/th><td><select name=\"lastvalue2temp\" id=\"lastvalue2temp\" id=\"season1\" onchange=\"moreoptionsupdate(this)\">";
-        for(var j = 1; j <= 4; j++){
-            textbox +="<option value='"+j+"'>"+text[j+9]+"<\/option>";
         }
-        textbox +="<\/select><\/td>";
-        var isyr = irregular_issues.firstissue;
-        textbox += "<td>" + irregular_issues.firstissue.getFullYear() + "<\/td><\/tr>\n";
-        textbox +="<tr><th scope=\"row\">"+text[6]+"<\/th>";
-        textbox +="<td><input type=\"text\" name=\"whenmorethan2temp\" id=\"whenmorethan2temp\" size=\"4\" onkeyup=\"moreoptionsupdate(this,1)\"><\/td>\n";
-        textbox +="<\/tr><\/table>\n";
-    }
-    document.getElementById("more_options").innerHTML = textbox;
+    )
 }
 
-function irregularity_check(){
-    document.f.irreg_check.value = 1; // Irregularity button now pushed
-    var periodicity = document.f.periodicity.value;
-       var rollover = document.f.issuesexpected1.value;
-    if( (document.f.whenmorethan2) && ( document.f.whenmorethan2.value > 0) ){
-      rollover = document.f.whenmorethan2.value;
-    }
-    if((document.f.whenmorethan3) && document.f.whenmorethan3.value > 0 ){
-        // FIXME: Irregularity check assumes that the full prediction pattern repeats each year.
-               //  In cases where the outermost periodicity is > 1 year,  
-               //  e.g. where a volume spans two years, the irregularity check will be incorrect, 
-        // but you can safely ignore the check, submit the form, and the prediction pattern should be correct.
-               //  a way to distinguish between these two cases is needed.
-               rollover = document.f.whenmorethan3.value * document.f.whenmorethan2.value;
-    }
-    var error='';
-    var toobig;
-    var expected; 
-    var errortext = "<b>"+_("Warning irregularity detected")+"</b><br \/>";
-    switch(periodicity){
-    case "12":
-        if(rollover < 730) expected =730;
-        if(rollover > 730) {
-            expectedover=730;
-            toobig=1;
-        }
-        break;
-    case "1":
-        if(rollover < 365) expected =365;
-        if(rollover > 365) {
-            expectedover=365;
-            toobig=1;
-        }
-        break;
-    case "2":
-        if(rollover < 52) expected =52;
-        if(rollover > 52){
-            expectedover=52;
-            toobig=1;
-        }
-        break;
-    case "3":
-        if(rollover < 26) expected =26;
-        if(rollover > 26){
-            expectedover=26;
-            toobig=1;
-        }
-        break;
-    case "4":
-        if(rollover < 17) expected =17;
-        if(rollover > 17){
-            expectedover=17;
-            toobig=1;
-        }
-        break;
-    case "5":
-        if(rollover < 12) expected =12;
-        if(rollover > 12){
-            expectedover=12;
-            toobig=1;
-        }
-        break;
-    case "6":
-        if(rollover < 6) expected =6;
-        if(rollover > 6){
-            expectedover=6;
-            toobig=1;
-        }
-        break;
-    case "7":
-        if(rollover < 4) expected =4;
-        if(rollover > 4){
-            expectedover=4;
-            toobig=1;
-        }
-        break;
-    case "8":
-        if(rollover < 4) expected =4;
-        if(rollover > 4){
-            expectedover=4;
-            toobig=1;
-        }
-        break;
-    case "9":
-        if(rollover < 2) expected =2;
-        if(rollover > 2){
-            expectedover=2;
-            toobig=1;
-        }
-        break;
-    case "10":
-        if(rollover < 1) expected =1;
-        if(rollover > 1){
-            expectedover=1;
-            toobig=1;
+function numberpatternload(){
+    $.getJSON("subscription-numberpattern.pl",{"numberpattern_id":document.f.numbering_pattern.value,ajax:'true'},
+        function(numpatterndata){
+            globalnumpatterndata=numpatterndata;
+            if (globalnumpatterndata==undefined){
+                return false;
+            }
+            displaymoreoptions();
+            restoreAdvancedPattern();
         }
-        break;
-    default:
-        break;
-    }
-    if(expected){
-        if(expected == 365 || expected==730){  // what about leap years ?
-                       // FIXME:  We interpret irregularity as which days per week for periodicity==1.
-                       //  We need two cases: one in which we're published n days/week, in which case irregularity should be per week,
-                       //  and a regular daily pub, where irregularity should be per year.
-            errortext += _("Please indicate which days of the week you DO NOT expect to receive issues.")+"<br \/>";
-        } else {
-            errortext +=expected+_(" issues expected, ")+rollover+_(" were entered.")+"<br \/>"+_("Please indicate which date(s) an issue is not expected")+"<br \/>";
-            irregular_issues.numskipped = expected - rollover;
-               }
-        errortext +="<select multiple id=\"irregularity_select\" name=\"irregularity_select\" onchange=\"irregular_issues.update();\">\n";
-               errortext +=irregular_options(periodicity);
-               errortext += "<\/select>\n <textarea rows=\"6\" width=\"18\" id=\"irregularity_summary\" name=\"irregularity_summary\" value=\"foo\"><\/textarea>";
-        error=errortext;
-    }
-    if(toobig){
-        errortext +=expectedover+_(" issues expected, ")+rollover+_(" were entered")+"<p class=\"warning\">"+_("You seem to have indicated more issues per year than expected.<\/p>");
-        error=errortext;
-    }
-    if(error.length ==0){
-        error=_("No irregularities noticed");
-    }
-       display_example(expected);
-    document.getElementById("irregularity").innerHTML = error;
-       irregular_issues.update();
+    );
 }
 
-function irregular_options(periodicity){
-    var titles;
-    var count;
-    var errortext='';
-    var numberpattern = document.getElementById('numberpattern').value;
-    if(periodicity == 1) {
-        expected = 7;
-        titles = irregular_issues.daynames;
-        count = 1;
+function displaymoreoptions() {
+    if(globalnumpatterndata == undefined){
+        $("#moreoptionst").hide();
+        return false;
     }
-    if(periodicity == 2 || periodicity == 3 || periodicity == 4) { 
-        titles = irregular_issues.weeks;
-               count = 1;
-        if(periodicity==3) {  // 1/2 wks
-            expected = 26;
-        } else if(periodicity == 4) { // 1/3 wks
-            expected = 17;
+
+    var X = 0, Y = 0, Z = 0;
+    var numberingmethod = unescape(globalnumpatterndata.numberingmethod);
+    if(numberingmethod.match(/{X}/)) X = 1;
+    if(numberingmethod.match(/{Y}/)) Y = 1;
+    if(numberingmethod.match(/{Z}/)) Z = 1;
+
+    if(X || Y || Z) {
+        $("#moreoptionst").show();
+    } else {
+        $("#moreoptionst").hide();
+    }
+
+    if(X) {
+        if(globalnumpatterndata.label1) {
+            $("#headerX").html(unescape(globalnumpatterndata.label1));
         } else {
-            expected = 52;
+            $("#headerX").html("X");
         }
+        $("#headerX").show();
+        $("#beginsX").show();
+        $("#innerX").show();
+    } else {
+        $("#headerX").hide();
+        $("#beginsX").hide();
+        $("#innerX").hide();
+        $("#lastvaluetemp1").val('');
+        $("#innerlooptemp1").val('');
     }
-    if(periodicity == 5 || periodicity == 6 || periodicity == 7 || periodicity == 8 || periodicity == 9) {
-        if(periodicity == 8 && numberpattern==8) {
-            is_season = 1; // setting up from edit page
-        } 
-        if(is_season){
-            titles = irregular_issues.seasons;
-            expected = 4;
-            if(is_hemisphere == 2){
-                count = 2;
-            } else {
-                count = 1;
-            }
+    if(Y) {
+        if(globalnumpatterndata.label2) {
+            $("#headerY").html(unescape(globalnumpatterndata.label2));
         } else {
-            titles = irregular_issues.months;
-            expected = 12;
-            count = 1;
+            $("#headerY").html("Y");
         }
+        $("#headerY").show();
+        $("#beginsY").show();
+        $("#innerY").show();
+    } else {
+        $("#headerY").hide();
+        $("#beginsY").hide();
+        $("#innerY").hide();
+        $("#lastvaluetemp2").val('');
+        $("#innerlooptemp2").val('');
     }
-       if( !expected) {
-               return '';   // don't know how to deal with irregularity.
-       }       
-    for(var j=0;j<expected;j++){   // rch - changed frrom (1..expected).
-        if(isArray(titles)){
-            if(count>expected){
-                count = count-expected;
-            }
-            if(is_season && is_hemisphere == 1){
-                errortext +="<option value='"+((count*3)-2)+"'>"+titles[j]+"<\/option>\n";
-// alert("value: "+((count*3)-2)+" title: "+titles[j]);
-            } else if(is_season && is_hemisphere == 2){
-                errortext +="<option value='"+((count*3)-2)+"'>"+titles[j-1]+"<\/option>\n";
-// alert("value: "+((count*3)-2)+" title: "+titles[j-1]);
-            } else {  // all non-seasonal periodicities:
-                var incr=1; // multiplier for ( 1/n weeks)  patterns; in this case the irreg calc relies on the week# , not the issue#.
-                if(periodicity==3) {  // 1/2 wks
-                    incr=2;
-                } else if(periodicity == 4) { // 1/3 wks
-                    incr=3;
-                }
-                errortext += "<option value='" + (1+j*incr) ;  
-                               if(irregular_issues.irregular(1+incr*j)) {
-                                       errortext += "' selected='selected" ;
-                               }
-                               errortext += "'>"+titles[incr*j]+"<\/option>\n";
-            }
-            count++;
-        } else { 
-            errortext +="<option value='"+j+"'>"+titles+" "+j+"<\/option>\n";
+    if(Z) {
+        if(globalnumpatterndata.label3) {
+            $("#headerZ").html(unescape(globalnumpatterndata.label3));
+        } else {
+            $("#headerZ").html("Z");
         }
+        $("#headerZ").show();
+        $("#beginsZ").show();
+        $("#innerZ").show();
+    } else {
+        $("#headerZ").hide();
+        $("#beginsZ").hide();
+        $("#innerZ").hide();
+        $("#lastvaluetemp3").val('');
+        $("#innerlooptemp3").val('');
     }
-    return errortext;
 }
 
+function toggleAdvancedPattern() {
+    $("#advancedpredictionpattern").toggle();
+}
 
-function display_example(expected){
-    var startfrom1 = parseInt(document.f.lastvalue1.value);
-    var startfrom2 = parseInt(document.f.lastvalue2.value);
-    var startfrom3 = parseInt(document.f.lastvalue3.value);
-    var every1 = parseInt(document.f.every1.value);
-    var every2 = parseInt(document.f.every2.value);
-    var every3 = parseInt(document.f.every3.value);
-    var numberpattern = document.f.numberingmethod.value;
-    var whenmorethan2 = parseInt(document.f.whenmorethan2.value);
-    var whenmorethan3 = parseInt(document.f.whenmorethan3.value);
-    var setto2 = parseInt(document.f.setto2.value);
-    var setto3 = parseInt(document.f.setto3.value);
-    var displaytext = _("Based on the information entered, the Numbering Pattern will look like this: ") + "<br \/><ul class=\"numpattern_preview\">";
-    if(startfrom3>0){
-        var count=startfrom3-1;
-        var count2=startfrom2;
-        for(var i = 0 ; i < 12; i++){
-            if(count>=whenmorethan3){
-                count=setto3;
-                if(count2>=whenmorethan2){
-                    startfrom1++;
-                    count2=setto2;
-                } else {
-                    count2++;
-                }
-            } else {
-                count++;
-            }
-            displaytext += '<li>' + numberpattern.replace(/{Z}/,count) + '<\/li>\n';
-            displaytext = displaytext.replace(/{Y}/,count2);
-            displaytext = displaytext.replace(/{X}/,startfrom1);
+function modifyAdvancedPattern() {
+    $("#patternname").attr("readonly", false).val('');
+    $("#numberingmethod").attr("readonly", false);
 
-        }
-    }
-    if(startfrom2>0 && !startfrom3){
-        var count=startfrom2-1;
-        for(var i=0;i<12;i++){
-            if(count>=whenmorethan2){
-                startfrom1++;
-                count=setto2;
-            } else {
-                count++;
-            }
+    $("#advancedpredictionpatternt input").each(function() {
+        $(this).attr("readonly", false);
+    });
+    $("#advancedpredictionpatternt select").each(function() {
+        $(this).attr("disabled", false);
+    });
 
-            if(is_season){
-                if(is_hemisphere == 2){
-                    if(count == 1) {
-                        displaytext += numberpattern.replace(/{Y}/,text[count+12])+'\n';
-                    } else {
-                        displaytext += numberpattern.replace(/{Y}/,text[count+8])+'\n';
-                    }
-                } else {
-                displaytext += numberpattern.replace(/{Y}/,text[count+10])+'\n';
-                }
-            } else {
-                displaytext += numberpattern.replace(/{Y}/,count)+'\n';
-            }
-            displaytext = displaytext.replace(/{X}/,startfrom1)+'<br \/>\n';
+    $("#restoreadvancedpatternbutton").show();
+    $("#saveadvancedpatternbutton").show();
+    $("#modifyadvancedpatternbutton").hide();
+
+    advancedpatternlocked = 0;
+}
+
+function restoreAdvancedPattern() {
+    $("#patternname").attr("readonly", true).val(unescape(globalnumpatterndata.label));
+    $("#numberingmethod").attr("readonly", true).val(unescape(globalnumpatterndata.numberingmethod));
+
+    $("#advancedpredictionpatternt input").each(function() {
+        $(this).attr("readonly", true);
+        var id = $(this).attr('id');
+        if(id.match(/lastvalue/) || id.match(/innerloop/)) {
+            var tempid = id.replace(/(\d)/, "temp$1");
+            $(this).val($("#"+tempid).val());
+        } else {
+            $(this).val(unescape(globalnumpatterndata[id]));
         }
+    });
+    $("#advancedpredictionpatternt select").each(function() {
+        $(this).attr("disabled", true);
+        var id = $(this).attr('id');
+        $(this).val(unescape(globalnumpatterndata[id]));
+    });
+
+    $("#restoreadvancedpatternbutton").hide();
+    $("#saveadvancedpatternbutton").hide();
+    $("#modifyadvancedpatternbutton").show();
+
+    advancedpatternlocked = 1;
+}
+
+function testPredictionPattern() {
+    var frequencyid = $("#frequency").val();
+    var acquidate;
+    var error = 0;
+    var error_msg = "";
+    if(frequencyid == undefined || frequencyid == ""){
+        error_msg += _("- Frequency is not defined\n");
+        error ++;
     }
-    if(startfrom1>0 && !startfrom2 && !startfrom3){
-        var offset=eval(document.f.issuesexpected1.value);
-        if (!offset){
-            offset = 12 
-        }
-        for(var i=startfrom1;i<(startfrom1+offset);i+=every1){
-            displaytext += numberpattern.replace(/{X}/,i)+'<br \/>\n';
-        }
+    acquidate = $("#acqui_date").val();
+    if(acquidate == undefined || acquidate == ""){
+        error_msg += _("- First publication date is not defined\n");
+        error ++;
     }
-   //  displaytext = "<div style='padding: 5px; background-color: #CCCCCC'>"+displaytext+"<\/div>";
-    document.getElementById("displayexample").innerHTML = displaytext;
-}
+    [% IF (more_than_one_serial) %]
+      var nextacquidate = $("#nextacquidate").val();
+      if(nextacquidate == undefined || nextacquidate == ""){
+        error_msg += _("- Next issue publication date is not defined\n");
+        error ++;
+      }
+    [% END %]
 
-function isArray(obj) {
-if (obj.constructor.toString().indexOf("Array") == -1)
-    return false;
-else
-    return true;
-}
+    if(error){
+        alert(_("Cannot test prediction pattern for the following reason(s):\n\n")
+            + error_msg);
+        return false;
+    }
 
-function moreoptionsupdate(inputfield,rollover){
-    fieldname = inputfield.name;
-    // find parent element in base table by stripping 'temp' from element name.
-    basefield = document.getElementById(fieldname.slice(0,-4));
-    var fieldnumber = fieldname.slice(-5,-4);
+    var custompattern = 0;
+    if(advancedpatternlocked == 0) {
+        custompattern = 1;
+    }
 
-    basefield.value = inputfield.value;
-    var patternchoice = document.getElementById("numberpattern").value;
-    switch(patternchoice){
-    case "2":
-    case "4":
-    case "5":
-    case "8": // Year, Number.  -- Why not just use Vol, Number withvol==year??
-                //  FIXME: this my conflict with innerloop calc below.
-       if (document.f.lastvalue2temp.value > 0){document.f.innerloop1.value = document.f.lastvalue2temp.value - 1;}
-      break;   
-    }  
-    if(basefield.name.slice(0,-1) == 'lastvalue' || 'whenmorethan' ) {
-        // The enumeration string is held in a positional numeral notation with three positions, X,Y,Z.
-        // The last values lastvalue1, lastvalue2,lastvalue3 should match the last received serial's X,Y,Z enumeration.
-        // make array indexes start with 1 for consistency with variable names.
-        var innerloop = new Array( undefined, document.getElementById('innerloop1'), document.getElementById('innerloop2'), document.getElementById('innerloop3') );
-        var lastvalue = new Array( undefined, document.getElementById('lastvalue1').value *1 , document.getElementById('lastvalue2').value *1 , document.getElementById('lastvalue3').value *1  );
-        var every = new Array( undefined, document.getElementById('every1').value *1 , document.getElementById('every2').value *1 , document.getElementById('every3').value *1  );
-        var add = new Array( undefined, document.getElementById('add1').value *1 , document.getElementById('add2').value *1 , document.getElementById('add3').value *1  );
-        var whenmorethan = new Array( undefined, document.getElementById('whenmorethan1').value *1 , document.getElementById('whenmorethan2').value *1 , document.getElementById('whenmorethan3').value *1  );
-        
-       if(rollover){
-       // calculate rollover  for higher level of periodicity.
-       // if there are two levels of periodicity, (e.g. vol{X},num{Y},issue{Z}, then every1=every2*whenmorethan2 / add2 .
-          for(var N=3;N>1;N--){
-            if( add[N] > 0){
-                var addN = (add[N]) ? add[N] : 1 ;
-                var everyN = (document.getElementById('every'+N)) ? document.getElementById('every'+N).value : 1 ;
-                document.getElementById('every'+(N-1)).value = whenmorethan[N] * everyN / addN ;
-            }
-          }
-        }
-        innerloop[3].value = ( every[3] > 1 ) ? lastvalue[3] % every[3] : 0 ;
-        innerloop[2].value = ( every[2] > 1 ) ? lastvalue[3] - 1 : 0 ;
-        innerloop[1].value = ( every[1] > 1 ) ? 
-                                    ( whenmorethan[3] > 0 ) ?  (lastvalue[2] - 1) * every[2] + 1* innerloop[2].value 
-                                                            : lastvalue[2] - 1
-                                               : 0 ;
+    var ajaxData = {
+        'custompattern': custompattern,
+        [% IF (subscriptionid) %]
+            'subscriptionid': [% subscriptionid %],
+        [% END %]
+        [% IF (more_than_one_serial) %]
+          'nextacquidate': nextacquidate,
+        [% END %]
+        'firstacquidate': acquidate
+    };
+    var ajaxParams = [
+        'to', 'subtype', 'sublength', 'frequency', 'numberingmethod',
+        'lastvalue1', 'lastvalue2', 'lastvalue3', 'add1', 'add2', 'add3',
+        'every1', 'every2', 'every3', 'innerloop1', 'innerloop2', 'innerloop3',
+        'setto1', 'setto2', 'setto3', 'numbering1', 'numbering2', 'numbering3',
+        'whenmorethan1', 'whenmorethan2', 'whenmorethan3', 'locale'
+    ];
+    for(i in ajaxParams) {
+        var param = ajaxParams[i];
+        var value = $("#"+param).val();
+        if(value.length > 0)
+            ajaxData[param] = value;
     }
-     //FIXME : add checks for innerloop || lastvalue .gt. rollover  
+
+    $.ajax({
+        url:"/cgi-bin/koha/serials/showpredictionpattern.pl",
+        data: ajaxData,
+        success: function(data) {
+            $("#displayexample").html(data);
+            patternneedtobetested = 0;
+        }
+    });
 }
 
+function saveAdvancedPattern() {
+    if ($("#patternname").val().length == 0) {
+        alert(_("Please enter a name for this pattern"));
+        return false;
+    }
 
-function check_input(e){
-    var unicode=e.charCode? e.charCode : e.keyCode
-    if (unicode!=8 && unicode !=46 && unicode!=9 && unicode !=13){ // if key isn't backspace or delete
-        if (unicode<48||unicode>57) { // if not a number
-            alert(_("Needs to be entered in digit form -eg 10"));
-            return false // disable key press
+    // Check if patternname already exists, and modify pattern
+    // instead of creating it if so
+    var found = 0;
+    $("#numberpattern option").each(function(){
+        if($(this).text() == $("#patternname").val()){
+            found = 1;
+            return false;
         }
+    });
+    var cnfrm = 1;
+    if(found){
+        var msg = _("This pattern name already exists. Do you want to modify it?")
+            + "\n" + _("Warning: it will modify the pattern for all subscriptions")
+            + _("that are using it.");
+        cnfrm = confirm(msg);
     }
-}
 
-function addbiblioPopup(biblionumber) {
-       var destination = "/cgi-bin/koha/cataloguing/addbiblio.pl?mode=popup";
-       if(biblionumber){ destination += "&biblionumber="+biblionumber; }
- window.open(destination,'AddBiblioPopup','width=1024,height=768,toolbar=no,scrollbars=yes');
-}
+    if(cnfrm) {
+        var ajaxData = {};
+        var ajaxParams = [
+            'patternname', 'numberingmethod', 'label1', 'label2', 'label3',
+            'add1', 'add2', 'add3', 'every1', 'every2', 'every3',
+            'setto1', 'setto2', 'setto3', 'numbering1', 'numbering2', 'numbering3',
+            'whenmorethan1', 'whenmorethan2', 'whenmorethan3', 'locale'
+        ];
+        for(i in ajaxParams) {
+            var param = ajaxParams[i];
+            var value = $("#"+param).val();
+            if(value.length > 0)
+                ajaxData[param] = value;
+        }
 
-function Plugin(f)
-{
-        window.open('subscription-bib-search.pl','FindABibIndex','width=800,height=400,toolbar=no,scrollbars=yes');
+        $.getJSON(
+            "/cgi-bin/koha/serials/create-numberpattern.pl",
+            ajaxData,
+            function(data){
+                if (data.numberpatternid) {
+                    if(found == 0){
+                        $("#numberpattern").append("<option value=\""+data.numberpatternid+"\">"+$("#patternname").val()+"</option>");
+                    }
+                    $("#numberpattern").val(data.numberpatternid);
+                    numberpatternload();
+                } else {
+                    alert(_("Something went wrong. Unable to create a new numbering pattern."));
+                }
+            }
+        );
+    }
 }
 
-function FindAcqui(f)
-{
-        window.open('acqui-search.pl','FindASupplier','width=800,height=400,toolbar=no,scrollbars=yes');
+function show_page_1() {
+    $("#page_1").show();
+    $("#page_2").hide();
+    $("#page_number").text("1/2");
 }
 
-function Find_ISSN(f)
-{
-        window.open('issn-search.pl','FindABibIndex','width=800,height=400,toolbar=no,scrollbars=yes');
+function show_page_2() {
+    $("#page_1").hide();
+    $("#page_2").show();
+    $("#page_number").text("2/2");
+    displaymoreoptions();
 }
 
 
-function Check(f) {
-    if (f.aqbooksellerid.value.length==0) {
-        input_box = confirm(_("If you wish to claim late or missing issues you must link this subscription to a vendor. Click OK to ignore or Cancel to return and enter a vendor"));
-               if (input_box==true) {
-               }
-               else {
-                       return false;
-               }
-    }
-       if (f.biblionumber.value.length==0) {
-        alert(_("You must choose or create a biblio"));
-    } else if(f.startdate.value.length != 0 && f.sublength.value > 0) {
-        if (f.irreg_check.value == 1) {
-            document.f.submit();
-        } else {
-            if(f.numbering_pattern.value == ''){
-                alert(_("Please choose a numbering pattern"));
-            } else {
-                alert(_("Please check for irregularity by clicking 'Test Prediction Pattern'"));
-            }
-        }
-    } else {
-        alert(_("You must choose a start date and a subscription length"));
-    }
-       if(irregular_issues.numskipped < irregular_issues.skipped.length ) {
-               alert(_("You have not accounted for all missing issues."));
-       }
-    return false;
-}
-
 $(document).ready(function() {
-    init_pattern();
-    // http://jqueryui.com/demos/datepicker/#date-range
-    var dates = $( "#histstartdate, #histenddate" ).datepicker({
-        changeMonth: true,
-        numberOfMonths: 1,
-        onSelect: function( selectedDate ) {
-            var option = this.id == "histstartdate" ? "minDate" : "maxDate",
-                instance = $( this ).data( "datepicker" );
-                date = $.datepicker.parseDate(
-                    instance.settings.dateFormat ||
-                    $.datepicker._defaults.dateFormat,
-                    selectedDate, instance.settings );
-            dates.not( this ).datepicker( "option", option, date );
-        }
+    $("select#frequency").change(function(){
+        patternneedtobetested = 1;
+        $("input[name='enddate']").val('');
+        frequencyload();
+    });
+    $("select#numberpattern").change(function(){
+        patternneedtobetested = 1;
+        numberpatternload();
+    });
+    $("#subtype").change(function(){
+        $("input[name='enddate']").val('');
+    });
+    $("#sublength").change(function(){
+        $("input[name='enddate']").val('');
+    });
+    $("#lastvaluetemp1").keyup(function(){
+        $("#lastvalue1").val($(this).val());
+    });
+    $("#lastvaluetemp2").keyup(function(){
+        $("#lastvalue2").val($(this).val());
+    });
+    $("#lastvaluetemp3").keyup(function(){
+        $("#lastvalue3").val($(this).val());
+    });
+    $("#lastvalue1").keyup(function(){
+        $("#lastvaluetemp1").val($(this).val());
+    });
+    $("#lastvalue2").keyup(function(){
+        $("#lastvaluetemp2").val($(this).val());
+    });
+    $("#lastvalue3").keyup(function(){
+        $("#lastvaluetemp3").val($(this).val());
     });
 
-    [% IF ( manualhistory ) %] $("#subscription_form_history").show();[% END %]
-       $("#cancel_manual_history").click(function(){
-               $("#subscription_form_history").hide();
-        $("#manuallist").removeAttr("checked");
-       });
-       $("#manuallist").click( function(){
-               if($(this).attr("checked")){
-                       $("#subscription_form_history").show();
-               } else {
-                       $("#subscription_form_history").hide();
-               }
-       }
-       );
-   //  $(".widelabel").attr("width", "300px");  // labels stay skinny in IE7 anyway.
-[% IF ( modify ) %]
-    set_num_pattern_from_template_vars();
-    [% IF ( hemisphere ) %]
-       is_hemisphere = [% hemisphere %] ;
-    hemispheres();
-    [% END %]
-[% END %]
-[% IF ( irregularity ) %]
-    irregularity_check();
-[% END %]
-    $('#numberpattern').change( function() { 
-        reset_num_pattern(); 
+    $("#innerlooptemp1").keyup(function(){
+        $("#innerloop1").val($(this).val());
+    });
+    $("#innerlooptemp2").keyup(function(){
+        $("#innerloop2").val($(this).val());
+    });
+    $("#innerlooptemp3").keyup(function(){
+        $("#innerloop3").val($(this).val());
+    });
+    $("#innerloop1").keyup(function(){
+        $("#innerlooptemp1").val($(this).val());
+    });
+    $("#innerloop2").keyup(function(){
+        $("#innerlooptemp2").val($(this).val());
+    });
+    $("#innerloop3").keyup(function(){
+        $("#innerlooptemp3").val($(this).val());
     });
 
+    if($("#frequency").val() != ""){
+        frequencyload();
+    }
+    if($("#numberpattern").val() != ""){
+        numberpatternload();
+    }
+
     var node;
     [% FOREACH field IN dont_export_field_loop %]
         node = $("#[% field.fieldid %]");
@@ -967,6 +457,8 @@ $(document).ready(function() {
             $(node).find("option:first").attr('selected','selected');
         }
     [% END %]
+
+    show_page_1();
 });
 //]]>
 </script>
@@ -978,415 +470,369 @@ $(document).ready(function() {
 <div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/serials/serials-home.pl">Serials</a> &rsaquo; [% IF ( modify ) %]<a href="/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=[% subscriptionid %]"><i>[% bibliotitle |html %]</i></a> &rsaquo; Modify subscription[% ELSE %]New subscription[% END %]</div>
 
 <div id="doc3" class="yui-t7">
-   
-   <div id="bd">
-<h1>[% IF ( modify ) %] Modify subscription for <i>[% bibliotitle |html %]</i>[% ELSE %]Add a new subscription[% END %]</h1>
-   <div class="yui-g">
-    <form method="post" name="f" action="/cgi-bin/koha/serials/subscription-add.pl">
-[% IF ( modify ) %]
-        <input type="hidden" name="op" value="modsubscription" />
-        <input type="hidden" name="subscriptionid" value="[% subscriptionid %]" />
-[% ELSE %]
-        <input type="hidden" name="op" value="addsubscription" />
-[% END %]
-<input type="hidden" name="user" value="[% loggedinusername %]" />
-<input type="hidden" name="irreg_check" value="0" />
-<input type="hidden" name="issuesexpected1" id="issuesexpected1" value="0" />
-
-       <div class="yui-u first">
-    <fieldset id="subscription_add_information" class="rows">
-       <legend>Subscription details</legend>
-       <ol>
-           [% IF ( subscriptionid ) %]
-        <li><span class="label">Subscription #</span> [% subscriptionid %]</li>
-        [% END %]
-        <li>
-            <label for="aqbooksellerid">Vendor: </label>
-            <input type="text" name="aqbooksellerid" id="aqbooksellerid" value="[% aqbooksellerid %]" size="8" /> (<input type="text" name="aqbooksellername" value="[% aqbooksellername %]" disabled="disabled" readonly="readonly" />) <a href="#" onclick="FindAcqui(f)">Search for a vendor</a>
-        </li>
-        <li>
-            <label for="biblionumber" class="required" title="Subscriptions must be associated with a bibliographic record">Biblio:</label>
-            
-                <input type="text" name="biblionumber" id="biblionumber" value="[% bibnum %]" size="8" /> 
-                (<input type="text" name="title" value="[% bibliotitle %]" disabled="disabled" readonly="readonly" />) <span class="required" title="Subscriptions must be associated with a bibliographic record">Required</span>
-               <div class="inputnote"> <a href="#" onclick="Plugin(f)">Search for Biblio</a>
-                   [% IF ( CAN_user_editcatalogue ) %] 
-                      [% IF ( modify ) %]
-                      | <a href="#" onclick="addbiblioPopup([% bibnum %]); return false;">Edit biblio</a>
-                      [% ELSE %]
-                      | <a href="#" onclick="addbiblioPopup(); return false;">Create Biblio</a>
-                      [% END %]
-                   [% END %]
-              </div>
-            
-        </li>
-        <li class="radio">
-            [% IF ( serialsadditems ) %]
-                <p><input type="radio" id="serialsadditems-yes" name="serialsadditems" value="1" checked="checked" /><label class="widelabel" for="serialsadditems-yes">create an item record when receiving this serial</label></p>
-                <p><input type="radio" id="serialsadditems-no" name="serialsadditems" value="0" /><label class="widelabel" for="serialsadditems-no">do not create an item record when receiving this serial </label></p>
-            [% ELSE %]
-                <p><input type="radio" id="serialsadditems-yes" name="serialsadditems" value="1"/><label class="widelabel" for="serialsadditems-yes">create an item record when receiving this serial</label></p>
-                <p><input type="radio" id="serialsadditems-no" name="serialsadditems" value="0" checked="checked" /><label class="widelabel" for="serialsadditems-no">do not create an item record when receiving this serial</label></p>
-            [% END %]
-        </li>
-        <li>
-            <label for="branchcode">Library:</label>
-            
-                <select name="branchcode" id="branchcode" style="width: 20em;">
-                    [% UNLESS ( Independantbranches ) %]<option value="">None</option>[% END %]
-                    [% FOREACH branchloo IN branchloop %][% IF ( branchloo.selected ) %]<option value="[% branchloo.value %]" selected="selected">[% branchloo.branchname %]</option>
-                               [% ELSE %]
-                               <option value="[% branchloo.value %]">[% branchloo.branchname %]</option>
-                               [% END %]
-                    [% END %]
-                </select> (select a library)
-            
-        </li>
-        <li>
-            <label for="location">Location:</label>
-            <select name="location" id="location">
-                <option value="">None</option>
-                [% FOREACH locations_loo IN locations_loop %][% IF ( locations_loo.selected ) %]<option value="[% locations_loo.authorised_value %]" selected="selected">[% locations_loo.lib %]</option>[% ELSE %]<option value="[% locations_loo.authorised_value %]">[% locations_loo.lib %]</option>[% END %][% END %]
-            </select>
-        </li>
-         <li>
-            <label for="callnumber">Call number:</label>
-            <input type="text" name="callnumber" id="callnumber" value="[% callnumber %]" size="20" />
-        </li>
-        <li>
-            <label for="graceperiod">Grace period:</label> <input type="text" name="graceperiod" id="graceperiod" value="[% graceperiod %]" size="5"/> day(s)
-        </li>
-        <li>
-            <label for="notes">OPAC note:</label>
-            <textarea name="notes" id="notes" cols="30" rows="2">[% notes %]</textarea>
-        </li>
-        <li>
-            <label for="internalnotes">Nonpublic note:</label>
-            <textarea name="internalnotes" id="internalnotes" cols="30" rows="2">[% internalnotes %]</textarea>
-        </li>
-        <li>
-            
-               [% IF ( letterloop ) %]
-            <label for="letter">Patron notification: </label>
-                          <select name="letter" id="letter">
-                    <option value="">None</option>
-                [% FOREACH letterloo IN letterloop %]
-                               [% IF ( letterloo.selected ) %]
-                    <option value="[% letterloo.value %]" selected="selected">[% letterloo.lettername %]</option>
-[% ELSE %]
-                    <option value="[% letterloo.value %]">[% letterloo.lettername %]</option>
-[% END %]
-                [% END %]
-                </select> 
-                <div class="hint">Select a notice and subscribers will be notified when new issues are received.</div>
-               [% ELSE %]
-            <span class="label">Patron notification: </span>
-                               <div class="hint">To notify patrons of new serial issues, you must <a href="/cgi-bin/koha/tools/letter.pl">define a notice</a>.</div>
-                               [% END %]
-        </li>
-               <li>
-                        <label class="widelabel" for="staffdisplaycount">Number of issues to display to staff: </label>
-                        <input type="text" name="staffdisplaycount" id="staffdisplaycount" value="[% staffdisplaycount %]" size="4"/>
-                </li>
-                <li>
-            <label class="widelabel" for="opacdisplaycount">Number of issues to display in OPAC: </label>
-                       <input type="text" name="opacdisplaycount" id="opacdisplaycount" value="[% opacdisplaycount %]" size="4"/>
-               </li>
-       </ol>
-       </fieldset>
-       </div>
-       
-<div class="yui-u">
-<div id="subscription_form_history" style="display:none"><h3 style="display:inline">Subscription history</h3> <a href="#" id="cancel_manual_history">[cancel manual history]</a>
-        <p>Hint: you can update the serial history manually. This can be useful for an old subscription or to clean the existing history. Modify these fields with care, as future serial receive will continue to update them automatically.</p>
-        <fieldset class="rows">
-            <ol>
-                <li>
-                <label for="histstartdate">Subscription start date</label>
-                <input type="text" name="histstartdate" id="histstartdate" value="[% histstartdate %]" /><div class="hint"> (start date of the 1st subscription)</div>
-                </li>
-                <li>
-                <label for="histenddate">Subscription end date</label>
-                <input type="text" name="histenddate" id="histenddate" value="[% histenddate %]" /> <div class="hint">(if empty, subscription is still active)</div>
-                </li>
-                <li>
-                <label for="recievedlist">Received issues</label>
-                <textarea name="recievedlist" id="recievedlist" cols="60" rows="5">[% recievedlist %]</textarea>
-                </li>
-                <li>
-                <label for="missinglist">Missing issues</label>
-                <textarea name="missinglist" id="missinglist" cols="60" rows="5">[% missinglist %]</textarea>
-                </li>
-                <li>
-                <label for="opacnote">Note for OPAC</label>
-                <textarea name="opacnote" id="opacnote" cols="60" rows="5">[% opacnote %]</textarea>
-                </li>
-                <li>
-                <label for="librariannote">Note for staff</label>
-                <textarea name="librariannote" id="librariannote" cols="60" rows="5">[% librariannote %]</textarea>
-                </li>
-            </ol>
-        </fieldset>
-    <fieldset class="action"><input type="submit" value="Save subscription history"  /></fieldset>
-</div>
-
-<div id="subscription_form_planning">
-       <fieldset class="rows">
-       <legend>Serials planning</legend>
-    <ol>
-        <li>
-           <label for="acqui_date"> First issue publication date:</label>
-                [% IF ( modify ) %]<input type="text" name="firstacquidate" value="[% firstacquidate %]"  size="13" maxlength="10" id="acqui_date" disabled="disabled" />
-                [% ELSE %]<input type="text" name="firstacquidate" value="[% firstacquidate %]"  size="13" maxlength="10" id="acqui_date" class="datepicker" />[% END %]
-        </li>
-           [% IF ( modify ) %]<li><label for="next_acqui_date"> Next issue publication date:</label>
-                <input type="text" name="nextacquidate" value="[% nextacquidate %]" size="13" maxlength="10" id="next_acqui_date" class="datepicker" />
-                </li>[% END %]
-                
-        <li>
-            <label for="periodicity" class="required">Frequency:</label>
-                <select name="periodicity" size="1" id="periodicity" onchange="javascript:document.getElementsByName('manualhist')[0].checked=(this.value==1); reset_num_pattern();">
-                <option value="" selected="selected">-- please choose --</option>
-                [% IF ( periodicity16 ) %]
-                <option value="16" selected="selected">Without periodicity</option>
-                [% ELSE %]
-                    <option value="16">Without periodicity</option>
-                [% END %]
-                [% IF ( periodicity48 ) %]
-                <option value="48" selected="selected">Unknown</option>
-                [% ELSE %]
-                <option value="48">Unknown</option>
-                [% END %]
-                [% IF ( periodicity32 ) %]
-                <option value="32" selected="selected">Irregular</option>
-                [% ELSE %]
-                    <option value="32">Irregular</option>
-                [% END %]
-
-                [% IF ( periodicity12 ) %]
-                    <option value="12" selected="selected">2/day</option>
-                [% ELSE %]
-                    <option value="12">2/day</option>
-                [% END %]
-                [% IF ( periodicity1 ) %]
-                    <option value="1" selected="selected">daily (n/week)</option>
-                [% ELSE %]
-                    <option value="1">daily (n/week)</option>
-                [% END %]
-                [% IF ( periodicity2 ) %]
-                    <option value="2" selected="selected">1/week</option>
+    <div id="bd">
+        <div class="yui-g">
+            <h1>[% IF ( modify ) %] Modify subscription for <i>[% bibliotitle |html %]</i>[% ELSE %]Add a new subscription[% END %] (<span id="page_number">1/2</span>)</h1>
+            <form method="post" name="f" action="/cgi-bin/koha/serials/subscription-add.pl">
+                [% IF ( modify ) %]
+                    <input type="hidden" name="op" value="modsubscription" />
+                    <input type="hidden" name="subscriptionid" value="[% subscriptionid %]" />
                 [% ELSE %]
-                    <option value="2">1/week</option>
+                        <input type="hidden" name="op" value="addsubscription" />
                 [% END %]
-                [% IF ( periodicity3 ) %]
-                    <option value="3" selected="selected">1/2 weeks </option>
-                [% ELSE %]
-                    <option value="3">1/2 weeks </option>
-                [% END %]
-                [% IF ( periodicity4 ) %]
-                    <option value="4" selected="selected">1/3 weeks</option>
-                [% ELSE %]
-                    <option value="4">1/3 weeks</option>
-                [% END %]
-                [% IF ( periodicity5 ) %]
-                    <option value="5" selected="selected">1/month</option>
-                [% ELSE %]
-                    <option value="5">1/month</option>
-                [% END %]
-                [% IF ( periodicity6 ) %]
-                    <option value="6" selected="selected">1/2 months (6/year)</option>
-                [% ELSE %]
-                    <option value="6">1/2 months (6/year)</option>
-                [% END %]
-                [% IF ( periodicity7 ) %]
-                    <option value="7" selected="selected">1/3 months (1/quarter)</option>
-                [% ELSE %]
-                    <option value="7">1/3 months (1/quarter)</option>
-                [% END %]
-                <!-- periodicity8 is 1/quarter, exactly like periodicity7 but will use it for seasonal option -->
-                [% IF ( periodicity8 ) %]
-                    <option value="8" selected="selected">1/quarter (seasonal)</option>
-                [% ELSE %]
-                    <option value="8">1/quarter (seasonal)</option>
-                [% END %]
-                [% IF ( periodicity13 ) %]
-                    <option value="13" selected="selected">1/4 months (3/year)</option>
-                [% ELSE %]
-                    <option value="13">1/4 months (3/year)</option>
-                [% END %]
-
-                [% IF ( periodicity9 ) %]
-                    <option value="9" selected="selected">2/years</option>
-                [% ELSE %]
-                    <option value="9">2/year</option>
-                [% END %]
-                [% IF ( periodicity10 ) %]
-                    <option value="10" selected="selected">1/year</option>
-                [% ELSE %]
-                    <option value="10">1/year</option>
-                [% END %]
-                [% IF ( periodicity11 ) %]
-                    <option value="11" selected="selected">1/2 years</option>
-                [% ELSE %]
-                    <option value="11">1/2 years</option>
-                [% END %]
-                </select> <span class="required">Required</span></li>
-                <li>
-                    <label for="manuallist"> Manual history:</label>
-                    [% IF ( manualhistory ) %]
-                        <input type="checkbox" name="manualhist" id="manuallist" value="1" checked="checked" />
-                    [% ELSE %]
-                        <input type="checkbox" name="manualhist" id="manuallist" value="1" />
-                    [% END %]
-                </li>
-        <li>
-           <label for="numberpattern"> Numbering pattern:</label>
-            
-                <select name="numbering_pattern" size="1" id="numberpattern" >
-                    <option value="" selected="selected">-- please choose --</option>
-                    [% IF ( numberpattern1 ) %]
-                        <option value="1" selected="selected">Number</option>
-                    [% ELSE %]
-                        <option value="1">Number</option>
-                    [% END %]
-                    [% IF ( numberpattern2 ) %]
-                        <option value="2" selected="selected">Volume, number, issue</option>
-                    [% ELSE %]
-                        <option value="2">Volume, number, issue</option>
-                    [% END %]
-                    [% IF ( numberpattern3 ) %]
-                        <option value="3" selected="selected">Volume, number</option>
-                    [% ELSE %]
-                        <option value="3">Volume, number</option>
-                    [% END %]
-                    [% IF ( numberpattern4 ) %]
-                        <option value="4" selected="selected">Volume, issue</option>
-                    [% ELSE %]
-                        <option value="4">Volume, issue</option>
-                    [% END %]
-                    [% IF ( numberpattern5 ) %]
-                        <option value="5" selected="selected">Number, issue</option>
-                    [% ELSE %]
-                        <option value="5">Number, issue</option>
-                    [% END %]
-                    [% IF ( numberpattern6 ) %]
-                        <option value="6" selected="selected">Seasonal only</option>
-                    [% ELSE %]
-                        <option value="6">Seasonal only</option>
-                    [% END %]
-                    [% IF ( numberpattern8 ) %]
-                        <option value="8" selected="selected">Year/Number</option>
-                    [% ELSE %]
-                        <option value="8">Year/Number</option>
-                    [% END %]          
-                    [% IF ( numberpattern7 ) %]
-                        <option value="7" selected="selected">None of the above</option>
-                    [% ELSE %]
-                        <option value="7">None of the above</option>
-                    [% END %]
-                </select>
-        </li>
-                <li id="more_options"></li>
-                <li id="irregularity"></li>
-                  <li id="displayexample"></li>
-        <li>
-           <label for="from" class="required"> Subscription start date:</label>
-                <input type="text" name="startdate" value="[% startdate %]" size="13" maxlength="10" id="from" class="datepickerfrom" />
-            <span class="required">Required</span>
-        </li>
-        <li>
-            <label for="subtype" class="required">Subscription length:</label>
-            
-                <select name="subtype" id="subtype">
-                    [% IF ( subtype_monthlength ) %]<option value="monthlength" selected="selected">[% ELSE %]<option value="monthlength">[% END %] Number of months</option>
-                    [% IF ( subtype_numberlength ) %]<option value="numberlength" selected="selected">[% ELSE %]<option value="numberlength">[% END %] Number of issues</option>
-                    [% IF ( subtype_weeklength ) %]<option value="weeklength" selected="selected">[% ELSE %]<option value="weeklength">[% END %] Number of weeks</option>
-                </select>
-                <input type="text" id="numberlength" name="sublength" value="[% sublength %]" size="3" onkeypress="return check_input(event)" /> (enter amount in numerals)
-            <span class="required">Required</span>
-        </li>
-        <li>
-           <label for="to"> Subscription end date:</label>
-                <input type="text" name="enddate" value="[% enddate %]" size="13" maxlength="10" id="to" class="datepickerto" />
-        </li>
-    <li><label for="numberingmethod">Numbering formula:</label> <input type="text" name="numberingmethod" id="numberingmethod" value="[% numberingmethod %]" />
-    </li>
-    </ol>
-       </fieldset>
-
-       <fieldset class="action">
-    <input type="button" class="action_test" value="Test prediction pattern" onclick="javascript:irregularity_check()" />
-    <input type="button" class="action_reset" value="Reset pattern" onclick="javascript:reset_pattern()" />
-    <input type="button" class="action_save"  value="Save subscription" onclick="Check(this.form)" accesskey="w" />
-       </fieldset>
-    <fieldset class="action">
-    <input type="button" class="action_advanced" value="Show/Hide advanced pattern" onclick="javascript:display_table()" />
-    </fieldset>
-           <div id="basetable"  style="display: none;">
-            <table class="small">
-                <tr><th colspan="4">Advanced prediction pattern</th></tr>
-                               <tr>
-                    <th>&nbsp;</th>
-                    <th>X</th>
-                    <th>Y</th>
-                    <th>Z</th>
-                </tr>
-                <tr>
-                    <td>Add</td>
-                    <td>
-                        <input type="text" name="add1" id="add1" value="[% add1 %]" />
-                    </td>
-                    <td>
-                        <input type="text" name="add2" id="add2" value="[% add2 %]" />
-                    </td>
-                    <td>
-                        <input type="text" name="add3" id="add3" value="[% add3 %]" />
-                    </td>
-                </tr>
-                <tr>
-                    <td>once every</td>
-                    <td><input type="text" name="every1" id="every1" value="[% every1 %]" /></td>
-                    <td><input type="text" name="every2" id="every2" value="[% every2 %]" /></td>
-                    <td><input type="text" name="every3" id="every3" value="[% every3 %]" /></td>
-                </tr>
-                <tr>
-                    <td>When more than</td>
-                    <td><input type="text" name="whenmorethan1" id="whenmorethan1" value="[% whenmorethan1 %]" /></td>
-                    <td><input type="text" name="whenmorethan2" id="whenmorethan2" value="[% whenmorethan2 %]" /></td>
-                    <td><input type="text" name="whenmorethan3" id="whenmorethan3" value="[% whenmorethan3 %]" /></td>
-                </tr>
-                <tr>
-                    <td>inner counter</td>
-                    <td><input type="text" name="innerloop1" id="innerloop1" value="[% innerloop1 %]" /></td>
-                    <td><input type="text" name="innerloop2" id="innerloop2" value="[% innerloop2 %]" /></td>
-                    <td><input type="text" name="innerloop3" id="innerloop3" value="[% innerloop3 %]" /></td>
-                </tr>
-                <tr>
-                    <td>Set back to</td>
-                    <td><input type="text" name="setto1" id="setto1" value="[% setto1 %]" /></td>
-                    <td><input type="text" name="setto2" id="setto2" value="[% setto2 %]" /></td>
-                    <td><input type="text" name="setto3" id="setto3" value="[% setto3 %]" /></td>
-                </tr>
-                <tr>
-                    <td>
-                        [% IF ( modify ) %]
-                            Last value
-                        [% ELSE %]
-                            Begins with
-                        [% END %]
-                    </td>
-                    <td><input type="text" name="lastvalue1" id="lastvalue1" value="[% lastvalue1 %]" /></td>
-                    <td><input type="text" name="lastvalue2" id="lastvalue2" value="[% lastvalue2 %]" /></td>
-                    <td><input type="text" name="lastvalue3" id="lastvalue3" value="[% lastvalue3 %]" /></td>
-                </tr>
-            </table>
+                <input type="hidden" name="user" value="[% loggedinusername %]" />
+                <input type="hidden" name="irreg_check" value="0" />
+
+                <div id="page_1">
+                    <div class="yui-u first">
+                        <fieldset id="subscription_add_information" class="rows">
+                            <legend>Subscription details</legend>
+                            <ol>
+                                [% IF ( subscriptionid ) %]
+                                    <li><span class="label">Subscription #</span> [% subscriptionid %]</li>
+                                [% END %]
+                                <li>
+                                    <label for="aqbooksellerid">Vendor: </label>
+                                    <input type="text" name="aqbooksellerid" id="aqbooksellerid" value="[% aqbooksellerid %]" size="8" /> (<input type="text" name="aqbooksellername" value="[% aqbooksellername %]" disabled="disabled" readonly="readonly" />) <a href="#" onclick="FindAcqui(f)">Search for a vendor</a>
+                                </li>
+                                <li>
+                                    <label for="biblionumber" class="required" title="Subscriptions must be associated with a bibliographic record">Biblio:</label>
+                                    <input type="text" name="biblionumber" id="biblionumber" value="[% bibnum %]" size="8" />
+                                    (<input type="text" name="title" value="[% bibliotitle %]" disabled="disabled" readonly="readonly" />) <span class="required" title="Subscriptions must be associated with a bibliographic record">Required</span>
+                                    <div class="inputnote"> <a href="#" onclick="Plugin(f)">Search for Biblio</a>
+                                        [% IF ( CAN_user_editcatalogue ) %]
+                                            [% IF ( modify ) %]
+                                            | <a href="#" onclick="addbiblioPopup([% bibnum %]); return false;">Edit biblio</a>
+                                            [% ELSE %]
+                                            | <a href="#" onclick="addbiblioPopup(); return false;">Create Biblio</a>
+                                            [% END %]
+                                        [% END %]
+                                    </div>
+                                </li>
+                                <li class="radio">
+                                    [% IF ( serialsadditems ) %]
+                                        <p><input type="radio" id="serialsadditems-yes" name="serialsadditems" value="1" checked="checked" /><label class="widelabel" for="serialsadditems-yes">create an item record when receiving this serial</label></p>
+                                        <p><input type="radio" id="serialsadditems-no" name="serialsadditems" value="0" /><label class="widelabel" for="serialsadditems-no">do not create an item record when receiving this serial </label></p>
+                                    [% ELSE %]
+                                        <p><input type="radio" id="serialsadditems-yes" name="serialsadditems" value="1"/><label class="widelabel" for="serialsadditems-yes">create an item record when receiving this serial</label></p>
+                                        <p><input type="radio" id="serialsadditems-no" name="serialsadditems" value="0" checked="checked" /><label class="widelabel" for="serialsadditems-no">do not create an item record when receiving this serial</label></p>
+                                    [% END %]
+                                </li>
+                                <li class="radio">
+                                  <p>When there is an irregular issue:</p>
+                                  [% IF (skip_serialseq) %]
+                                    <p>
+                                      <input type="radio" id="skip_serialseq_yes" name="skip_serialseq" value="1" checked="checked" />
+                                      <label for="skip_serialseq_yes">Skip issue number</label>
+                                    </p>
+                                    <p>
+                                      <input type="radio" id="skip_serialseq_no" name="skip_serialseq" value="0" />
+                                      <label for="skip_serialseq_no">Keep issue number</label>
+                                    </p>
+                                  [% ELSE %]
+                                    <p>
+                                      <input type="radio" id="skip_serialseq_yes" name="skip_serialseq" value="1" />
+                                      <label for="skip_serialseq_yes">Skip issue number</label>
+                                    </p>
+                                    <p>
+                                      <input type="radio" id="skip_serialseq_no" name="skip_serialseq" value="0" checked="checked" />
+                                      <label for="skip_serialseq_no">Keep issue number</label>
+                                    </p>
+                                  [% END %]
+                                </li>
+                                <li>
+                                    <label for="manualhistory">Manual history</label>
+                                    [% IF (manualhistory) %]
+                                        <input type="checkbox" id="manualhistory" name="manualhist" checked="checked" />
+                                    [% ELSE %]
+                                        <input type="checkbox" id="manualhistory" name="manualhist" />
+                                    [% END %]
+                                </li>
+                                <li>
+                                    <label for="callnumber">Call number</label>
+                                    <input type="text" name="callnumber" id="callnumber" value="[% callnumber %]" size="20" />
+                                </li>
+                                <li>
+                                    <label for="branchcode">Library:</label>
+                                    <select name="branchcode" id="branchcode" style="width: 20em;">
+                                        [% UNLESS ( Independantbranches ) %]
+                                            <option value="">None</option>
+                                        [% END %]
+                                        [% FOREACH branchloo IN branchloop %]
+                                            [% IF ( branchloo.selected ) %]
+                                                <option value="[% branchloo.value %]" selected="selected">[% branchloo.branchname %]</option>
+                                            [% ELSE %]
+                                                <option value="[% branchloo.value %]">[% branchloo.branchname %]</option>
+                                            [% END %]
+                                        [% END %]
+                                    </select> (select a library)
+                                </li>
+                                <li>
+                                    <label for="notes">Public note:</label>
+                                    <textarea name="notes" id="notes" cols="30" rows="2">[% notes %]</textarea>
+                                </li>
+                                <li>
+                                    <label for="internalnotes">Nonpublic note:</label>
+                                    <textarea name="internalnotes" id="internalnotes" cols="30" rows="2">[% internalnotes %]</textarea>
+                                </li>
+                                <li>
+                                    [% IF ( letterloop ) %]
+                                        <label for="letter">Patron notification: </label>
+                                        <select name="letter" id="letter">
+                                            <option value="">None</option>
+                                            [% FOREACH letterloo IN letterloop %]
+                                                [% IF ( letterloo.selected ) %]
+                                                    <option value="[% letterloo.value %]" selected="selected">[% letterloo.lettername %]</option>
+                                                [% ELSE %]
+                                                    <option value="[% letterloo.value %]">[% letterloo.lettername %]</option>
+                                                [% END %]
+                                            [% END %]
+                                        </select>
+                                        <div class="hint">Select a notice and patrons on the routing list will be notified when new issues are received.</div>
+                                    [% ELSE %]
+                                        <span class="label">Patron notification: </span>
+                                        <div class="hint">To notify patrons of new serial issues, you must <a href="/cgi-bin/koha/tools/letter.pl">define a notice</a>.</div>
+                                    [% END %]
+                                </li>
+                                <li>
+                                    <label for="location">Location:</label>
+                                    <select name="location" id="location">
+                                        <option value="">None</option>
+                                        [% FOREACH locations_loo IN locations_loop %]
+                                            [% IF ( locations_loo.selected ) %]
+                                                <option value="[% locations_loo.authorised_value %]" selected="selected">[% locations_loo.lib %]</option>
+                                            [% ELSE %]
+                                                <option value="[% locations_loo.authorised_value %]">[% locations_loo.lib %]</option>
+                                            [% END %]
+                                        [% END %]
+                                    </select>
+                                </li>
+                                <li>
+                                    <label for="graceperiod">Grace period:</label>
+                                    <input type="text" name="graceperiod" id="graceperiod" value="[% graceperiod %]" size="5"/> day(s)
+                                </li>
+                                <li>
+                                     <label class="widelabel" for="staffdisplaycount">Number of issues to display to staff: </label>
+                                     <input type="text" name="staffdisplaycount" id="staffdisplaycount" value="[% staffdisplaycount %]" size="4"/>
+                                 </li>
+                                 <li>
+                                    <label class="widelabel" for="opacdisplaycount">Number of issues to display to the public: </label>
+                                    <input type="text" name="opacdisplaycount" id="opacdisplaycount" value="[% opacdisplaycount %]" size="4"/>
+                                </li>
+                            </ol>
+                        </fieldset>
+                        <fieldset class="action">
+                            <input type="button" value="Next >>" onclick="if ( Check_page1() ) show_page_2();" style="float:right;" />
+                        </fieldset>
+                    </div>
+                </div>
+
+                <div id="page_2">
+                    <div class="yui-u first">
+                        <div id="subscription_form_planning">
+                            <fieldset class="rows">
+                                <legend>Serials planning</legend>
+                                <ol>
+                                    <li>
+                                        <label for="firstacquidate">First issue publication date: (*)</label>
+                                        [% UNLESS (more_than_one_serial) %]
+                                          <input type="text" size="10" id="acqui_date" name="firstacquidate" value="[% firstacquidate | $KohaDates %]" class="datepicker" readonly="readonly"/>
+                                        [% ELSE %]
+                                          [% firstacquidate | $KohaDates %]
+                                          <input type="hidden" size="10" id="acqui_date" name="firstacquidate" value="[% firstacquidate | $KohaDates %]"/>
+                                        [% END %]
+                                    </li>
+                                    [% IF (more_than_one_serial) %]
+                                      <li>
+                                        <label for="nextacquidate">Next issue publication date:</label>
+                                        <input type="text" size="10" id="nextacquidate" name="nextacquidate" value="[% nextacquidate | $KohaDates %]" class="datepicker" readonly="readonly"/>
+                                      </li>
+                                    [% END %]
+                                    <li>
+                                        <label for="frequency">Frequency: (*)</label>
+                                        <select name="frequency" size="1" id="frequency">
+                                            <option value="">-- please choose --</option>
+                                            [% FOREACH frequency IN frequencies %]
+                                                <option value="[% frequency.id %]" [% IF (frequency.selected) %] selected="selected" [% END %]>
+                                                    [% frequency.label %]
+                                                </option>
+                                            [% END %]
+                                        </select>
+                                    </li>
+                                    <li>
+                                        <label for="subtype">Subscription length:</label>
+                                        <select name="subtype" id="subtype">
+                                            [% FOREACH subt IN subtype %]
+                                                <option value="[% subt.name %]" [% IF (subt.selected) %] selected="selected" [% END %] >
+                                                    [% subt.name %]
+                                                </option>
+                                            [% END %]
+                                        </select>
+                                        <input type="text" name="sublength" id="sublength" value="[% sublength %]" size="3" /> (enter amount in numerals)
+                                        <input type="hidden" name="issuelengthcount">
+                                    </li>
+                                    <li>
+                                        <label for="startdate"> Subscription start date: (*)</label>
+                                        <input type="text" size="10" id="from" name="startdate" value="[% startdate | $KohaDates %]" class="datepickerfrom" readonly="readonly"/>
+                                    </li>
+                                    <li>
+                                        <label for="enddate">Subscription end date:</label>
+                                        <input type="text" size="10" id="to" name="enddate" value="[% enddate | $KohaDates %]" class="datepickerto" readonly="readonly"/>
+                                    </li>
+                                    <li>
+                                        <label for="numberpattern">Numbering pattern:</label>
+                                        <select name="numbering_pattern" size="1" id="numberpattern">
+                                            <option value="">-- please choose --</option>
+                                            [% FOREACH numberpattern IN numberpatterns %]
+                                                <option value="[% numberpattern.id %]" [% IF (numberpattern.selected) %] selected="selected" [% END %]>[% numberpattern.label %]</option>
+                                            [% END %]
+                                        </select>
+                                    </li>
+                                    <li>
+                                        <label for="locale">Locale</label>
+                                        <select id="locale" name="locale">
+                                            <option value=""></option>
+                                            [% FOREACH locale IN locales %]
+                                                <option value="[% locale %]">
+                                                    [% locale %]
+                                                </option>
+                                            [% END %]
+                                        </select>
+                                        <span class="hint">If empty, system locale is used</span>
+                                    </li>
+                                    <li id="more_options">
+                                        <table id="moreoptionst">
+                                            <thead>
+                                                <tr>
+                                                    <th>&nbsp;</th>
+                                                    <th id="headerX">&nbsp;</th>
+                                                    <th id="headerY">&nbsp;</th>
+                                                    <th id="headerZ">&nbsp;</th>
+                                                </tr>
+                                            </thead>
+                                            <tbody>
+                                                <tr>
+                                                    <td>
+                                                      [% IF (more_than_one_serial) %]
+                                                        Last value
+                                                      [% ELSE %]
+                                                        Begins with
+                                                      [% END %]
+                                                    </td>
+                                                    <td id="beginsX"><input type="text" id="lastvaluetemp1" name="lastvaluetemp1" value="[% lastvalue1 %]" /></td>
+                                                    <td id="beginsY"><input type="text" id="lastvaluetemp2" name="lastvaluetemp2" value="[% lastvalue2 %]" /></td>
+                                                    <td id="beginsZ"><input type="text" id="lastvaluetemp3" name="lastvaluetemp3" value="[% lastvalue3 %]" /></td>
+                                                </tr>
+                                                <tr>
+                                                    <td>Inner counter</td>
+                                                    <td id="innerX"><input type="text" id="innerlooptemp1" name="innerlooptemp1" value="[% innerloop1 %]" /></td>
+                                                    <td id="innerY"><input type="text" id="innerlooptemp2" name="innerlooptemp2" value="[% innerloop2 %]" /></td>
+                                                    <td id="innerZ"><input type="text" id="innerlooptemp3" name="innerlooptemp3" value="[% innerloop3 %]" /></td>
+                                                </tr>
+                                            </tbody>
+                                        </table>
+                                    </li>
+                                    <li><a style="cursor:pointer" onclick="toggleAdvancedPattern();">Show/Hide advanced pattern</a></li>
+                                    <div id="advancedpredictionpattern" style="display:none">
+                                      <li>
+                                        <label for="patternname">Pattern name: (*)</label>
+                                        <input id="patternname" name="patternname" type="text" readonly="readonly" />
+                                      </li>
+                                      <li>
+                                        <label for="numberingmethod">Numbering formula:</label>
+                                        <input readonly="readonly" type="text" name="numberingmethod" id="numberingmethod" size="50" value="[% numberingmethod %]" />
+                                      </li>
+                                        <table id="advancedpredictionpatternt">
+                                            <thead>
+                                                <tr>
+                                                    <th colspan="4">Advanced prediction pattern</td>
+                                                </tr>
+                                                <tr>
+                                                    <th>&nbsp;</th>
+                                                    <th>X</th>
+                                                    <th>Y</th>
+                                                    <th>Z</th>
+                                                </tr>
+                                            </thead>
+                                            <tbody>
+                                                <tr>
+                                                    <td>Label</td>
+                                                    <td><input type="text" readonly="readonly" id="label1" name="label1" /></td>
+                                                    <td><input type="text" readonly="readonly" id="label2" name="label2" /></td>
+                                                    <td><input type="text" readonly="readonly" id="label3" name="label3" /></td>
+                                                </tr>
+                                                <tr>
+                                                    <td>Begins with</td>
+                                                    <td><input type="text" readonly="readonly" id="lastvalue1" name="lastvalue1" /></td>
+                                                    <td><input type="text" readonly="readonly" id="lastvalue2" name="lastvalue2" /></td>
+                                                    <td><input type="text" readonly="readonly" id="lastvalue3" name="lastvalue3" /></td>
+                                                </tr>
+                                                <tr>
+                                                    <td>Add</td>
+                                                    <td><input type="text" readonly="readonly" id="add1" name="add1" /></td>
+                                                    <td><input type="text" readonly="readonly" id="add2" name="add2" /></td>
+                                                    <td><input type="text" readonly="readonly" id="add3" name="add3" /></td>
+                                                </tr>
+                                                <tr>
+                                                    <td>Every</td>
+                                                    <td><input type="text" readonly="readonly" id="every1" name="every1" /></td>
+                                                    <td><input type="text" readonly="readonly" id="every2" name="every2" /></td>
+                                                    <td><input type="text" readonly="readonly" id="every3" name="every3" /></td>
+                                                </tr>
+                                                <tr>
+                                                    <td>Set back to</td>
+                                                    <td><input type="text" readonly="readonly" id="setto1" name="setto1" /></td>
+                                                    <td><input type="text" readonly="readonly" id="setto2" name="setto2" /></td>
+                                                    <td><input type="text" readonly="readonly" id="setto3" name="setto3" /></td>
+                                                </tr>
+                                                <tr>
+                                                    <td>When more than</td>
+                                                    <td><input type="text" readonly="readonly" id="whenmorethan1" name="whenmorethan1" /></td>
+                                                    <td><input type="text" readonly="readonly" id="whenmorethan2" name="whenmorethan2" /></td>
+                                                    <td><input type="text" readonly="readonly" id="whenmorethan3" name="whenmorethan3" /></td>
+                                                </tr>
+                                                <tr>
+                                                    <td>Inner counter</td>
+                                                    <td><input type="text" readonly="readonly" id="innerloop1" name="innerloop1" /></td>
+                                                    <td><input type="text" readonly="readonly" id="innerloop2" name="innerloop2" /></td>
+                                                    <td><input type="text" readonly="readonly" id="innerloop3" name="innerloop3" /></td>
+                                                </tr>
+                                                <tr>
+                                                    [% BLOCK numbering_select %]
+                                                        <select disabled="disabled" id="[% name %]" name="[% name %]" />
+                                                            <option value=""></option>
+                                                            <option value="dayname">Name of day</option>
+                                                            <option value="monthname">Name of month</option>
+                                                            <option value="season">Name of season</option>
+                                                        </select>
+                                                    [% END %]
+                                                    <td>Formatting</td>
+                                                    <td>[% PROCESS numbering_select name="numbering1" %]</td>
+                                                    <td>[% PROCESS numbering_select name="numbering2" %]</td>
+                                                    <td>[% PROCESS numbering_select name="numbering3" %]</td>
+                                                </tr>
+                                            </tbody>
+                                        </table>
+                                        <input id="modifyadvancedpatternbutton" type="button" value="Modify pattern" onclick="modifyAdvancedPattern();" />
+                                        <input id="restoreadvancedpatternbutton" type="button" value="Cancel modifications" onclick="restoreAdvancedPattern();" style="display:none" />
+                                        <input id="saveadvancedpatternbutton" type="button" value="Save as new pattern" onclick="saveAdvancedPattern();" style="display:none" />
+                                    </div>
+                                </ol>
+                            </fieldset>
+                            <fieldset class="action">
+                                <input type="button" value="<< Previous" onclick="show_page_1();" style="float:left;"/>
+                                <input id="testpatternbutton" type="button" value="Test prediction pattern" onclick="testPredictionPattern();" />
+                                <input type="button" value="Save subscription" onclick="if (Check_page2()) submit();" style="float:right;" accesskey="w" />
+                            </fieldset>
+                        </div>
+                    </div>
+                    <div class="yui-u">
+                        <li id="displayexample"></li>
+                    </div>
+                </div>
+            </form>
         </div>
-
-</div>
-</div>
-</form>
-</div>
-
+    </div>
 </div>
 
 [% INCLUDE 'intranet-bottom.inc' %]
index e6a7074..80f74e7 100644 (file)
@@ -9,21 +9,6 @@ var text = new Array(_("Number"),_("Volume"),_("Issue"),_("Month"),_("Week"),_("
 "Autumn"),_("Winter"),_("Spring"),_("Summer"),_("Fall"),_("Season"),_("Year"));
 
 
-// to display the options section
-function options(x,y,z){
-var textbox = '';
-    // alert("X: "+x+"Y: "+y+"Z: "+z);
-    if(x){
-        document.f.xfield.value = x;
-        if(y){
-            document.f.yfield.value = y;
-            if(z){
-                document.f.zfield.value = z;
-            }
-        }
-    }
-}
-
 function confirm_deletion() {
     var is_confirmed = confirm(_("Are you sure you want to delete this subscription?"));
     if (is_confirmed) {
@@ -108,6 +93,14 @@ $(document).ready(function() {
         [% ELSE %]
             <li><span class="label">Items:</span> Serial receipt does not create an item record.</li>
         [% END %]
+        <li>
+            <span class="label">Serial number:</span>
+            [% IF skip_serialseq %]
+                Serial number is skipped when an irregularity is found.
+            [% ELSE %]
+                Serial number is kept when an irregularity is found.
+            [% END %]
+        </li>
         <li><span class="label">Grace period:</span> [% graceperiod %]</li>
         </ol>
     </div>
@@ -171,118 +164,44 @@ $(document).ready(function() {
         <ol>
             <li><span class="label">Beginning date:</span> [% startdate %]
             </li>
-            <li><span class="label">Frequency (*):</span>
-                [% IF ( periodicity16 ) %]
-                        Without regularity
-                [% END %]
-                [% IF ( periodicity32 ) %]
-                        Irregular
-                [% END %]
-                [% IF ( periodicity0 ) %]
-                        Unknown
-                [% END %]
-                [% IF ( periodicity12 ) %]
-                        2/day
-                [% END %]
-                [% IF ( periodicity1 ) %]
-                        1/day
-                [% END %]
-                [% IF ( periodicity13 ) %]
-                        1/4 months (3/year)
-                [% END %]
-                [% IF ( periodicity2 ) %]
-                        1/week
-                [% END %]
-                [% IF ( periodicity3 ) %]
-                        1/2 weeks
-                [% END %]
-                [% IF ( periodicity4 ) %]
-                        1/3 weeks
-                [% END %]
-                [% IF ( periodicity5 ) %]
-                        1/month
-                [% END %]
-                [% IF ( periodicity6 ) %]
-                        1/2 months (6/year)
-                [% END %]
-                [% IF ( periodicity7 ) %]
-                        1/quarter
-                [% END %]
-                [% IF ( periodicity8 ) %]
-                        1/quarter
-                [% END %]
-                [% IF ( periodicity9 ) %]
-                        2/year
-                [% END %]
-                [% IF ( periodicity10 ) %]
-                        1/year
-                [% END %]
-                [% IF ( periodicity11 ) %]
-                        1/2 years
-                [% END %]
+            <li><span class="label">Frequency:</span>
+                [% frequency.description %]
             </li>
             <li>
               <span class="label">Manual history: </span>
                 [% IF ( manualhistory ) %]
-                    Enabled
+                    Enabled <a href="/cgi-bin/koha/serials/subscription-history.pl?subscriptionid=[% subscriptionid %]">Edit history</a>
                 [% ELSE %]
                     Disabled
                 [% END %]
             </li>
             <li><span class="label">Number pattern:</span>
-                [% IF ( numberpattern1 ) %]
-                    Number only
-                [% END %]
-                [% IF ( numberpattern2 ) %]
-                    Volume, number, issue
-                [% END %]
-                [% IF ( numberpattern3 ) %]
-                    Volume, number
+                [% numberpattern.label %]
+            </li>
+            <li><table>
+            <tr>
+                <td>Starting with:</td>
+                [% IF (has_X) %]
+                    <td align="center">[% lastvalue1 %]</td>
                 [% END %]
-                [% IF ( numberpattern4 ) %]
-                    Volume, issue
+                [% IF (has_Y) %]
+                    <td align="center">[% lastvalue2 %]</td>
                 [% END %]
-                [% IF ( numberpattern5 ) %]
-                    Number, issue
+                [% IF (has_Z) %]
+                    <td align="center">[% lastvalue3 %]</td>
                 [% END %]
-                [% IF ( numberpattern8 ) %]
-                    Year/Number
+            </tr>
+            <tr>
+                <td>Rollover:</td>
+                [% IF (has_X) %]
+                    <td align="center">[% numberpattern.whenmorethan1 %]</td>
                 [% END %]
-                [% IF ( numberpattern6 ) %]
-                    Seasonal only
+                [% IF (has_Y) %]
+                    <td align="center">[% numberpattern.whenmorethan2 %]</td>
                 [% END %]
-                [% IF ( numberpattern7 ) %]
-                    None of the above
+                [% IF (has_Z) %]
+                    <td align="center">[% numberpattern.whenmorethan3 %]</td>
                 [% END %]
-            </li>
-            <li><table>
-            <tr><td>Starting with:</td>
-                <td align="center">[% lastvalue1 %]</td>
-            [% IF ( lastvalue2 ) %]
-                <td align="center">&nbsp; 
-                    [% lastvalue2 %]
-                </td>
-            [% END %]
-            [% IF ( lastvalue3 ) %]
-                <td align="center">&nbsp; 
-                    [% lastvalue3 %]
-                </td>
-            [% END %]
-            </tr>
-            <tr><td>Rollover:</td>
-                <td align="center">
-                    [% IF ( whenmorethan1 < 9999999 ) %][% whenmorethan1 %][% ELSE %]Never[% END %]
-                </td>
-            [% IF ( whenmorethan2 ) %]
-                <td align="center">&nbsp;
-                    [% IF ( whenmorethan2 < 9999999 ) %][% whenmorethan2 %][% ELSE %]Never[% END %]
-                </td>
-            [% END %]
-            [% IF ( whenmorethan3 ) %]
-                <td align="center">&nbsp;
-                    [% IF ( whenmorethan3 < 9999999 ) %][% whenmorethan3 %][% ELSE %]Never[% END %]
-                </td>
-            [% END %]
             </tr>
             </table></li>
             [% IF ( irregular_issues ) %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-frequencies.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-frequencies.tt
new file mode 100644 (file)
index 0000000..8f8a4ab
--- /dev/null
@@ -0,0 +1,215 @@
+[% INCLUDE 'doc-head-open.inc' %]
+<title>Koha &rsaquo; Serials &rsaquo; Frequencies</title>
+[% INCLUDE 'doc-head-close.inc' %]
+<script type="text/javascript">
+//<![CDATA[
+function confirmDelete() {
+  return confirm(_("Are you sure you want to delete this subscription frequency?"));
+}
+
+function check_form() {
+    var description = $("#description").val();
+    var unit = $("#unit").val();
+    var issuesperunit = $("#issuesperunit").val();
+    var unitsperissue = $("#unitsperissue").val();
+    var alert_msg = _("Some fields are not valid:") + "\n";
+    var errors = 0;
+
+    if(description.length == 0) {
+        alert_msg += "\t - " + _("Description is required");
+        errors ++;
+    }
+    if(unit.length > 0) {
+        if(isNaN(issuesperunit) || issuesperunit == 0) {
+            alert_msg += "\n\t - " + _("Issues per unit is required")
+                + " " + _("(must be a number greater than 0)");
+            errors ++;
+        }
+        if(isNaN(unitsperissue) || unitsperissue == 0) {
+            alert_msg += "\n\t - " + _("Units per issue is required")
+                + " " + _("(must be a number greater than 0)");
+            errors ++;
+        }
+        if(issuesperunit > 1 && unitsperissue > 1) {
+            alert_msg += "\n\t - " + _("One of 'issues per unit' and 'units per issue' must be equal to 1");
+            errors ++;
+        }
+    }
+
+    if(errors == 0) {
+        return true;
+    }
+
+    alert(alert_msg);
+    return false;
+}
+
+function show_blocking_subs() {
+    $("#blocking_subs").show();
+}
+
+$(document).ready(function() {
+    $("#issuesperunit").change(function() {
+        var value = $(this).val();
+        if(!isNaN(value) && value > 1) {
+            $("#unitsperissue").val(1);
+        }
+    });
+    $("#unitsperissue").change(function() {
+        var value = $(this).val();
+        if(!isNaN(value) && value > 1) {
+            $("#issuesperunit").val(1);
+        }
+    });
+});
+//]]>
+</script>
+</head>
+
+<body>
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'serials-search.inc' %]
+
+<div id="breadcrumbs">
+    <a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo;
+    <a href="/cgi-bin/koha/serials/serials-home.pl">Serials</a> &rsaquo;
+    <a href="/cgi-bin/koha/serials/subscription-frequencies.pl">Frequencies</a>
+</div>
+
+<div id="doc3" class="yui-t2">
+
+<div id="bd">
+  <div id="yui-main">
+    <div class="yui-b">
+      [% IF (new or modify) %]
+        [% IF (new) %]
+          <h1>New frequency</h1>
+        [% ELSE %]
+          <h1>Modify frequency: [% description %]</h1>
+        [% END %]
+        <form action="/cgi-bin/koha/serials/subscription-frequencies.pl" method="post" onsubmit="return check_form();">
+          [% IF (modify) %]
+            <input type="hidden" name="id" value="[% id %]" />
+            <input type="hidden" name="op" value="savemod" />
+          [% ELSE %]
+            <input type="hidden" name="op" value="savenew" />
+          [% END %]
+          <fieldset class="rows">
+            <ol>
+              <li>
+                <label for="description">Description:</label>
+                <input type="text" id="description" name="description" value="[% description %]" />
+              </li>
+              <li>
+                <label for="unit">Unit</label>
+                <select id="unit" name="unit">
+                  <option value="">None</option>
+                  [% FOREACH unit IN units_loop %]
+                    [% IF (unit.selected) %]
+                      <option selected="selected" value="[% unit.val %]">
+                    [% ELSE %]
+                      <option value="[% unit.val %]">
+                    [% END %]
+                      [% unit.val %]
+                    </option>
+                  [% END %]
+                </select>
+              </li>
+              <li><span class="hint">Note: one of the two following fields must be equal to 1</span></li>
+              <li>
+                <label for="issuesperunit">Issues per unit</label>
+                [% IF (new) %]
+                  <input type="text" id="issuesperunit" name="issuesperunit" value="1" size="3" />
+                [% ELSE %]
+                  <input type="text" id="issuesperunit" name="issuesperunit" value="[% issuesperunit %]" size="3" />
+                [% END %]
+              </li>
+              <li>
+                <label for="unitsperissue">Units per issue</label>
+                [% IF (new) %]
+                  <input type="text" id="unitsperissue" name="unitsperissue" value="1" size="3" />
+                [% ELSE %]
+                  <input type="text" id="unitsperissue" name="unitsperissue" value="[% unitsperissue %]" size="3" />
+                [% END %]
+              </li>
+              <li>
+                <label for="displayorder">Display order</label>
+                <input type="text" id="displayorder" name="displayorder" value="[% displayorder %]" size="3" />
+              </li>
+            </ol>
+          </fieldset>
+          <fieldset class="action">
+            <input type="submit" value="Save" />
+            <input type="button" value="Cancel" onclick="window.location='/cgi-bin/koha/serials/subscription-frequencies.pl'" />
+          </fieldset>
+        </form>
+      [% ELSE %]
+        <h1>Frequencies</h1>
+        [% IF still_used %]
+            <div class="dialog">
+                <p>
+                    This frequency is still used by [% subscriptions.size %]
+                    subscription(s). Do you still want to delete it?
+                </p>
+                <p><a href="#" onclick="show_blocking_subs(); return false;">Show subscriptions</a></p>
+                <ul id="blocking_subs" style="display:none">
+                    [% FOREACH sub IN subscriptions %]
+                        <li style="list-style-type:none">
+                            <a href="/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=[% sub.subscriptionid %]">[% sub.title %]</a>
+                        </li>
+                    [% END %]
+                </ul>
+
+                <form action="" method="get">
+                    <input type="hidden" name="op" value="del" />
+                    <input type="hidden" name="confirm" value="1" />
+                    <input type="hidden" name="frequencyid" value="[% frequencyid %]" />
+                    <input type="submit" class="approve" value="Yes, delete" />
+                </form>
+                <form action="" method="get">
+                    <input type="submit" class="deny" value="No, don't delete" />
+                </form>
+            </div>
+        [% END %]
+        <a href="/cgi-bin/koha/serials/subscription-frequencies.pl?op=new">New frenquency</a>
+
+        [% IF (frequencies_loop.size) %]
+          <table id="frequenciest">
+            <thead>
+              <tr>
+                <th>Description</th>
+                <th>Unit</th>
+                <th>Issues per unit</th>
+                <th>Units per issue</th>
+                <th>Display order</th>
+                <th>&nbsp;</th>
+              </tr>
+            </thead>
+            <tbody>
+              [% FOREACH frequency IN frequencies_loop %]
+                <tr>
+                  <td>[% frequency.description %]</td>
+                  <td>[% frequency.unit %]</td>
+                  <td>[% frequency.issuesperunit %]</td>
+                  <td>[% frequency.unitsperissue %]</td>
+                  <td>[% frequency.displayorder %]</td>
+                  <td>
+                    <a href="/cgi-bin/koha/serials/subscription-frequencies.pl?op=modify&frequencyid=[% frequency.id %]">Modify</a> |
+                    <a href="/cgi-bin/koha/serials/subscription-frequencies.pl?op=del&frequencyid=[% frequency.id %]">Delete</a>
+                  </td>
+                </tr>
+              [% END %]
+            </tbody>
+          </table>
+        [% ELSE %]
+          <p>There is no defined frequency.</p>
+        [% END %]
+      [% END %]
+
+    </div>
+  </div>
+  <div class="yui-b">
+    [% INCLUDE 'serials-menu.inc' %]
+  </div>
+</div>
+[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-history.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-history.tt
new file mode 100644 (file)
index 0000000..ef35f31
--- /dev/null
@@ -0,0 +1,60 @@
+[% USE KohaDates %]
+
+[% INCLUDE 'doc-head-open.inc' %]
+<title>Koha &rsaquo; Serials &rsaquo; Subscription history</title>
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+
+<body>
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'serials-search.inc' %]
+
+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/serials/serials-home.pl">Serials</a> &rsaquo; Subscription history</div>
+
+<div id="doc3" class="yui-t2">
+
+<div id="bd">
+  <div id="yui-main">
+    <div class="yui-b">
+      <h1>Subscription history for [% title %]</h1>
+        <div id="subscription_form_history">
+          <form method="post" action="/cgi-bin/koha/serials/subscription-history.pl">
+            <input type="hidden" name="op" value="mod" />
+            <input type="hidden" name="subscriptionid" value="[% subscriptionid %]" />
+            <p>Hint : you can update the serial history manually. This can be useful for an old subscription or to clean the existing history. Modify those fields with care, as future serial recieve will continue to update them automatically.</p>
+            <table>
+              <tr>
+                <td>Subscription start date</td>
+                <td><input type="text" name="histstartdate" value="[% histstartdate | $KohaDates %]" /> (start date of the 1st subscription)</td>
+              </tr>
+              <tr>
+                <td>Subscription end date</td>
+                <td><input type="text" name="histenddate" value="[% histenddate | $KohaDates %]" />(if empty, subscription is still active)</td>
+              </tr>
+              <tr>
+                <td>Received issues</td>
+                <td><textarea name="receivedlist" cols="60" rows="5">[% receivedlist %]</textarea></td>
+              </tr>
+              <tr>
+                <td>Missing issues</td>
+                <td><textarea name="missinglist" cols="60" rows="5">[% missinglist %]</textarea></td>
+              </tr>
+              <tr>
+                <td>Note for OPAC</td>
+                <td><textarea name="opacnote" cols="60" rows="5">[% opacnote %]</textarea></td>
+              </tr>
+              <tr>
+                <td>Note for staff</td>
+                <td><textarea name="librariannote" cols="60" rows="5">[% librariannote %]</textarea></td>
+              </tr>
+            </table>
+            <input type="submit" value="Save subscription history"  />
+          </form>
+        </div>
+    </div>
+  </div>
+  <div class="yui-b">
+    [% INCLUDE 'serials-menu.inc' %]
+  </div>
+</div>
+[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-numberpatterns.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-numberpatterns.tt
new file mode 100644 (file)
index 0000000..4ab79f4
--- /dev/null
@@ -0,0 +1,333 @@
+[% INCLUDE 'doc-head-open.inc' %]
+<title>Koha &rsaquo; Serials &rsaquo; Number patterns</title>
+[% INCLUDE 'doc-head-close.inc' %]
+[% INCLUDE 'calendar.inc' %]
+<script type="text/javascript">
+//<![CDATA[
+[% IF (new or modify) %]
+  function testPattern() {
+      var frequencyid = $("#frequency").val();
+      var firstacquidate = $("#firstacquidate").val();
+      var error = 0;
+      var error_msg = "";
+      if(frequencyid == undefined || frequencyid == "") {
+          error_msg += _("- Frequency is not defined\n");
+          error ++;
+      }
+      if(firstacquidate == undefined || firstacquidate == "") {
+          error_msg += _("- First publication date is not defined\n");
+          error ++;
+      }
+
+      if(error){
+          alert(_("Cannot test prediction pattern for the following reason(s):\n\n")
+              + error_msg);
+          return false;
+      }
+
+      var ajaxData = {
+          'custompattern': true,
+      };
+      var ajaxParams = [
+          'firstacquidate', 'subtype', 'sublength', 'frequency', 'numberingmethod',
+          'lastvalue1', 'lastvalue2', 'lastvalue3', 'add1', 'add2', 'add3',
+          'every1', 'every2', 'every3', 'innerloop1', 'innerloop2', 'innerloop3',
+          'setto1', 'setto2', 'setto3', 'numbering1', 'numbering2', 'numbering3',
+          'whenmorethan1', 'whenmorethan2', 'whenmorethan3', 'locale'
+      ];
+      for(i in ajaxParams) {
+          var param = ajaxParams[i];
+          var value = $("#"+param).val();
+          if(value.length > 0)
+              ajaxData[param] = value;
+      }
+
+      $.ajax({
+          url: "/cgi-bin/koha/serials/showpredictionpattern.pl",
+          data: ajaxData,
+          async: false,
+          dataType: "text",
+          success: function(data) {
+              $("#predictionpattern").html(data);
+          }
+      });
+  }
+[% END %]
+
+function show_blocking_subs() {
+    $("#blocking_subs").show();
+}
+//]]>
+</script>
+</head>
+
+<body>
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'serials-search.inc' %]
+
+<div id="breadcrumbs">
+    <a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo;
+    <a href="/cgi-bin/koha/serials/serials-home.pl">Serials</a> &rsaquo;
+    <a href="/cgi-bin/koha/serials/subscription-numberpatterns.pl">Numbering patterns</a>
+</div>
+
+<div id="doc3" class="yui-t2">
+
+<div id="bd">
+  <div id="yui-main">
+    <div class="yui-b">
+      [% IF (new or modify) %]
+        <div class="yui-g">
+          [% IF (new) %]
+            <h1>New number pattern</h1>
+            [% IF (error_existing_numberpattern) %]
+              <div class="dialog">
+                <p>A pattern with this name already exists.</p>
+              </div>
+            [% END %]
+          [% ELSE %]
+            <h1>Modify pattern: [% label %]</h1>
+            [% IF (error_existing_numberpattern) %]
+              <div class="dialog">
+                <p>Another pattern with this name already exists.</p>
+              </div>
+            [% END %]
+          [% END %]
+        </div>
+        <div class="yui-g">
+          <form action="/cgi-bin/koha/serials/subscription-numberpatterns.pl" method="post">
+            [% IF (new) %]
+              <input type="hidden" name="op" value="savenew" />
+            [% ELSE %]
+              <input type="hidden" name="op" value="savemod" />
+              <input type="hidden" name="id" value="[% id %]" />
+            [% END %]
+            <fieldset class="rows">
+              <ol>
+                <li>
+                  <label for="label">Name:</label>
+                  <input type="text" id="label" name="label" value="[% label %]" />
+                </li>
+                <li>
+                  <label for="description">Description:</label>
+                  <input type="text" id="description" name="description" value="[% description %]" />
+                </li>
+                <li>
+                  <label for="numberingmethod">Numbering formula:</label>
+                  <input type="text" id="numberingmethod" name="numberingmethod" value="[% numberingmethod %]" />
+                </li>
+                <li>
+                  <label for="displayorder">Display order:</label>
+                  <input type="text" id="displayorder" name="displayorder" value="[% displayorder %]" />
+                </li>
+              </ol>
+              <table>
+                <thead>
+                  <tr>
+                    <th>&nbsp;</th>
+                    <th>X</th>
+                    <th>Y</th>
+                    <th>Z</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  <tr>
+                    <td>Label</td>
+                    <td><input type="text" id="label1" name="label1" value="[% label1 %]" /></td>
+                    <td><input type="text" id="label2" name="label2" value="[% label2 %]" /></td>
+                    <td><input type="text" id="label3" name="label3" value="[% label3 %]" /></td>
+                  </tr>
+                  <tr>
+                    <td>Add</td>
+                    <td><input type="text" id="add1" name="add1" value="[% add1 %]" /></td>
+                    <td><input type="text" id="add2" name="add2" value="[% add2 %]" /></td>
+                    <td><input type="text" id="add3" name="add3" value="[% add3 %]" /></td>
+                  </tr>
+                  <tr>
+                    <td>Every</td>
+                    <td><input type="text" id="every1" name="every1" value="[% every1 %]" /></td>
+                    <td><input type="text" id="every2" name="every2" value="[% every2 %]" /></td>
+                    <td><input type="text" id="every3" name="every3" value="[% every3 %]" /></td>
+                  </tr>
+                  <tr>
+                    <td>Set back to</td>
+                    <td><input type="text" id="setto1" name="setto1" value="[% setto1 %]" /></td>
+                    <td><input type="text" id="setto2" name="setto2" value="[% setto2 %]" /></td>
+                    <td><input type="text" id="setto3" name="setto3" value="[% setto3 %]" /></td>
+                  </tr>
+                  <tr>
+                    <td>When more than</td>
+                    <td><input type="text" id="whenmorethan1" name="whenmorethan1" value="[% whenmorethan1 %]" /></td>
+                    <td><input type="text" id="whenmorethan2" name="whenmorethan2" value="[% whenmorethan2 %]" /></td>
+                    <td><input type="text" id="whenmorethan3" name="whenmorethan3" value="[% whenmorethan3 %]" /></td>
+                  </tr>
+                  <tr>
+                    [% BLOCK numbering_select %]
+                      <select id="[% name %]" name="[% name %]" />
+                        <option value=""></option>
+                        [% IF (value == "dayname") %]
+                            <option selected="selected" value="dayname">Name of day</option>
+                        [% ELSE %]
+                            <option value="dayname">Name of day</option>
+                        [% END %]
+                        [% IF (value == "monthname") %]
+                            <option selected="selected" value="monthname">Name of month</option>
+                        [% ELSE %]
+                            <option value="monthname">Name of month</option>
+                        [% END %]
+                        [% IF (value == "season") %]
+                            <option selected="selected" value="season">Name of season</option>
+                        [% ELSE %]
+                            <option value="season">Name of season</option>
+                        [% END %]
+                      </select>
+                    [% END %]
+                    <td>Fromatting</td>
+                    <td>[% PROCESS numbering_select name="numbering1" value=numbering1 %]</td>
+                    <td>[% PROCESS numbering_select name="numbering2" value=numbering2 %]</td>
+                    <td>[% PROCESS numbering_select name="numbering3" value=numbering3 %]</td>
+                  </tr>
+                </tbody>
+              </table>
+            </fieldset>
+            <fieldset class="action">
+              <input type="submit" value="Save" />
+              <input type="reset" value="Reset" />
+              <input type="button" value="Cancel" onclick="window.location = '/cgi-bin/koha/serials/subscription-numberpatterns.pl';" />
+            </fieldset>
+          </form>
+        </div>
+        <div class="yui-g">
+          <form>
+            <fieldset class="rows">
+              <legend>Test prediction pattern</legend>
+              <ol>
+                <li>
+                  <label for="frequency">Frequency:</label>
+                  <select id="frequency">
+                    [% FOREACH frequency IN frequencies_loop %]
+                      <option value="[% frequency.id %]">[% frequency.description %]</option>
+                    [% END %]
+                  </select>
+                </li>
+                <li>
+                  <label for="firstacquidate">First issue publication date</label>
+                  <input type="text" id="firstacquidate" class="datepicker" size="10" />
+                </li>
+                <li>
+                  <label for="sublength">Subscription length:</label>
+                  <select id="subtype">
+                    [% FOREACH subtype IN subtypes_loop %]
+                      <option value="[% subtype.value %]">[% subtype.value %]</option>
+                    [% END %]
+                  </select>
+                  <input type="text" id="sublength" size="3" />
+                </li>
+                <li>
+                  <label for="locale">Locale:</label>
+                  <select id="locale" name="locale">
+                      <option value=""></option>
+                      [% FOREACH locale IN locales %]
+                        <option value="[% locale %]">[% locale %]</option>
+                      [% END %]
+                    </select>
+                  <span class="hint">If empty, system locale is used</span>
+                </li>
+              </ol>
+              <table>
+                <thead>
+                  <tr>
+                    <th>&nbsp;</th>
+                    <th>X</th>
+                    <th>Y</th>
+                    <th>Z</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  <tr>
+                    <td>Begins with</td>
+                    <td><input type="text" id="lastvalue1" name="lastvalue1" value="[% lastvalue1 %]" /></td>
+                    <td><input type="text" id="lastvalue2" name="lastvalue2" value="[% lastvalue2 %]" /></td>
+                    <td><input type="text" id="lastvalue3" name="lastvalue3" value="[% lastvalue3 %]" /></td>
+                  </tr>
+                  <tr>
+                    <td>Inner counter</td>
+                    <td><input type="text" id="innerloop1" name="innerloop1" value="[% innerloop1 %]" /></td>
+                    <td><input type="text" id="innerloop2" name="innerloop2" value="[% innerloop2 %]" /></td>
+                    <td><input type="text" id="innerloop3" name="innerloop3" value="[% innerloop3 %]" /></td>
+                  </tr>
+                </tbody>
+              </table>
+              <fieldset class="action">
+              <input type="button" value="Test pattern" onclick="testPattern();" />
+              </fieldset>
+              <div id="predictionpattern"></div>
+            </fieldset>
+          </form>
+        </div>
+      [% ELSE %]
+        <h1>Number patterns</h1>
+        [% IF still_used %]
+            <div class="dialog">
+                <p>
+                    This pattern is still used by [% subscriptions.size %]
+                    subscription(s). Do you still want to delete it?
+                </p>
+                <p><a href="#" onclick="show_blocking_subs(); return false;">Show subscriptions</a></p>
+                <ul id="blocking_subs" style="display:none">
+                    [% FOREACH sub IN subscriptions %]
+                        <li style="list-style-type:none">
+                            <a href="/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=[% sub.subscriptionid %]">[% sub.title %]</a>
+                        </li>
+                    [% END %]
+                </ul>
+
+                <form action="" method="get">
+                    <input type="hidden" name="op" value="del" />
+                    <input type="hidden" name="confirm" value="1" />
+                    <input type="hidden" name="id" value="[% id %]" />
+                    <input type="submit" class="approve" value="Yes, delete" />
+                </form>
+                <form action="" method="get">
+                    <input type="submit" class="deny" value="No, don't delete" />
+                </form>
+            </div>
+        [% END %]
+        <a href="/cgi-bin/koha/serials/subscription-numberpatterns.pl?op=new">New numbering pattern</a>
+        [% IF (numberpatterns_loop.size) %]
+          <table id="numberpatternst">
+            <thead>
+              <tr>
+                <th>Name</th>
+                <th>Description</th>
+                <th>Numbering formula</th>
+                <th>Display order</th>
+                <th>&nbsp;</th>
+              </tr>
+            </thead>
+            <tbody>
+              [% FOREACH numberpattern IN numberpatterns_loop %]
+                <tr>
+                  <td>[% numberpattern.label %]</td>
+                  <td>[% numberpattern.description %]</td>
+                  <td>[% numberpattern.numberingmethod %]</td>
+                  <td>[% numberpattern.displayorder %]</td>
+                  <td>
+                    <a href="/cgi-bin/koha/serials/subscription-numberpatterns.pl?op=modify&id=[% numberpattern.id %]">Edit</a> |
+                    <a href="/cgi-bin/koha/serials/subscription-numberpatterns.pl?op=del&id=[% numberpattern.id %]">Delete</a>
+                  </td>
+                </tr>
+              [% END %]
+            </tbody>
+          </table>
+        [% ELSE %]
+          <p>There is no existing patterns.</p>
+        [% END %]
+      [% END %]
+    </div>
+  </div>
+  <div class="yui-b">
+    [% INCLUDE 'serials-menu.inc' %]
+  </div>
+</div>
+[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/serials/create-numberpattern.pl b/serials/create-numberpattern.pl
new file mode 100755 (executable)
index 0000000..d5e6abf
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+use CGI;
+use C4::Context;
+use C4::Serials::Numberpattern;
+use URI::Escape;
+use strict;
+use warnings;
+
+my $input = new CGI;
+
+my $numberpattern;
+foreach (qw/ numberingmethod label1 label2 label3 add1 add2 add3
+  every1 every2 every3 setto1 setto2 setto3 whenmorethan1 whenmorethan2
+  whenmorethan3 numbering1 numbering2 numbering3 locale /) {
+    $numberpattern->{$_} = $input->param($_);
+}
+# patternname is label in database
+$numberpattern->{'label'} = $input->param('patternname');
+
+# Check if pattern already exist in database
+my $dbh = C4::Context->dbh;
+my $query = qq{
+    SELECT id
+    FROM subscription_numberpatterns
+    WHERE STRCMP(label, ?) = 0
+};
+my $sth = $dbh->prepare($query);
+my $rv = $sth->execute($numberpattern->{'label'});
+my $numberpatternid;
+if($rv == 0) {
+    # Pattern does not exists
+    $numberpatternid = AddSubscriptionNumberpattern($numberpattern);
+} else {
+    ($numberpatternid) = $sth->fetchrow_array;
+    $numberpattern->{'id'} = $numberpatternid;
+    ModSubscriptionNumberpattern($numberpattern);
+}
+
+binmode STDOUT, ":utf8";
+print $input->header(-type => 'text/plain', -charset => 'UTF-8');
+print "{\"numberpatternid\":\"$numberpatternid\"}";
index ad57e07..cdeb6eb 100755 (executable)
@@ -109,9 +109,6 @@ if (@subscriptionid){
     $subs->{missinglist}  =~ s/\n/\<br\/\>/g;
     $subs->{recievedlist} =~ s/\n/\<br\/\>/g;
     ##these are display information
-    $subs->{ "periodicity" . $subs->{periodicity} } = 1;
-    $subs->{ "numberpattern" . $subs->{numberpattern} } = 1;
-    $subs->{ "status" . $subs->{'status'} } = 1;
     $subs->{startdate}     = format_date( $subs->{startdate} );
     $subs->{histstartdate} = format_date( $subs->{histstartdate} );
     if ( !defined $subs->{enddate} || $subs->{enddate} eq '0000-00-00' ) {
@@ -125,6 +122,10 @@ if (@subscriptionid){
     $subs->{'subscriptionid'} = $subscriptionid;  # FIXME - why was this lost ?
        $location = GetAuthorisedValues('LOC', $subs->{'location'});
        $callnumber = $subs->{callnumber};
+    my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subs->{periodicity});
+    my $numberpattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subs->{numberpattern});
+    $subs->{frequency} = $frequency;
+    $subs->{numberpattern} = $numberpattern;
     push @$subscriptiondescs,$subs;
     my $tmpsubscription= GetFullSubscription($subscriptionid);
     @subscriptioninformation=(@$tmpsubscription,@subscriptioninformation);
@@ -154,6 +155,7 @@ foreach (@$location) {
     $locationlib = $_->{'lib'} if $_->{'selected'};
 }
 
+
 chop $subscriptionidlist;
 $template->param(
           subscriptionidlist => $subscriptionidlist,
index 770d10d..c14e4d0 100755 (executable)
@@ -192,10 +192,7 @@ for(my $i=0;$i<$count;$i++){
     $serialslist[$i]->{'barcode'} = "TEMP" . sprintf("%.0f",$temp);
 }
 
-my $sth= C4::Serials::GetSubscriptionHistoryFromSubscriptionId();
-
-$sth->execute($subscriptionid);
-my $solhistory = $sth->fetchrow_hashref;
+my $solhistory = GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
 
 $subs = &GetSubscription($subscriptionid);
 ($totalissues,@serialslist) = GetSerials($subscriptionid);
@@ -253,9 +250,7 @@ if (C4::Context->preference("serialsadditems")){
     $template->param(branchloop=>[],itemstatusloop=>[],itemlocationloop=>[]) ;
 }
 
-$sth= C4::Serials::GetSubscriptionHistoryFromSubscriptionId();
-$sth->execute($subscriptionid);
-$solhistory = $sth->fetchrow_hashref;
+$solhistory = GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
 
 $template->param(
             user => $auser,
diff --git a/serials/showpredictionpattern.pl b/serials/showpredictionpattern.pl
new file mode 100755 (executable)
index 0000000..e56695c
--- /dev/null
@@ -0,0 +1,194 @@
+#!/usr/bin/perl
+
+# Copyright 2011 BibLibre SARL
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+=head1 NAME
+
+showpredictionpattern.pl
+
+=head1 DESCRIPTION
+
+This script calculate numbering of serials based on numbering pattern, and
+publication date, based on frequency and first publication date.
+
+=cut
+
+use Modern::Perl;
+
+use CGI;
+use Date::Calc qw(Today Day_of_Year Week_of_Year Day_of_Week Days_in_Year Delta_Days Add_Delta_Days Add_Delta_YM);
+use C4::Auth;
+use C4::Output;
+use C4::Serials;
+use C4::Serials::Frequency;
+
+my $input = new CGI;
+my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user( {
+    template_name   => 'serials/showpredictionpattern.tt',
+    query           => $input,
+    type            => 'intranet',
+    authnotrequired => 0,
+    flagsrequired   => { 'serials' => '*' },
+} );
+
+my $subscriptionid = $input->param('subscriptionid');
+my $frequencyid = $input->param('frequency');
+my $firstacquidate = $input->param('firstacquidate');
+my $nextacquidate = $input->param('nextacquidate');
+my $enddate = $input->param('enddate');
+my $subtype = $input->param('subtype');
+my $sublength = $input->param('sublength');
+my $custompattern = $input->param('custompattern');
+
+
+my %val = (
+    locale          => $input->param('locale') // '',
+    numberingmethod => $input->param('numberingmethod') // '',
+    numbering1      => $input->param('numbering1') // '',
+    numbering2      => $input->param('numbering2') // '',
+    numbering3      => $input->param('numbering3') // '',
+    lastvalue1      => $input->param('lastvalue1') // '',
+    lastvalue2      => $input->param('lastvalue2') // '',
+    lastvalue3      => $input->param('lastvalue3') // '',
+    add1            => $input->param('add1') // '',
+    add2            => $input->param('add2') // '',
+    add3            => $input->param('add3') // '',
+    whenmorethan1   => $input->param('whenmorethan1') // '',
+    whenmorethan2   => $input->param('whenmorethan2') // '',
+    whenmorethan3   => $input->param('whenmorethan3') // '',
+    setto1          => $input->param('setto1') // '',
+    setto2          => $input->param('setto2') // '',
+    setto3          => $input->param('setto3') // '',
+    every1          => $input->param('every1') // '',
+    every2          => $input->param('every2') // '',
+    every3          => $input->param('every3') // '',
+    innerloop1      => $input->param('innerloop1') // '',
+    innerloop2      => $input->param('innerloop2') // '',
+    innerloop3      => $input->param('innerloop3') // '',
+);
+
+if(!defined $firstacquidate || $firstacquidate eq ''){
+    my ($year, $month, $day) = Today();
+    $firstacquidate = sprintf "%04d-%02d-%02d", $year, $month, $day;
+} else {
+    $firstacquidate = C4::Dates->new($firstacquidate)->output('iso');
+}
+
+if($enddate){
+    $enddate = C4::Dates->new($enddate)->output('iso');
+}
+
+if($nextacquidate) {
+    $nextacquidate = C4::Dates->new($nextacquidate)->output('iso');
+} else {
+    $nextacquidate = $firstacquidate;
+}
+my $date = $nextacquidate;
+
+my %subscription = (
+    irregularity    => '',
+    periodicity     => $frequencyid,
+    countissuesperunit  => 1,
+    firstacquidate  => $firstacquidate,
+);
+
+my $issuenumber;
+if(defined $subscriptionid) {
+    ($issuenumber) = C4::Serials::GetFictiveIssueNumber(\%subscription, $date);
+} else {
+    $issuenumber = 1;
+}
+
+my @predictions_loop;
+my ($calculated) = GetSeq(\%val);
+push @predictions_loop, {
+    number => $calculated,
+    publicationdate => $date,
+    issuenumber => $issuenumber,
+    dow => Day_of_Week(split /-/, $date),
+};
+my @irreg = ();
+if(defined $subscriptionid) {
+    @irreg = C4::Serials::GetSubscriptionIrregularities($subscriptionid);
+    while(@irreg && $issuenumber > $irreg[0]) {
+        shift @irreg;
+    }
+    if(@irreg && $issuenumber == $irreg[0]){
+        $predictions_loop[0]->{'not_published'} = 1;
+        shift @irreg;
+    }
+}
+
+my $i = 1;
+while( $i < 1000 ) {
+    my %line;
+
+    if(defined $date){
+        $date = GetNextDate(\%subscription, $date);
+    }
+    if(defined $date){
+        $line{'publicationdate'} = $date;
+        $line{'dow'} = Day_of_Week(split /-/, $date);
+    }
+
+    # Check if we don't have exceed end date
+    if($sublength){
+        if($subtype eq "issues" && $i >= $sublength){
+            last;
+        } elsif($subtype eq "weeks" && $date && Delta_Days( split(/-/, $date), Add_Delta_Days( split(/-/, $firstacquidate), 7*$sublength - 1 ) ) < 0) {
+            last;
+        } elsif($subtype eq "months" && $date && (Delta_Days( split(/-/, $date), Add_Delta_YM( split(/-/, $firstacquidate), 0, $sublength) ) - 1) < 0 ) {
+            last;
+        }
+    }
+    if($enddate && $date && Delta_Days( split(/-/, $date), split(/-/, $enddate) ) <= 0 ) {
+        last;
+    }
+
+    ($calculated, $val{'lastvalue1'}, $val{'lastvalue2'}, $val{'lastvalue3'}, $val{'innerloop1'}, $val{'innerloop2'}, $val{'innerloop3'}) = GetNextSeq(\%val);
+    $issuenumber++;
+    $line{'number'} = $calculated;
+    $line{'issuenumber'} = $issuenumber;
+    if(@irreg && $issuenumber == $irreg[0]){
+        $line{'not_published'} = 1;
+        shift @irreg;
+    }
+    push @predictions_loop, \%line;
+
+    $i++;
+}
+
+$template->param(
+    predictions_loop => \@predictions_loop,
+);
+
+my $frequency = GetSubscriptionFrequency($frequencyid);
+
+if ( $frequency->{unit} and not $custompattern ) {
+    $template->param( ask_for_irregularities => 1 );
+    if ( $frequency->{unit} eq 'day' and $frequency->{unitsperissue} == 1 ) {
+        $template->param( daily_options => 1 );
+    }
+}
+
+if (   ( $date && $enddate && $date ne $enddate )
+    or ( $subtype eq 'issues' && $i < $sublength ) )
+{
+    $template->param( not_consistent_end_date => 1 );
+}
+
+output_html_with_http_headers $input, $cookie, $template->output;
index 10bccd1..fd338b0 100755 (executable)
@@ -19,7 +19,7 @@ use strict;
 use warnings;
 
 use CGI;
-use Date::Calc qw(Today Day_of_Year Week_of_Year Add_Delta_Days);
+use Date::Calc qw(Today Day_of_Year Week_of_Year Add_Delta_Days Add_Delta_YM);
 use C4::Koha;
 use C4::Biblio;
 use C4::Auth;
@@ -29,6 +29,8 @@ use C4::Output;
 use C4::Context;
 use C4::Branch; # GetBranches
 use C4::Serials;
+use C4::Serials::Frequency;
+use C4::Serials::Numberpattern;
 use C4::Letters;
 use Carp;
 
@@ -46,7 +48,7 @@ my @budgets;
 my $permission = ($op eq "modify") ? "edit_subscription" : "create_subscription";
 
 my ($template, $loggedinuser, $cookie)
-= get_template_and_user({template_name => "serials/subscription-add.tmpl",
+= get_template_and_user({template_name => "serials/subscription-add.tt",
                                query => $query,
                                type => "intranet",
                                authnotrequired => 0,
@@ -57,9 +59,7 @@ my ($template, $loggedinuser, $cookie)
 
 
 my $sub_on;
-my @subscription_types = (
-            'issues', 'weeks', 'months'
-        );
+my @subscription_types = (qw(issues weeks months));
 my @sub_type_data;
 
 my $subs;
@@ -81,7 +81,7 @@ if ($op eq 'modify' || $op eq 'dup' || $op eq 'modsubscription') {
          if ($subs->{$_} eq '0000-00-00') {
             $subs->{$_} = ''
        } else {
-            $subs->{$_} = format_date($subs->{$_});
+            $subs->{$_} = $subs->{$_};
         }
          }
       if (!defined $subs->{letter}) {
@@ -89,28 +89,32 @@ if ($op eq 'modify' || $op eq 'dup' || $op eq 'modsubscription') {
       }
     letter_loop($subs->{'letter'}, $template);
     my $nextexpected = GetNextExpected($subscriptionid);
-    $nextexpected->{'isfirstissue'} = $nextexpected->{planneddate}->output('iso') eq $firstissuedate ;
-    $subs->{nextacquidate} = $nextexpected->{planneddate}->output()  if($op eq 'modify');
+    $nextexpected->{'isfirstissue'} = $nextexpected->{planneddate} eq $firstissuedate ;
+    $subs->{nextacquidate} = $nextexpected->{planneddate}  if($op eq 'modify');
     unless($op eq 'modsubscription') {
         foreach my $length_unit (qw(numberlength weeklength monthlength)) {
-                       if ($subs->{$length_unit}){
-                               $sub_length=$subs->{$length_unit};
-                               $sub_on=$length_unit;
-                               last;
-                       }
-               }
+            if ($subs->{$length_unit}) {
+                $sub_length=$subs->{$length_unit};
+                $sub_on=$length_unit;
+                last;
+            }
+        }
 
         $template->param( %{$subs} );
-        $template->param("dow".$subs->{'dow'} => 1) if defined $subs->{'dow'};
         $template->param(
                     $op => 1,
                     "subtype_$sub_on" => 1,
                     sublength =>$sub_length,
                     history => ($op eq 'modify'),
-                    "periodicity".$subs->{'periodicity'} => 1,
-                    "numberpattern".$subs->{'numberpattern'} => 1,
                     firstacquiyear => substr($firstissuedate,0,4),
                     );
+
+        if($op eq 'modify') {
+            my ($serials_number) = GetSerials($subscriptionid);
+            if($serials_number > 1) {
+                $template->param(more_than_one_serial => 1);
+            }
+        }
     }
 
     if ( $op eq 'dup' ) {
@@ -173,8 +177,48 @@ if ($op eq 'addsubscription') {
             $template->param(bibliotitle => $bib->{title});
         }
     }
-        $template->param((uc(C4::Context->preference("marcflavour"))) => 1);
-       output_html_with_http_headers $query, $cookie, $template->output;
+
+    $template->param((uc(C4::Context->preference("marcflavour"))) => 1);
+
+    my @frequencies = GetSubscriptionFrequencies;
+    my @frqloop;
+    foreach my $freq (@frequencies) {
+        my $selected = 0;
+        $selected = 1 if ($subs->{periodicity} and $freq->{id} eq $subs->{periodicity});
+        my $row = {
+            id => $freq->{'id'},
+            selected => $selected,
+            label => $freq->{'description'},
+        };
+        push @frqloop, $row;
+    }
+    $template->param(frequencies => \@frqloop);
+
+    my @numpatterns = GetSubscriptionNumberpatterns;
+    my @numberpatternloop;
+    foreach my $numpattern (@numpatterns) {
+        my $selected = 0;
+        $selected = 1 if($subs->{numberpattern} and $numpattern->{id} eq $subs->{numberpattern});
+        my $row = {
+            id => $numpattern->{'id'},
+            selected => $selected,
+            label => $numpattern->{'label'},
+        };
+        push @numberpatternloop, $row;
+    }
+    $template->param(numberpatterns => \@numberpatternloop);
+
+    # Get installed locales
+    # FIXME this will not work with all environments.
+    # If call to locale fails, @locales will be an empty array, which is fine.
+    my @locales = map {
+        chomp;
+        # we don't want POSIX and C locales
+        /^C|^POSIX$/ ? () : $_
+    } `locale -a`;
+    $template->param(locales => \@locales);
+
+    output_html_with_http_headers $query, $cookie, $template->output;
 }
 
 sub letter_loop {
@@ -196,76 +240,96 @@ sub _get_sub_length {
     my ($type, $length) = @_;
     return
         (
-            $type eq 'numberlength' ? $length : 0,
-            $type eq 'weeklength'   ? $length : 0,
-            $type eq 'monthlength'  ? $length : 0,
+            $type eq 'issues' ? $length : 0,
+            $type eq 'weeks'   ? $length : 0,
+            $type eq 'months'  ? $length : 0,
         );
 }
 
+sub _guess_enddate {
+    my ($startdate_iso, $frequencyid, $numberlength, $weeklength, $monthlength) = @_;
+    my ($year, $month, $day);
+    my $enddate;
+    if($numberlength != 0) {
+        my $frequency = GetSubscriptionFrequency($frequencyid);
+        if($frequency->{'unit'} eq 'day') {
+            ($year, $month, $day) = Add_Delta_Days(split(/-/, $startdate_iso), $numberlength * $frequency->{'unitsperissue'} / $frequency->{'issuesperunit'});
+        } elsif($frequency->{'unit'} eq 'week') {
+            ($year, $month, $day) = Add_Delta_Days(split(/-/, $startdate_iso), $numberlength * 7 * $frequency->{'unitsperissue'} / $frequency->{'issuesperunit'});
+        } elsif($frequency->{'unit'} eq 'month') {
+            ($year, $month, $day) = Add_Delta_YM(split(/-/, $startdate_iso), 0, $numberlength * $frequency->{'unitsperissue'} / $frequency->{'issuesperunit'});
+        } elsif($frequency->{'unit'} eq 'year') {
+            ($year, $month, $day) = Add_Delta_YM(split(/-/, $startdate_iso), $numberlength * $frequency->{'unitsperissue'} / $frequency->{'issuesperunit'}, 0);
+        }
+    } elsif($weeklength != 0) {
+        ($year, $month, $day) = Add_Delta_Days(split(/-/, $startdate_iso), $weeklength * 7);
+    } elsif($monthlength != 0) {
+        ($year, $month, $day) = Add_Delta_YM(split(/-/, $startdate_iso), 0, $monthlength);
+    }
+    if(defined $year) {
+        $enddate = sprintf("%04d-%02d-%02d", $year, $month, $day);
+    } else {
+        undef $enddate;
+    }
+    return $enddate;
+}
+
 sub redirect_add_subscription {
     my $auser          = $query->param('user');
     my $branchcode     = $query->param('branchcode');
     my $aqbooksellerid = $query->param('aqbooksellerid');
     my $cost           = $query->param('cost');
     my $aqbudgetid     = $query->param('aqbudgetid');
-    my $periodicity    = $query->param('periodicity');
-    my $dow            = $query->param('dow');
-    my @irregularity   = $query->param('irregularity_select');
+    my $periodicity    = $query->param('frequency');
+    my @irregularity   = $query->param('irregularity');
     my $numberpattern  = $query->param('numbering_pattern');
+    my $locale         = $query->param('locale');
     my $graceperiod    = $query->param('graceperiod') || 0;
 
+    my $subtype = $query->param('subtype');
+    my $sublength = $query->param('sublength');
     my ( $numberlength, $weeklength, $monthlength )
-        = _get_sub_length( $query->param('subtype'), $query->param('sublength') );
+        = _get_sub_length( $subtype, $sublength );
     my $add1              = $query->param('add1');
-    my $every1            = $query->param('every1');
-    my $whenmorethan1     = $query->param('whenmorethan1');
-    my $setto1            = $query->param('setto1');
     my $lastvalue1        = $query->param('lastvalue1');
     my $innerloop1        = $query->param('innerloop1');
-    my $add2              = $query->param('add2');
-    my $every2            = $query->param('every2');
-    my $whenmorethan2     = $query->param('whenmorethan2');
-    my $setto2            = $query->param('setto2');
     my $innerloop2        = $query->param('innerloop2');
     my $lastvalue2        = $query->param('lastvalue2');
-    my $add3              = $query->param('add3');
-    my $every3            = $query->param('every3');
-    my $whenmorethan3     = $query->param('whenmorethan3');
-    my $setto3            = $query->param('setto3');
     my $lastvalue3        = $query->param('lastvalue3');
     my $innerloop3        = $query->param('innerloop3');
-    my $numberingmethod   = $query->param('numberingmethod');
     my $status            = 1;
     my $biblionumber      = $query->param('biblionumber');
     my $callnumber        = $query->param('callnumber');
     my $notes             = $query->param('notes');
     my $internalnotes     = $query->param('internalnotes');
-    my $hemisphere        = $query->param('hemisphere') || 1;
     my $letter            = $query->param('letter');
-    my $manualhistory     = $query->param('manualhist');
+    my $manualhistory     = $query->param('manualhist') ? 1 : 0;
     my $serialsadditems   = $query->param('serialsadditems');
     my $staffdisplaycount = $query->param('staffdisplaycount');
     my $opacdisplaycount  = $query->param('opacdisplaycount');
     my $location          = $query->param('location');
+    my $skip_serialseq    = $query->param('skip_serialseq');
     my $startdate = format_date_in_iso( $query->param('startdate') );
     my $enddate = format_date_in_iso( $query->param('enddate') );
     my $firstacquidate  = format_date_in_iso($query->param('firstacquidate'));
-    my $histenddate = format_date_in_iso($query->param('histenddate'));
-    my $histstartdate = format_date_in_iso($query->param('histstartdate'));
-    my $recievedlist = $query->param('recievedlist');
-    my $missinglist = $query->param('missinglist');
-    my $opacnote = $query->param('opacnote');
-    my $librariannote = $query->param('librariannote');
-       my $subscriptionid = NewSubscription($auser,$branchcode,$aqbooksellerid,$cost,$aqbudgetid,$biblionumber,
-                                       $startdate,$periodicity,$dow,$numberlength,$weeklength,$monthlength,
-                                       $add1,$every1,$whenmorethan1,$setto1,$lastvalue1,$innerloop1,
-                                       $add2,$every2,$whenmorethan2,$setto2,$lastvalue2,$innerloop2,
-                                       $add3,$every3,$whenmorethan3,$setto3,$lastvalue3,$innerloop3,
-                                       $numberingmethod, $status, $notes,$letter,$firstacquidate,join(",",@irregularity),
-                    $numberpattern, $callnumber, $hemisphere,($manualhistory?$manualhistory:0),$internalnotes,
-                    $serialsadditems,$staffdisplaycount,$opacdisplaycount,$graceperiod,$location,$enddate
-                               );
-    ModSubscriptionHistory ($subscriptionid,$histstartdate,$histenddate,$recievedlist,$missinglist,$opacnote,$librariannote);
+    if(!defined $enddate || $enddate eq '') {
+        if($subtype eq "issues") {
+            $enddate = _guess_enddate($firstacquidate, $periodicity, $numberlength, $weeklength, $monthlength);
+        } else {
+            $enddate = _guess_enddate($startdate, $periodicity, $numberlength, $weeklength, $monthlength);
+        }
+    }
+
+    my $subscriptionid = NewSubscription(
+        $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $biblionumber,
+        $startdate, $periodicity, $numberlength, $weeklength,
+        $monthlength, $lastvalue1, $innerloop1, $lastvalue2, $innerloop2,
+        $lastvalue3, $innerloop3, $status, $notes, $letter, $firstacquidate,
+        join(";",@irregularity), $numberpattern, $locale, $callnumber,
+        $manualhistory, $internalnotes, $serialsadditems,
+        $staffdisplaycount, $opacdisplaycount, $graceperiod, $location, $enddate,
+        $skip_serialseq
+    );
 
     print $query->redirect("/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=$subscriptionid");
     return;
@@ -273,7 +337,7 @@ sub redirect_add_subscription {
 
 sub redirect_mod_subscription {
     my $subscriptionid = $query->param('subscriptionid');
-         my @irregularity = $query->param('irregularity_select');
+    my @irregularity = $query->param('irregularity');
     my $auser = $query->param('user');
     my $librarian => $query->param('librarian'),
     my $branchcode = $query->param('branchcode');
@@ -282,76 +346,66 @@ sub redirect_mod_subscription {
     my $biblionumber = $query->param('biblionumber');
     my $aqbudgetid = $query->param('aqbudgetid');
     my $startdate = format_date_in_iso($query->param('startdate'));
+    my $firstacquidate = format_date_in_iso( $query->param('firstacquidate') );
     my $nextacquidate = $query->param('nextacquidate') ?
                             format_date_in_iso($query->param('nextacquidate')):
-                            format_date_in_iso($query->param('startdate'));
+                            $firstacquidate;
     my $enddate = format_date_in_iso($query->param('enddate'));
-    my $periodicity = $query->param('periodicity');
-    my $dow = $query->param('dow');
+    my $periodicity = $query->param('frequency');
 
+    my $subtype = $query->param('subtype');
+    my $sublength = $query->param('sublength');
     my ($numberlength, $weeklength, $monthlength)
-        = _get_sub_length( $query->param('subtype'), $query->param('sublength') );
+        = _get_sub_length( $subtype, $sublength );
     my $numberpattern = $query->param('numbering_pattern');
-    my $add1 = $query->param('add1');
-    my $every1 = $query->param('every1');
-    my $whenmorethan1 = $query->param('whenmorethan1');
-    my $setto1 = $query->param('setto1');
+    my $locale = $query->param('locale');
     my $lastvalue1 = $query->param('lastvalue1');
     my $innerloop1 = $query->param('innerloop1');
-    my $add2 = $query->param('add2');
-    my $every2 = $query->param('every2');
-    my $whenmorethan2 = $query->param('whenmorethan2');
-    my $setto2 = $query->param('setto2');
     my $lastvalue2 = $query->param('lastvalue2');
     my $innerloop2 = $query->param('innerloop2');
-    my $add3 = $query->param('add3');
-    my $every3 = $query->param('every3');
-    my $whenmorethan3 = $query->param('whenmorethan3');
-    my $setto3 = $query->param('setto3');
     my $lastvalue3 = $query->param('lastvalue3');
     my $innerloop3 = $query->param('innerloop3');
-    my $numberingmethod = $query->param('numberingmethod');
     my $status = 1;
     my $callnumber = $query->param('callnumber');
     my $notes = $query->param('notes');
     my $internalnotes = $query->param('internalnotes');
-    my $hemisphere = $query->param('hemisphere');
     my $letter = $query->param('letter');
-    my $manualhistory = $query->param('manualhist');
+    my $manualhistory = $query->param('manualhist') ? 1 : 0;
     my $serialsadditems = $query->param('serialsadditems');
-    # subscription history
-    my $histenddate = format_date_in_iso($query->param('histenddate'));
-    my $histstartdate = format_date_in_iso($query->param('histstartdate'));
-    my $recievedlist = $query->param('recievedlist');
-    my $missinglist = $query->param('missinglist');
-    my $opacnote = $query->param('opacnote');
-    my $librariannote = $query->param('librariannote');
        my $staffdisplaycount = $query->param('staffdisplaycount');
        my $opacdisplaycount = $query->param('opacdisplaycount');
     my $graceperiod     = $query->param('graceperiod') || 0;
     my $location = $query->param('location');
+    my $skip_serialseq    = $query->param('skip_serialseq');
+
+    # Guess end date
+    if(!defined $enddate || $enddate eq '') {
+        if($subtype eq "issues") {
+            $enddate = _guess_enddate($nextacquidate, $periodicity, $numberlength, $weeklength, $monthlength);
+        } else {
+            $enddate = _guess_enddate($startdate, $periodicity, $numberlength, $weeklength, $monthlength);
+        }
+    }
+
     my $nextexpected = GetNextExpected($subscriptionid);
-       #  If it's  a mod, we need to check the current 'expected' issue, and mod it in the serials table if necessary.
-    if ( $nextacquidate ne $nextexpected->{planneddate}->output('iso') ) {
-        ModNextExpected($subscriptionid,C4::Dates->new($nextacquidate,'iso'));
+    #  If it's  a mod, we need to check the current 'expected' issue, and mod it in the serials table if necessary.
+    if ( $nextexpected->{planneddate} && $nextacquidate ne $nextexpected->{planneddate} ) {
+        ModNextExpected($subscriptionid, $nextacquidate);
         # if we have not received any issues yet, then we also must change the firstacquidate for the subs.
         $firstissuedate = $nextacquidate if($nextexpected->{isfirstissue});
     }
 
-        ModSubscription(
-            $auser,           $branchcode,   $aqbooksellerid, $cost,
-            $aqbudgetid,      $startdate,    $periodicity,    $firstissuedate,
-            $dow,             join(q{,},@irregularity), $numberpattern,  $numberlength,
-            $weeklength,      $monthlength,  $add1,           $every1,
-            $whenmorethan1,   $setto1,       $lastvalue1,     $innerloop1,
-            $add2,            $every2,       $whenmorethan2,  $setto2,
-            $lastvalue2,      $innerloop2,   $add3,           $every3,
-            $whenmorethan3,   $setto3,       $lastvalue3,     $innerloop3,
-            $numberingmethod, $status,       $biblionumber,   $callnumber,
-            $notes,           $letter,       $hemisphere,     $manualhistory,$internalnotes,
-            $serialsadditems, $staffdisplaycount,$opacdisplaycount,$graceperiod,$location,$enddate,$subscriptionid
-        );
-        ModSubscriptionHistory ($subscriptionid,$histstartdate,$histenddate,$recievedlist,$missinglist,$opacnote,$librariannote);
+    ModSubscription(
+        $auser, $branchcode, $aqbooksellerid, $cost, $aqbudgetid, $startdate,
+        $periodicity, $firstacquidate, join(";",@irregularity),
+        $numberpattern, $locale, $numberlength, $weeklength, $monthlength, $lastvalue1,
+        $innerloop1, $lastvalue2, $innerloop2, $lastvalue3, $innerloop3,
+        $status, $biblionumber, $callnumber, $notes, $letter,
+        $manualhistory, $internalnotes, $serialsadditems, $staffdisplaycount,
+        $opacdisplaycount, $graceperiod, $location, $enddate, $subscriptionid,
+        $skip_serialseq
+    );
+
     print $query->redirect("/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=$subscriptionid");
     return;
 }
index 009360b..3b36284 100755 (executable)
@@ -116,15 +116,9 @@ $template->param(%{ $subs });
 $template->param(biblionumber_for_new_subscription => $subs->{bibnum});
 my @irregular_issues = split /,/, $subs->{irregularity};
 
-if (! $subs->{numberpattern}) {
-    $subs->{numberpattern} = q{};
-}
-if (! $subs->{dow}) {
-    $subs->{dow} = q{};
-}
-if (! $subs->{periodicity}) {
-    $subs->{periodicity} = '0';
-}
+my $frequency = C4::Serials::Frequency::GetSubscriptionFrequency($subs->{periodicity});
+my $numberpattern = C4::Serials::Numberpattern::GetSubscriptionNumberpattern($subs->{numberpattern});
+
 my $default_bib_view = get_default_view();
 
 my ( $order, $bookseller, $tmpl_infos );
@@ -166,9 +160,11 @@ $template->param(
                 C4::Context->userenv->{flags} % 2 !=1  &&
                 C4::Context->userenv->{branch} && $subs->{branchcode} &&
                 (C4::Context->userenv->{branch} ne $subs->{branchcode})),
-    'periodicity' . $subs->{periodicity} => 1,
-    'arrival' . $subs->{dow} => 1,
-    'numberpattern' . $subs->{numberpattern} => 1,
+    frequency => $frequency,
+    numberpattern => $numberpattern,
+    has_X           => ($numberpattern->{'numberingmethod'} =~ /{X}/) ? 1 : 0,
+    has_Y           => ($numberpattern->{'numberingmethod'} =~ /{Y}/) ? 1 : 0,
+    has_Z           => ($numberpattern->{'numberingmethod'} =~ /{Z}/) ? 1 : 0,
     intranetstylesheet => C4::Context->preference('intranetstylesheet'),
     intranetcolorstylesheet => C4::Context->preference('intranetcolorstylesheet'),
     irregular_issues => scalar @irregular_issues,
diff --git a/serials/subscription-frequencies.pl b/serials/subscription-frequencies.pl
new file mode 100755 (executable)
index 0000000..53de1c7
--- /dev/null
@@ -0,0 +1,120 @@
+#!/usr/bin/perl
+
+# Copyright 2011 BibLibre SARL
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+=head1 NAME
+
+subscription-frequencies.pl
+
+=head1 DESCRIPTION
+
+Manage subscription frequencies
+
+=cut
+
+use Modern::Perl;
+
+use CGI;
+
+use C4::Auth;
+use C4::Output;
+use C4::Serials;
+use C4::Serials::Frequency;
+
+my $input = new CGI;
+my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user( {
+    template_name   => 'serials/subscription-frequencies.tt',
+    query           => $input,
+    type            => 'intranet',
+    authnotrequired => 0,
+    flagsrequired   => { 'parameters' => 1 },
+    debug           => 1,
+} );
+
+my $op = $input->param('op');
+
+if($op && ($op eq 'new' || $op eq 'modify')) {
+    my @units_loop;
+    push @units_loop, {val => $_} for (qw/ day week month year /);
+
+    if($op eq 'modify') {
+        my $frequencyid = $input->param('frequencyid');
+        my $frequency = GetSubscriptionFrequency($frequencyid);
+        foreach (@units_loop) {
+            if($frequency->{unit} and $_->{val} eq $frequency->{unit}) {
+                $_->{selected} = 1;
+                last;
+            }
+        }
+        $template->param( %$frequency );
+    }
+
+    $template->param(
+        units_loop => \@units_loop,
+        $op        => 1,
+    );
+    output_html_with_http_headers $input, $cookie, $template->output;
+    exit;
+}
+
+if($op && ($op eq 'savenew' || $op eq 'savemod')) {
+    my $frequency;
+    foreach (qw/ description unit issuesperunit unitsperissue displayorder /) {
+        $frequency->{$_} = $input->param($_);
+    }
+    $frequency->{unit} = undef if $frequency->{unit} eq '';
+    foreach (qw/issuesperunit unitsperissue/) {
+        $frequency->{$_} = 1 if $frequency->{$_} !~ /\d+/;
+    }
+    $frequency->{issuesperunit} = 1 if $frequency->{issuesperunit} < 1;
+    $frequency->{unitsperissue} = 1 if $frequency->{issuesperunit} != 1;
+
+    if($op eq 'savemod') {
+        $frequency->{id} = $input->param('id');
+        ModSubscriptionFrequency($frequency);
+    } else {
+        AddSubscriptionFrequency($frequency);
+    }
+} elsif($op && $op eq 'del') {
+    my $frequencyid = $input->param('frequencyid');
+
+    if ($frequencyid) {
+        my $confirm = $input->param('confirm');
+        if ($confirm) {
+            DelSubscriptionFrequency($frequencyid);
+        } else {
+            my @subs = GetSubscriptionsWithFrequency($frequencyid);
+            if (@subs) {
+                $template->param(
+                    frequencyid => $frequencyid,
+                    still_used => 1,
+                    subscriptions => \@subs
+                );
+            } else {
+                DelSubscriptionFrequency($frequencyid);
+            }
+        }
+    }
+}
+
+
+my @frequencies = GetSubscriptionFrequencies();
+
+$template->param(frequencies_loop => \@frequencies);
+$template->param($op => 1) if $op;
+
+output_html_with_http_headers $input, $cookie, $template->output;
diff --git a/serials/subscription-frequency.pl b/serials/subscription-frequency.pl
new file mode 100755 (executable)
index 0000000..965b0ff
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/perl
+
+use CGI;
+use C4::Context;
+use C4::Serials::Frequency;
+use C4::Auth qw/check_cookie_auth/;
+use URI::Escape;
+use strict;
+
+my $input=new CGI;
+my $frqid=$input->param("frequency_id");
+my ($auth_status, $sessionID) = check_cookie_auth($input->cookie('CGISESSID'), { serials => '*' });
+if ($auth_status ne "ok") {
+    exit 0;
+}
+my $frequencyrecord=GetSubscriptionFrequency($frqid);
+binmode STDOUT, ":utf8";
+print $input->header(-type => 'text/plain', -charset => 'UTF-8');
+print "{".join (",",map { "\"$_\":\"".uri_escape($frequencyrecord->{$_})."\"" }sort keys %$frequencyrecord)."}";
diff --git a/serials/subscription-history.pl b/serials/subscription-history.pl
new file mode 100755 (executable)
index 0000000..398fe4a
--- /dev/null
@@ -0,0 +1,87 @@
+#!/usr/bin/perl
+
+# Copyright 2011 BibLibre SARL
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+=head1 NAME
+
+subscription-history.pl
+
+=head1 DESCRIPTION
+
+Modify subscription history
+
+=cut
+
+use Modern::Perl;
+
+use CGI;
+use C4::Auth;
+use C4::Output;
+
+use C4::Biblio;
+use C4::Dates qw(format_date_in_iso);
+use C4::Serials;
+
+my $input = new CGI;
+my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user( {
+    template_name   => 'serials/subscription-history.tt',
+    query           => $input,
+    type            => 'intranet',
+    authnotrequired => 0,
+    flagsrequired   => { 'serials' => 'edit_subscription' },
+    debug           => 1,
+} );
+
+my $subscriptionid  = $input->param('subscriptionid');
+my $op              = $input->param('op');
+
+if(!defined $subscriptionid || $subscriptionid eq '') {
+    print $input->redirect('/cgi-bin/koha/serials/serials-home.pl');
+    exit;
+}
+
+if($op && $op eq 'mod') {
+    my $histstartdate   = $input->param('histstartdate');
+    my $histenddate     = $input->param('histenddate');
+    my $receivedlist    = $input->param('receivedlist');
+    my $missinglist     = $input->param('missinglist');
+    my $opacnote        = $input->param('opacnote');
+    my $librariannote   = $input->param('librariannote');
+
+    ModSubscriptionHistory( $subscriptionid, format_date_in_iso($histstartdate),
+        format_date_in_iso($histenddate), $receivedlist, $missinglist, $opacnote,
+        $librariannote );
+
+    print $input->redirect("/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=$subscriptionid");
+    exit;
+} else {
+    my $history = GetSubscriptionHistoryFromSubscriptionId($subscriptionid);
+    my (undef, $biblio) = GetBiblio($history->{'biblionumber'});
+
+    $template->param(
+        subscriptionid  => $subscriptionid,
+        title           => $biblio->{'title'},
+        histstartdate   => $history->{'histstartdate'},
+        histenddate     => $history->{'histenddate'},
+        receivedlist    => $history->{'recievedlist'},
+        missinglist     => $history->{'missinglist'},
+        opacnote        => $history->{'opacnote'},
+        librariannote   => $history->{'librariannote'},
+    );
+
+    output_html_with_http_headers $input, $cookie, $template->output;
+}
diff --git a/serials/subscription-numberpattern.pl b/serials/subscription-numberpattern.pl
new file mode 100755 (executable)
index 0000000..5da614e
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/perl
+
+use CGI;
+use C4::Serials::Numberpattern;
+use URI::Escape;
+use strict;
+use warnings;
+
+my $input=new CGI;
+my $numpatternid=$input->param("numberpattern_id");
+
+my $numberpatternrecord=GetSubscriptionNumberpattern($numpatternid);
+binmode STDOUT, ":utf8";
+print $input->header(-type => 'text/plain', -charset => 'UTF-8');
+print "{",join (",",map {"\"$_\":\"".(uri_escape($numberpatternrecord->{$_}) // '')."\"" }sort keys %$numberpatternrecord),"}";
diff --git a/serials/subscription-numberpatterns.pl b/serials/subscription-numberpatterns.pl
new file mode 100755 (executable)
index 0000000..2647672
--- /dev/null
@@ -0,0 +1,150 @@
+#!/usr/bin/perl
+
+# Copyright 2011 BibLibre SARL
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+=head1 NAME
+
+subscription-numberpatterns.pl
+
+=head1 DESCRIPTION
+
+Manage numbering patterns
+
+=cut
+
+use Modern::Perl;
+use CGI;
+
+use C4::Auth;
+use C4::Output;
+use C4::Serials::Numberpattern;
+use C4::Serials::Frequency;
+
+my $input = new CGI;
+my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user( {
+    template_name   => 'serials/subscription-numberpatterns.tt',
+    query           => $input,
+    type            => 'intranet',
+    authnotrequired => 0,
+    flagsrequired   => { 'parameters' => 1 }
+} );
+
+my $op = $input->param('op');
+
+if($op && $op eq 'savenew') {
+    my $label = $input->param('label');
+    my $numberpattern;
+    foreach(qw/ label description numberingmethod displayorder
+      label1 label2 label3 add1 add2 add3 every1 every2 every3
+      setto1 setto2 setto3 whenmorethan1 whenmorethan2 whenmorethan3
+      numbering1 numbering2 numbering3 /) {
+        $numberpattern->{$_} = $input->param($_);
+        if($numberpattern->{$_} and $numberpattern->{$_} eq '') {
+            $numberpattern->{$_} = undef;
+        }
+    }
+    my $numberpattern2 = GetSubscriptionNumberpatternByName($label);
+
+    if(!defined $numberpattern2) {
+        AddSubscriptionNumberpattern($numberpattern);
+    } else {
+        $op = 'new';
+        $template->param(error_existing_numberpattern => 1);
+        $template->param(%$numberpattern);
+    }
+} elsif ($op && $op eq 'savemod') {
+    my $id = $input->param('id');
+    my $label = $input->param('label');
+    my $numberpattern = GetSubscriptionNumberpattern($id);
+    my $mod_ok = 1;
+    if($numberpattern->{'label'} ne $label) {
+        my $numberpattern2 = GetSubscriptionNumberpatternByName($label);
+        if(defined $numberpattern2 && $id != $numberpattern2->{'id'}) {
+            $mod_ok = 0;
+        }
+    }
+    if($mod_ok) {
+        foreach(qw/ id label description numberingmethod displayorder
+          label1 label2 label3 add1 add2 add3 every1 every2 every3
+          setto1 setto2 setto3 whenmorethan1 whenmorethan2 whenmorethan3
+          numbering1 numbering2 numbering3 /) {
+            $numberpattern->{$_} = $input->param($_) || undef;
+        }
+        ModSubscriptionNumberpattern($numberpattern);
+    } else {
+        $op = 'modify';
+        $template->param(error_existing_numberpattern => 1);
+    }
+}
+
+if($op && ($op eq 'new' || $op eq 'modify')) {
+    if($op eq 'modify') {
+        my $id = $input->param('id');
+        if(defined $id) {
+            my $numberpattern = GetSubscriptionNumberpattern($id);
+            $template->param(%$numberpattern);
+        } else {
+            $op = 'new';
+        }
+    }
+    my @frequencies = GetSubscriptionFrequencies();
+    my @subtypes;
+    push @subtypes, { value => $_ } for (qw/ issues weeks months /);
+    my @locales = map {
+        chomp;
+        /^C|^POSIX$/ ? () : $_
+    } `locale -a`;
+
+    $template->param(
+        $op => 1,
+        frequencies_loop => \@frequencies,
+        subtypes_loop => \@subtypes,
+        locales => \@locales,
+        DHTMLcalendar_dateformat => C4::Dates->DHTMLcalendar(),
+    );
+    output_html_with_http_headers $input, $cookie, $template->output;
+    exit;
+}
+
+if($op && $op eq 'del') {
+    my $id = $input->param('id');
+    if ($id) {
+        my $confirm = $input->param('confirm');
+        if ($confirm) {
+            DelSubscriptionNumberpattern($id);
+        } else {
+            my @subs = GetSubscriptionsWithNumberpattern($id);
+            if (@subs) {
+                $template->param(
+                    id => $id,
+                    still_used => 1,
+                    subscriptions => \@subs
+                );
+            } else {
+                DelSubscriptionNumberpattern($id);
+            }
+        }
+    }
+}
+
+my @numberpatterns_loop = GetSubscriptionNumberpatterns();
+
+$template->param(
+    numberpatterns_loop => \@numberpatterns_loop,
+);
+
+output_html_with_http_headers $input, $cookie, $template->output;