Bug 17234: Add constraint_exists and column_exists to updatedatabase.pl
[koha.git] / installer / data / mysql / updatedatabase.pl
index fe0b381..2bf6319 100755 (executable)
@@ -47,7 +47,7 @@ use MARC::File::XML ( BinaryEncoding => 'utf8' );
 
 use File::Path qw[remove_tree]; # perl core module
 use File::Spec;
-use Path::Tiny;
+use File::Slurp;
 
 # FIXME - The user might be installing a new database, so can't rely
 # on /etc/koha.conf anyway.
@@ -8476,6 +8476,7 @@ $DBversion = "3.15.00.049";
 if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
     $dbh->do("ALTER TABLE biblioitems DROP INDEX isbn");
     $dbh->do("ALTER TABLE biblioitems DROP INDEX issn");
+    $dbh->do("ALTER TABLE biblioitems DROP INDEX issn_idx");
     $dbh->do("ALTER TABLE biblioitems
               CHANGE isbn isbn MEDIUMTEXT NULL DEFAULT NULL,
               CHANGE issn issn MEDIUMTEXT NULL DEFAULT NULL
@@ -9735,6 +9736,7 @@ if ( CheckVersion($DBversion) ) {
                     MODIFY COLUMN seealso varchar(1100) COLLATE utf8_unicode_ci DEFAULT NULL,
                     MODIFY COLUMN link varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL
                 |);
+                $dbh->do(qq|ALTER TABLE $name CHARACTER SET utf8 COLLATE utf8_unicode_ci|);
             }
             else {
                 $dbh->do(qq|ALTER TABLE $name CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci|);
@@ -10420,15 +10422,21 @@ if ( CheckVersion($DBversion) ) {
 
 $DBversion = "3.19.00.041";
 if ( CheckVersion($DBversion) ) {
-    $dbh->do(q|
-        ALTER IGNORE TABLE suggestions ADD KEY status (STATUS)
-    |);
-    $dbh->do(q|
-        ALTER IGNORE TABLE suggestions ADD KEY biblionumber (biblionumber)
-    |);
-    $dbh->do(q|
-        ALTER IGNORE TABLE suggestions ADD KEY branchcode (branchcode)
-    |);
+    unless ( constraint_exists( 'suggestions', 'status' ) ) {
+        $dbh->do(q|
+            ALTER TABLE suggestions ADD KEY status (STATUS)
+        |);
+    }
+    unless ( constraint_exists( 'suggestions', 'biblionumber' ) ) {
+        $dbh->do(q|
+            ALTER TABLE suggestions ADD KEY biblionumber (biblionumber)
+        |);
+    }
+    unless ( constraint_exists( 'suggestions', 'branchcode' ) ) {
+        $dbh->do(q|
+            ALTER TABLE suggestions ADD KEY branchcode (branchcode)
+        |);
+    }
     print "Upgrade to $DBversion done (Bug 14132: suggestions table is missing indexes)\n";
     SetVersion ($DBversion);
 }
@@ -10442,12 +10450,14 @@ if ( CheckVersion($DBversion) ) {
         WHERE auth_types.authtypecode IS NULL
     });
 
-    $dbh->do(q{
-        ALTER IGNORE TABLE auth_subfield_structure
-        ADD CONSTRAINT auth_subfield_structure_ibfk_1
-        FOREIGN KEY (authtypecode) REFERENCES auth_types(authtypecode)
-        ON DELETE CASCADE ON UPDATE CASCADE
-    });
+    unless ( constraint_exists( 'auth_subfield_structure', 'auth_subfield_structure_ibfk_1' ) ) {
+        $dbh->do(q{
+            ALTER TABLE auth_subfield_structure
+            ADD CONSTRAINT auth_subfield_structure_ibfk_1
+            FOREIGN KEY (authtypecode) REFERENCES auth_types(authtypecode)
+            ON DELETE CASCADE ON UPDATE CASCADE
+        });
+    }
 
     print "Upgrade to $DBversion done (Bug 8480: Add foreign key on auth_subfield_structure.authtypecode)\n";
     SetVersion($DBversion);
@@ -10563,31 +10573,58 @@ if ( CheckVersion($DBversion) ) {
 
 $DBversion = "3.21.00.007";
 if ( CheckVersion($DBversion) ) {
-    $dbh->do(q|
-        ALTER IGNORE TABLE aqbasket
-            ADD KEY authorisedby (authorisedby)
-    |);
-    $dbh->do(q|
-        ALTER IGNORE TABLE aqbooksellers
-            ADD KEY name (name(255))
-    |);
-    $dbh->do(q|
-        ALTER IGNORE TABLE aqbudgets
-            ADD KEY budget_parent_id (budget_parent_id),
-            ADD KEY budget_code (budget_code),
-            ADD KEY budget_branchcode (budget_branchcode),
-            ADD KEY budget_period_id (budget_period_id),
-            ADD KEY budget_owner_id (budget_owner_id)
-    |);
-    $dbh->do(q|
-        ALTER IGNORE TABLE aqbudgets_planning
-            ADD KEY budget_period_id (budget_period_id)
-    |);
-    $dbh->do(q|
-        ALTER IGNORE TABLE aqorders
-            ADD KEY parent_ordernumber (parent_ordernumber),
-            ADD KEY orderstatus (orderstatus)
-    |);
+    unless ( constraint_exists( 'aqbasket', 'authorisedby' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqbasket
+                ADD KEY authorisedby (authorisedby)
+        |);
+    }
+    unless ( constraint_exists( 'aqbooksellers', 'name' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqbooksellers
+                ADD KEY name (name(255))
+        |);
+    }
+    unless ( constraint_exists( 'aqbudgets', 'budget_parent_id' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqbudgets
+                ADD KEY budget_parent_id (budget_parent_id)|);
+        }
+    unless ( constraint_exists( 'aqbudgets', 'budget_code' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqbudgets
+                ADD KEY budget_code (budget_code)|);
+    }
+    unless ( constraint_exists( 'aqbudgets', 'budget_branchcode' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqbudgets
+                ADD KEY budget_branchcode (budget_branchcode)|);
+    }
+    unless ( constraint_exists( 'aqbudgets', 'budget_period_id' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqbudgets
+                ADD KEY budget_period_id (budget_period_id)|);
+    }
+    unless ( constraint_exists( 'aqbudgets', 'budget_owner_id' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqbudgets
+                ADD KEY budget_owner_id (budget_owner_id)|);
+    }
+    unless ( constraint_exists( 'aqbudgets_planning', 'budget_period_id' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqbudgets_planning
+                ADD KEY budget_period_id (budget_period_id)|);
+    }
+    unless ( constraint_exists( 'aqorders', 'parent_ordernumber' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqorders
+                ADD KEY parent_ordernumber (parent_ordernumber)|);
+    }
+    unless ( constraint_exists( 'aqorders', 'orderstatus' ) ) {
+        $dbh->do(q|
+            ALTER TABLE aqorders
+                ADD KEY orderstatus (orderstatus)|);
+    }
     print "Upgrade to $DBversion done (Bug 14053: Acquisition db tables are missing indexes)\n";
     SetVersion ($DBversion);
 }
@@ -10688,9 +10725,12 @@ if ( CheckVersion($DBversion) ) {
         INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type)
         VALUES ('OAI-PMH:DeletedRecord','persistent','Koha\'s deletedbiblio table will never be deleted (persistent) or might be deleted (transient)','transient|persistent','Choice')
     });
-    $dbh->do(q|
-        ALTER TABLE oai_sets_biblios DROP FOREIGN KEY oai_sets_biblios_ibfk_1
-    |);
+
+    if ( constraint_exists( 'oai_sets_biblios', 'oai_sets_biblios_ibfk_1' ) ) {
+        $dbh->do(q|
+            ALTER TABLE oai_sets_biblios DROP FOREIGN KEY oai_sets_biblios_ibfk_1
+        |);
+    }
     print "Upgrade to $DBversion done (Bug 3206: OAI repository deleted record support)\n";
     SetVersion ($DBversion);
 }
@@ -10771,12 +10811,14 @@ if ( CheckVersion($DBversion) ) {
 
 $DBversion = "3.21.00.019";
 if ( CheckVersion($DBversion) ) {
-    $dbh->do(q{
-        ALTER TABLE reserves DROP constrainttype
-    });
-    $dbh->do(q{
-        ALTER TABLE old_reserves DROP constrainttype
-    });
+    if ( column_exists( 'reserves', 'constrainttype' ) ) {
+        $dbh->do(q{
+            ALTER TABLE reserves DROP constrainttype
+        });
+        $dbh->do(q{
+            ALTER TABLE old_reserves DROP constrainttype
+        });
+    }
     $dbh->do(q{
         DROP TABLE IF EXISTS reserveconstraints
     });
@@ -10816,12 +10858,14 @@ if ( CheckVersion($DBversion) ) {
     my ($print_error) = $dbh->{PrintError};
     $dbh->{RaiseError} = 0;
     $dbh->{PrintError} = 0;
-    $dbh->do(q{ALTER TABLE course_reserves DROP FOREIGN KEY course_reserves_ibfk_2});
-    $dbh->do(q{ALTER TABLE course_reserves DROP INDEX course_reserves_ibfk_2});
+    if ( constraint_exists('course_reserves', 'course_reserves_ibfk_2') ) {
+        $dbh->do(q{ALTER TABLE course_reserves DROP FOREIGN KEY course_reserves_ibfk_2});
+        $dbh->do(q{ALTER TABLE course_reserves DROP INDEX course_reserves_ibfk_2});
+    }
     $dbh->{PrintError} = $print_error;
 
     $dbh->do(q{
-        ALTER IGNORE TABLE course_reserves
+        ALTER TABLE course_reserves
             ADD CONSTRAINT course_reserves_ibfk_2
                 FOREIGN KEY (ci_id) REFERENCES course_items (ci_id)
                 ON DELETE CASCADE ON UPDATE CASCADE
@@ -10915,28 +10959,32 @@ if ( CheckVersion($DBversion) ) {
 
 $DBversion = "3.21.00.028";
 if ( CheckVersion($DBversion) ) {
-    $dbh->do(q{
-        ALTER TABLE uploaded_files
-            ADD COLUMN public tinyint,
-            ADD COLUMN permanent tinyint
-    });
-    $dbh->do(q{
-        UPDATE uploaded_files SET public=1, permanent=1
-    });
-    $dbh->do(q{
-        ALTER TABLE uploaded_files
-            CHANGE COLUMN categorycode uploadcategorycode tinytext
-    });
+    unless ( column_exists('uploaded_files', 'public') ) {
+        $dbh->do(q{
+            ALTER TABLE uploaded_files
+                ADD COLUMN public tinyint,
+                ADD COLUMN permanent tinyint
+        });
+        $dbh->do(q{
+            UPDATE uploaded_files SET public=1, permanent=1
+        });
+        $dbh->do(q{
+            ALTER TABLE uploaded_files
+                CHANGE COLUMN categorycode uploadcategorycode tinytext
+        });
+    }
     print "Upgrade to $DBversion done (Bug 14321: Merge UploadedFile and UploadedFiles into Koha::Upload)\n";
     SetVersion($DBversion);
 }
 
 $DBversion = "3.21.00.029";
 if ( CheckVersion($DBversion) ) {
-    $dbh->do(q{
-        ALTER IGNORE TABLE discharges
-            ADD COLUMN discharge_id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST
-    });
+    unless ( column_exists('discharges', 'discharge_id') ) {
+        $dbh->do(q{
+            ALTER TABLE discharges
+                ADD COLUMN discharge_id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST
+        });
+    }
     print "Upgrade to $DBversion done (Bug 14368: Add discharges history)\n";
     SetVersion($DBversion);
 }
@@ -11469,13 +11517,19 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
         ADD serialseq_z VARCHAR( 100 ) NULL DEFAULT NULL AFTER serialseq_y
    ");
 
-    my $schema        = Koha::Database->new()->schema();
-    my @subscriptions = $schema->resultset('Subscription')->all();
+    my $sth = $dbh->prepare("SELECT * FROM subscription");
+    $sth->execute();
+
+    my $sth2 = $dbh->prepare("SELECT * FROM subscription_numberpatterns WHERE id = ?");
+
+    my $sth3 = $dbh->prepare("UPDATE serial SET serialseq_x = ?, serialseq_y = ?, serialseq_z = ? WHERE serialid = ?");
 
-    foreach my $subscription (@subscriptions) {
-        my $number_pattern = $subscription->numberpattern();
+    foreach my $subscription ( $sth->fetchrow_hashref() ) {
+        next if !defined($subscription);
+        $sth2->execute( $subscription->{numberpattern} );
+        my $number_pattern = $sth2->fetchrow_hashref();
 
-        my $numbering_method = $number_pattern->numberingmethod();
+        my $numbering_method = $number_pattern->{numberingmethod};
         # Get all the data between the enumeration values, we need
         # to split each enumeration string based on these values.
         my @splits = split( /\{[XYZ]\}/, $numbering_method );
@@ -11487,12 +11541,15 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
         }
         my @indexes = sort { $indexes{$a} <=> $indexes{$b} } keys(%indexes);
 
-        my @serials =
-          $schema->resultset('Serial')
-          ->search( { subscriptionid => $subscription->subscriptionid() } );
+        my @serials = @{
+            $dbh->selectall_arrayref(
+                "SELECT * FROM serial WHERE subscriptionid = $subscription->{subscriptionid}",
+                { Slice => {} }
+            )
+        };
 
         foreach my $serial (@serials) {
-            my $serialseq = $serial->serialseq();
+            my $serialseq = $serial->{serialseq};
             my %enumeration_data;
 
             ## We cannot split on multiple values at once,
@@ -11514,12 +11571,11 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
                 $enumeration_data{ $indexes[0] } = $serialseq;
             }
 
-            $serial->update(
-                {
-                    serialseq_x => $enumeration_data{'X'},
-                    serialseq_y => $enumeration_data{'Y'},
-                    serialseq_z => $enumeration_data{'Z'},
-                }
+            $sth3->execute(
+                    $enumeration_data{'X'},
+                    $enumeration_data{'Y'},
+                    $enumeration_data{'Z'},
+                    $serial->{serialid},
             );
         }
     }
@@ -12265,9 +12321,9 @@ if ( $column_has_been_used ) {
 
 $DBversion = "3.23.00.050";
 if ( CheckVersion($DBversion) ) {
-    use YAML::Syck;
     use Koha::SearchMarcMaps;
     use Koha::SearchFields;
+    use Koha::SearchEngine::Elasticsearch;
 
     $dbh->do(q|INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type)
                     VALUES('SearchEngine','Zebra','Choose Search Engine','','Choice')|);
@@ -12329,21 +12385,8 @@ $dbh->do(q|
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
         |);
 
-my $mappings_yaml = C4::Context->config('intranetdir') . '/admin/searchengine/elasticsearch/mappings.yaml';
-my $indexes = LoadFile( $mappings_yaml );
-
-while ( my ( $index_name, $fields ) = each %$indexes ) {
-        while ( my ( $field_name, $data ) = each %$fields ) {
-            my $field_type = $data->{type};
-            my $field_label = $data->{label};
-            my $mappings = $data->{mappings};
-            my $search_field = Koha::SearchFields->find_or_create({ name => $field_name, label => $field_label, type => $field_type }, { key => 'name' });
-            for my $mapping ( @$mappings ) {
-                my $marc_field = Koha::SearchMarcMaps->find_or_create({ index_name => $index_name, marc_type => $mapping->{marc_type}, marc_field => $mapping->{marc_field} });
-                $search_field->add_to_search_marc_maps($marc_field, { facet => $mapping->{facet}, suggestible => $mapping->{suggestible}, sort => $mapping->{sort} } );
-            }
-        }
-}
+        # Insert default mappings
+        Koha::SearchEngine::Elasticsearch->reset_elasticsearch_mappings;
 
 print "Upgrade to $DBversion done (Bug 12478 - Elasticsearch support for Koha)\n";
     SetVersion($DBversion);
@@ -12580,6 +12623,9 @@ SetVersion($DBversion);
 
 $DBversion = "3.23.00.063";
 if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        UPDATE letter SET branchcode='' WHERE branchcode IS NULL;
+    });
     $dbh->do(q{
         ALTER TABLE letter MODIFY COLUMN branchcode varchar(10) NOT NULL DEFAULT ''
     });
@@ -12982,18 +13028,741 @@ if ( CheckVersion($DBversion) ) {
 }
 
 $DBversion = "16.06.00.027";
+if ( CheckVersion($DBversion) ) {
+    unless ( column_exists('borrowers', 'lastseen') ) {
+        $dbh->do(q{
+            ALTER TABLE borrowers ADD COLUMN lastseen datetime default NULL AFTER updated_on;
+        });
+        $dbh->do(q{
+            ALTER TABLE deletedborrowers ADD COLUMN lastseen datetime default NULL AFTER updated_on;
+        });
+    }
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('TrackLastPatronActivity', '0', 'If set, the field borrowers.lastseen will be updated everytime a patron is seen', NULL, 'YesNo');
+    });
+
+    print "Upgrade to $DBversion done (Bug 16274 - Make the selfregistration branchcode selection configurable)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.028';
+if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
+    {
+        print "Attempting upgrade to $DBversion (Bug 17135) ...\n";
+        my $maintenance_script = C4::Context->config("intranetdir") . "/installer/data/mysql/fix_unclosed_nonaccruing_fines_bug17135.pl";
+        system("perl $maintenance_script --confirm");
+
+        print "Upgrade to $DBversion done (Bug 17135 - Fine for the previous overdue may get overwritten by the next one)\n";
+
+        unless ($original_version < TransformToNum("3.23.00.032")) { ## Bug 15675
+            print "WARNING: There is a possibility (= just a possibility, it's configuration dependent etc.) that - due to regression introduced by Bug 15675 - some old fine records for overdued items (items which got renewed 1+ time while being overdue) may have been overwritten in your production 16.05+ database. See Bugzilla reports for Bug 14390 and Bug 17135 for more details.\n";
+            print "WARNING: Please note that this upgrade does not try to recover such overwitten old fine records (if any) - it's just an follow-up for Bug 14390, its sole purpose is preventing eventual further-on overwrites from happening in the future. Optional recovery of the overwritten fines (again, if any) is like, totally outside of the scope of this particular upgrade!\n";
+        }
+        SetVersion ($DBversion);
+    }
+}
+
+$DBversion = "16.06.00.029";
 if ( CheckVersion($DBversion) ) {
     $dbh->do(q{
-        ALTER IGNORE TABLE borrowers ADD COLUMN lastseen datetime default NULL AFTER updated_on;
+        UPDATE systempreferences SET type="Choice" WHERE variable="UsageStatsLibraryType";
     });
     $dbh->do(q{
-        ALTER IGNORE TABLE deletedborrowers ADD COLUMN lastseen datetime default NULL AFTER updated_on;
+        UPDATE systempreferences SET value="Canada" WHERE variable="UsageStatsCountry" AND value="CANADA";
     });
     $dbh->do(q{
-        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('TrackLastPatronActivity', '0', 'If set, the field borrowers.lastseen will be updated everytime a patron is seen', NULL, 'YesNo');
+        UPDATE systempreferences SET value="Czech Republic" WHERE variable="UsageStatsCountry" AND value="CZ";
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="United Kingdom" WHERE variable="UsageStatsCountry" AND (value="England" OR value="UK");
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="Spain" WHERE variable="UsageStatsCountry" AND value="España";
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="Greece" WHERE variable="UsageStatsCountry" AND value="GR";
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="Ireland" WHERE variable="UsageStatsCountry" AND value="Irelanbd";
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="Mexico" WHERE variable="UsageStatsCountry" AND value="México";
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="Peru" WHERE variable="UsageStatsCountry" AND value="Perú";
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="Dominican Rep." WHERE variable="UsageStatsCountry" AND value="República Dominicana";
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="Trinidad & Tob." WHERE variable="UsageStatsCountry" AND value="Trinidad";
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="Turkey" WHERE variable="UsageStatsCountry" AND value="Türkiye";
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="USA" WHERE variable="UsageStatsCountry" AND (value="United States" OR value="United States of America" OR value="US");
+    });
+    $dbh->do(q{
+        UPDATE systempreferences SET value="Zimbabwe" WHERE variable="UsageStatsCountry" AND value="Zimbabbwe";
     });
 
-    print "Upgrade to $DBversion done (Bug 16274 - Make the selfregistration branchcode selection configurable)\n";
+    print "Upgrade to $DBversion done (Bug 14707 - Change UsageStatsCountry from free text to a dropdown list)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = "16.06.00.030";
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+        ('OPACHoldingsDefaultSortField','first_column','first_column|homebranch|holdingbranch','Default sort field for the holdings table at the OPAC','choice');
+    });
+
+    print "Upgrade to $DBversion done (Bug 16552 - Add the ability to change the default holdings sort)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = "16.06.00.031";
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('PatronSelfRegistrationPrefillForm', '1', 'Display password and prefill login form after a patron has self registered', NULL, 'YesNo');
+    });
+
+    print "Upgrade to $DBversion done (Bug 16273 - Prevent selfregistration from printing the borrower password and filling the logging form)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = "16.06.00.032";
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        UPDATE marc_subfield_structure SET authorised_value="WITHDRAWN" WHERE authorised_value="WTHDRAWN";
+    });
+
+    print "Upgrade to $DBversion done (Bug 17357 - WTHDRAWN is still used in installer files)\n";
+    SetVersion($DBversion);
+}
+
+
+$DBversion = "16.06.00.033";
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        CREATE TABLE authorised_value_categories (
+        category_name VARCHAR(32) NOT NULL,
+        primary key (category_name)
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+        });
+## Add authorised value categories
+    $dbh->do(q{
+    INSERT INTO authorised_value_categories (category_name )
+    SELECT DISTINCT category FROM authorised_values;
+    });
+    
+## Add special categories
+    $dbh->do(q{
+    INSERT IGNORE INTO authorised_value_categories( category_name )
+    VALUES
+    ('Asort1'),
+    ('Asort2'),
+    ('Bsort1'),
+    ('Bsort2'),
+    ('SUGGEST'),
+    ('DAMAGED'),
+    ('LOST'),
+    ('REPORT_GROUP'),
+    ('REPORT_SUBGROUP'),
+    ('DEPARTMENT'),
+    ('TERM'),
+    ('SUGGEST_STATUS'),
+    ('ITEMTYPECAT');
+    });
+
+## Add very special categories
+    $dbh->do(q{
+    INSERT IGNORE INTO authorised_value_categories( category_name )
+    VALUES
+    ('branches'),
+    ('itemtypes'),
+    ('cn_source');
+    });
+
+    $dbh->do(q{
+    INSERT IGNORE INTO authorised_value_categories( category_name )
+    VALUES
+    ('WITHDRAWN'),
+    ('RESTRICTED'),
+    ('NOT_LOAN'),
+    ('CCODE'),
+    ('LOC'),
+    ('STACK');
+    });
+
+## Update the FK
+    $dbh->do(q{
+    ALTER TABLE items_search_fields
+    DROP FOREIGN KEY items_search_fields_authorised_values_category;
+    });
+
+    $dbh->do(q{
+    ALTER TABLE items_search_fields
+    ADD CONSTRAINT `items_search_fields_authorised_values_category` FOREIGN KEY (`authorised_values_category`) REFERENCES `authorised_value_categories` (`category_name`) ON DELETE SET NULL ON UPDATE CASCADE;
+    });
+
+    $dbh->do(q{
+    ALTER TABLE authorised_values
+    ADD CONSTRAINT `authorised_values_authorised_values_category` FOREIGN KEY (`category`) REFERENCES `authorised_value_categories` (`category_name`) ON DELETE CASCADE ON UPDATE CASCADE;
+    });
+
+    $dbh->do(q{
+            INSERT IGNORE INTO authorised_value_categories( category_name ) SELECT DISTINCT(authorised_value) FROM marc_subfield_structure;
+            });
+
+    $dbh->do(q{
+            UPDATE marc_subfield_structure SET authorised_value = NULL WHERE authorised_value = ';';
+            });
+
+    # If the DB has been created before 3.19.00.006, the default collate for marc_subfield_structure if not set to utf8_unicode_ci and the new FK will not be create (MariaDB or MySQL will raise err 150)
+    my $table_sth = $dbh->prepare(qq|SHOW CREATE TABLE marc_subfield_structure|);
+    $table_sth->execute;
+    my @table = $table_sth->fetchrow_array;
+    if ( $table[1] !~ /COLLATE=utf8_unicode_ci/ and $table[1] !~ /COLLATE=utf8mb4_unicode_ci/ ) { #catches utf8mb4 collated tables
+        $dbh->do(qq|ALTER TABLE marc_subfield_structure CHARACTER SET utf8 COLLATE utf8_unicode_ci|);
+    }
+    $dbh->do(q{
+            ALTER TABLE marc_subfield_structure
+            MODIFY COLUMN authorised_value VARCHAR(32) DEFAULT NULL,
+            ADD CONSTRAINT marc_subfield_structure_ibfk_1 FOREIGN KEY (authorised_value) REFERENCES authorised_value_categories (category_name) ON UPDATE CASCADE ON DELETE SET NULL;
+            });
+
+      print "Upgrade to $DBversion done (Bug 17216 - Add a new table to store authorized value categories)\n";
+      SetVersion($DBversion);
+}
+
+$DBversion = "16.06.00.034";
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        ALTER TABLE biblioitems DROP COLUMN marc;
+    });
+    $dbh->do(q{
+        ALTER TABLE deletedbiblioitems DROP COLUMN marc;
+    });
+
+    print "Upgrade to $DBversion done (Bug 10455 - remove redundant 'biblioitems.marc' field)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.035';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences ( variable, value, options, explanation, type )
+         SELECT 'AllowItemsOnHoldCheckoutSCO',COALESCE(value,0),'','Do not generate RESERVE_WAITING and RESERVED warning in the SCO module when checking out items reserved to someone else. This allows self checkouts for those items.','YesNo'
+         FROM systempreferences WHERE variable='AllowItemsOnHoldCheckout';
+    });
+
+    print "Upgrade to $DBversion done (Bug 15131: Give SCO separate control for AllowItemsOnHoldCheckout)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.036';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        CREATE TABLE IF NOT EXISTS `housebound_profile` (
+          `borrowernumber` int(11) NOT NULL, -- Number of the borrower associated with this profile.
+          `day` text NOT NULL,  -- The preferred day of the week for delivery.
+          `frequency` text NOT NULL, -- The Authorised_Value definining the pattern for delivery.
+          `fav_itemtypes` text default NULL, -- Free text describing preferred itemtypes.
+          `fav_subjects` text default NULL, -- Free text describing preferred subjects.
+          `fav_authors` text default NULL, -- Free text describing preferred authors.
+          `referral` text default NULL, -- Free text indicating how the borrower was added to the service.
+          `notes` text default NULL, -- Free text for additional notes.
+          PRIMARY KEY  (`borrowernumber`),
+          CONSTRAINT `housebound_profile_bnfk`
+            FOREIGN KEY (`borrowernumber`)
+            REFERENCES `borrowers` (`borrowernumber`)
+            ON UPDATE CASCADE ON DELETE CASCADE
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+    });
+    $dbh->do(q{
+        CREATE TABLE IF NOT EXISTS `housebound_visit` (
+          `id` int(11) NOT NULL auto_increment, -- ID of the visit.
+          `borrowernumber` int(11) NOT NULL, -- Number of the borrower, & the profile, linked to this visit.
+          `appointment_date` date default NULL, -- Date of visit.
+          `day_segment` varchar(10),  -- Rough time frame: 'morning', 'afternoon' 'evening'
+          `chooser_brwnumber` int(11) default NULL, -- Number of the borrower to choose items  for delivery.
+          `deliverer_brwnumber` int(11) default NULL, -- Number of the borrower to deliver items.
+          PRIMARY KEY  (`id`),
+          CONSTRAINT `houseboundvisit_bnfk`
+            FOREIGN KEY (`borrowernumber`)
+            REFERENCES `housebound_profile` (`borrowernumber`)
+            ON UPDATE CASCADE ON DELETE CASCADE,
+          CONSTRAINT `houseboundvisit_bnfk_1`
+            FOREIGN KEY (`chooser_brwnumber`)
+            REFERENCES `borrowers` (`borrowernumber`)
+            ON UPDATE CASCADE ON DELETE CASCADE,
+          CONSTRAINT `houseboundvisit_bnfk_2`
+            FOREIGN KEY (`deliverer_brwnumber`)
+            REFERENCES `borrowers` (`borrowernumber`)
+            ON UPDATE CASCADE ON DELETE CASCADE
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+    });
+    $dbh->do(q{
+        CREATE TABLE IF NOT EXISTS `housebound_role` (
+          `borrowernumber_id` int(11) NOT NULL, -- borrowernumber link
+          `housebound_chooser` tinyint(1) NOT NULL DEFAULT 0, -- set to 1 to indicate this patron is a housebound chooser volunteer
+          `housebound_deliverer` tinyint(1) NOT NULL DEFAULT 0, -- set to 1 to indicate this patron is a housebound deliverer volunteer
+          PRIMARY KEY (`borrowernumber_id`),
+          CONSTRAINT `houseboundrole_bnfk`
+            FOREIGN KEY (`borrowernumber_id`)
+            REFERENCES `borrowers` (`borrowernumber`)
+            ON UPDATE CASCADE ON DELETE CASCADE
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+    });
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences
+               (variable,value,options,explanation,type) VALUES
+               ('HouseboundModule',0,'',
+               'If ON, enable housebound module functionality.','YesNo');
+    });
+    $dbh->do(q{
+        INSERT IGNORE INTO authorised_value_categories( category_name ) VALUES
+            ('HSBND_FREQ');
+    });
+    $dbh->do(q{
+        INSERT IGNORE INTO authorised_values (category, authorised_value, lib) VALUES
+               ('HSBND_FREQ','EW','Every week');
+    });
+
+    print "Upgrade to $DBversion done (Bug 5670 - Housebound Readers Module)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = "16.06.00.037";
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        ALTER TABLE `issuingrules` ADD `article_requests` ENUM( 'no', 'yes', 'bib_only', 'item_only' ) NOT NULL DEFAULT 'no' AFTER `opacitemholds`;
+    });
+    $dbh->do(q{
+        INSERT INTO `systempreferences` (`variable`, `value`, `options`, `explanation`, `type`) VALUES
+            ('ArticleRequests', '0', NULL, 'Enables the article request feature', 'YesNo'),
+            ('ArticleRequestsMandatoryFields', '', NULL, 'Comma delimited list of required fields for bibs where article requests rule = ''yes''', 'multiple'),
+            ('ArticleRequestsMandatoryFieldsItemsOnly', '', NULL, 'Comma delimited list of required fields for bibs where article requests rule = ''item_only''', 'multiple'),
+            ('ArticleRequestsMandatoryFieldsRecordOnly', '', NULL, 'Comma delimited list of required fields for bibs where article requests rule = ''bib_only''', 'multiple');
+    });
+    $dbh->do(q{
+        CREATE TABLE IF NOT EXISTS `article_requests` (
+          `id` int(11) NOT NULL AUTO_INCREMENT,
+          `borrowernumber` int(11) NOT NULL,
+          `biblionumber` int(11) NOT NULL,
+          `itemnumber` int(11) DEFAULT NULL,
+          `branchcode` varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
+          `title` text,
+          `author` text,
+          `volume` text,
+          `issue` text,
+          `date` text,
+          `pages` text,
+          `chapters` text,
+          `patron_notes` text,
+          `status` enum('PENDING','PROCESSING','COMPLETED','CANCELED') NOT NULL DEFAULT 'PENDING',
+          `notes` text,
+          `created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+          `updated_on` timestamp NULL DEFAULT NULL,
+          PRIMARY KEY (`id`),
+          KEY `borrowernumber` (`borrowernumber`),
+          KEY `biblionumber` (`biblionumber`),
+          KEY `itemnumber` (`itemnumber`),
+          KEY `branchcode` (`branchcode`),
+          CONSTRAINT `article_requests_ibfk_1` FOREIGN KEY (`borrowernumber`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE CASCADE ON UPDATE CASCADE,
+          CONSTRAINT `article_requests_ibfk_2` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE,
+          CONSTRAINT `article_requests_ibfk_3` FOREIGN KEY (`itemnumber`) REFERENCES `items` (`itemnumber`) ON DELETE SET NULL ON UPDATE CASCADE,
+          CONSTRAINT `article_requests_ibfk_4` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE SET NULL ON UPDATE CASCADE
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+    });
+    $dbh->do(q{
+        INSERT INTO `letter` (`module`, `code`, `branchcode`, `name`, `is_html`, `title`, `content`, `message_transport_type`) VALUES
+        ('circulation', 'AR_CANCELED', '', 'Article Request - Email - Canceled', 0, 'Article Request Canceled', '<<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>)\r\n\r\nYour request for an article from <<biblio.title>> (<<items.barcode>>) has been canceled for the following reason:\r\n\r\n<<article_requests.notes>>\r\n\r\nArticle requested:\r\nTitle: <<article_requests.title>>\r\nAuthor: <<article_requests.author>>\r\nVolume: <<article_requests.volume>>\r\nIssue: <<article_requests.issue>>\r\nDate: <<article_requests.date>>\r\nPages: <<article_requests.pages>>\r\nChapters: <<article_requests.chapters>>\r\nNotes: <<article_requests.patron_notes>>\r\n', 'email'),
+        ('circulation', 'AR_COMPLETED', '', 'Article Request - Email - Completed', 0, 'Article Request Completed', '<<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>)\r\n\r\nWe are have completed your request for an article from <<biblio.title>> (<<items.barcode>>).\r\n\r\nArticle requested:\r\nTitle: <<article_requests.title>>\r\nAuthor: <<article_requests.author>>\r\nVolume: <<article_requests.volume>>\r\nIssue: <<article_requests.issue>>\r\nDate: <<article_requests.date>>\r\nPages: <<article_requests.pages>>\r\nChapters: <<article_requests.chapters>>\r\nNotes: <<article_requests.patron_notes>>\r\n\r\nYou may pick your article up at <<branches.branchname>>.\r\n\r\nThank you!', 'email'),
+        ('circulation', 'AR_PENDING', '', 'Article Request - Email - Open', 0, 'Article Request Received', '<<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>)\r\n\r\nWe have received your request for an article from <<biblio.title>> (<<items.barcode>>).\r\n\r\nArticle requested:\r\nTitle: <<article_requests.title>>\r\nAuthor: <<article_requests.author>>\r\nVolume: <<article_requests.volume>>\r\nIssue: <<article_requests.issue>>\r\nDate: <<article_requests.date>>\r\nPages: <<article_requests.pages>>\r\nChapters: <<article_requests.chapters>>\r\nNotes: <<article_requests.patron_notes>>\r\n\r\n\r\nThank you!', 'email'),
+        ('circulation', 'AR_SLIP', '', 'Article Request - Print Slip', 0, 'Test', 'Article Request:\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>)\r\n\r\nTitle: <<biblio.title>>\r\nBarcode: <<items.barcode>>\r\n\r\nArticle requested:\r\nTitle: <<article_requests.title>>\r\nAuthor: <<article_requests.author>>\r\nVolume: <<article_requests.volume>>\r\nIssue: <<article_requests.issue>>\r\nDate: <<article_requests.date>>\r\nPages: <<article_requests.pages>>\r\nChapters: <<article_requests.chapters>>\r\nNotes: <<article_requests.patron_notes>>\r\n', 'print'),
+        ('circulation', 'AR_PROCESSING', '', 'Article Request - Email - Processing', 0, 'Article Request Processing', '<<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>)\r\n\r\nWe are now processing your request for an article from <<biblio.title>> (<<items.barcode>>).\r\n\r\nArticle requested:\r\nTitle: <<article_requests.title>>\r\nAuthor: <<article_requests.author>>\r\nVolume: <<article_requests.volume>>\r\nIssue: <<article_requests.issue>>\r\nDate: <<article_requests.date>>\r\nPages: <<article_requests.pages>>\r\nChapters: <<article_requests.chapters>>\r\nNotes: <<article_requests.patron_notes>>\r\n\r\nThank you!', 'email');
+    });
+
+    print "Upgrade to $DBversion done (Bug 14610 - Add ability to place article requests in Koha)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.038';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('DefaultPatronSearchFields','surname,firstname,othernames,cardnumber,userid',NULL,'Comma separated list defining the default fields to be used during a patron search','free');
+    });
+
+    print "Upgrade to $DBversion done (Bug 14874 - Add ability to search for patrons by date of birth from checkout and patron quick searches)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = "16.06.00.039";
+if ( CheckVersion($DBversion) ) {
+
+    my $sth = $dbh->prepare(q{
+        SELECT s.itemnumber, i.itype, b.itemtype
+        FROM
+         ( SELECT DISTINCT itemnumber
+           FROM statistics
+           WHERE ( type = "return" OR type = "localuse" ) AND
+                 itemtype IS NULL
+         ) s
+        LEFT JOIN
+         ( SELECT itemnumber,biblionumber, itype
+             FROM items
+           UNION
+           SELECT itemnumber,biblionumber, itype
+             FROM deleteditems
+         ) i
+        ON (s.itemnumber=i.itemnumber)
+        LEFT JOIN
+         ( SELECT biblionumber, itemtype
+             FROM biblioitems
+           UNION
+           SELECT biblionumber, itemtype
+             FROM deletedbiblioitems
+         ) b
+        ON (i.biblionumber=b.biblionumber);
+    });
+    $sth->execute();
+
+    my $update_sth = $dbh->prepare(q{
+        UPDATE statistics
+        SET itemtype=?
+        WHERE itemnumber=? AND itemtype IS NULL
+    });
+    my $ilevel_itypes = C4::Context->preference('item-level_itypes');
+
+    while ( my ($itemnumber,$item_itype,$biblio_itype) = $sth->fetchrow_array ) {
+
+        my $effective_itemtype = $ilevel_itypes
+                                    ? $item_itype // $biblio_itype
+                                    : $biblio_itype;
+        warn "item-level_itypes set but no itype defined for item ($itemnumber)"
+            if $ilevel_itypes and !defined $item_itype;
+        $update_sth->execute( $effective_itemtype, $itemnumber );
+    }
+
+    print "Upgrade to $DBversion done (Bug 14598: itemtype is not set on statistics by C4::Circulation::AddReturn)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.040';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        ALTER TABLE `aqcontacts` ADD `orderacquisition` BOOLEAN NOT NULL DEFAULT 0 AFTER `notes`;
+    });
+    $dbh->do(q{
+        INSERT IGNORE INTO `letter` (module, code, name, title, content, message_transport_type) VALUES
+        ('orderacquisition','ACQORDER','Acquisition order','Order','<<aqbooksellers.name>>\r\n<<aqbooksellers.address1>>\r\n<<aqbooksellers.address2>>\r\n<<aqbooksellers.address3>>\r\n<<aqbooksellers.address4>>\r\n<<aqbooksellers.phone>>\r\n\r\nPlease order for the library:\r\n\r\n<order>Ordernumber <<aqorders.ordernumber>> (<<biblio.title>>) (quantity: <<aqorders.quantity>>) ($<<aqorders.listprice>> each).</order>\r\n\r\nThank you,\n\n<<branches.branchname>>', 'email');
+    });
+
+    print "Upgrade to $DBversion done (Bug 5260 - Add option to send an order by e-mail to the acquisition module)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.041';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('AggressiveMatchOnISSN','0','If enabled, attempt to match aggressively by trying all variations of the ISSNs in the imported record as a phrase in the ISSN fields of already cataloged records when matching on ISSN with the record import tool','','YesNo')
+    });
+
+    print "Upgrade to $DBversion done (Bug 14629 - Add aggressive ISSN matching feature equivalent to the aggressive ISBN matcher)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.042';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q|
+        ALTER TABLE aqorders
+            ADD COLUMN unitprice_tax_excluded decimal(28,6) default NULL AFTER unitprice,
+            ADD COLUMN unitprice_tax_included decimal(28,6) default NULL AFTER unitprice_tax_excluded,
+            ADD COLUMN rrp_tax_excluded decimal(28,6) default NULL AFTER rrp,
+            ADD COLUMN rrp_tax_included decimal(28,6) default NULL AFTER rrp_tax_excluded,
+            ADD COLUMN ecost_tax_excluded decimal(28,6) default NULL AFTER ecost,
+            ADD COLUMN ecost_tax_included decimal(28,6) default NULL AFTER ecost_tax_excluded,
+            ADD COLUMN tax_value decimal(6,4) default NULL AFTER gstrate
+    |);
+
+    # rename gstrate with tax_rate
+    $dbh->do(q|ALTER TABLE aqorders CHANGE COLUMN gstrate tax_rate decimal(6,4) DEFAULT NULL|);
+    $dbh->do(q|ALTER TABLE aqbooksellers CHANGE COLUMN gstrate tax_rate decimal(6,4) DEFAULT NULL|);
+
+    # Fill the new columns
+    my $orders = $dbh->selectall_arrayref(q|
+        SELECT * FROM aqorders
+    |, { Slice => {} } );
+
+    my $sth_update_order = $dbh->prepare(q|
+        UPDATE aqorders
+        SET unitprice_tax_excluded = ?,
+            unitprice_tax_included = ?,
+            rrp_tax_excluded = ?,
+            rrp_tax_included = ?,
+            ecost_tax_excluded = ?,
+            ecost_tax_included = ?,
+            tax_value = ?
+        WHERE ordernumber = ?
+    |);
+
+    my $sth_get_bookseller = $dbh->prepare(q|
+        SELECT aqbooksellers.*
+        FROM aqbooksellers
+        LEFT JOIN aqbasket ON aqbasket.booksellerid = aqbooksellers.id
+        LEFT JOIN aqorders ON aqorders.basketno = aqbasket.basketno
+        WHERE ordernumber = ?
+    |);
+
+    require Koha::Number::Price;
+    for my $order ( @$orders ) {
+        $sth_get_bookseller->execute( $order->{ordernumber} );
+        my ( $bookseller ) = $sth_get_bookseller->fetchrow_hashref;
+        $order->{rrp}   = Koha::Number::Price->new( $order->{rrp} )->round;
+        $order->{ecost} = Koha::Number::Price->new( $order->{ecost} )->round;
+        $order->{tax_rate} ||= 0 ; # tax_rate can be NULL in DB
+        # Ordering
+        if ( $bookseller->{listincgst} ) {
+            $order->{rrp_tax_included} = $order->{rrp};
+            $order->{rrp_tax_excluded} = Koha::Number::Price->new(
+                $order->{rrp_tax_included} / ( 1 + $order->{tax_rate} ) )->round;
+            $order->{ecost_tax_included} = $order->{ecost};
+            $order->{ecost_tax_excluded} = Koha::Number::Price->new(
+                $order->{ecost} / ( 1 + $order->{tax_rate} ) )->round;
+        }
+        else {
+            $order->{rrp_tax_excluded} = $order->{rrp};
+            $order->{rrp_tax_included} = Koha::Number::Price->new(
+                $order->{rrp} * ( 1 + $order->{tax_rate} ) )->round;
+            $order->{ecost_tax_excluded} = $order->{ecost};
+            $order->{ecost_tax_included} = Koha::Number::Price->new(
+                $order->{ecost} * ( 1 + $order->{tax_rate} ) )->round;
+        }
+
+        #receiving
+        if ( $bookseller->{listincgst} ) {
+            $order->{unitprice_tax_included} = Koha::Number::Price->new( $order->{unitprice} )->round;
+            $order->{unitprice_tax_excluded} = Koha::Number::Price->new(
+              $order->{unitprice_tax_included} / ( 1 + $order->{tax_rate} ) )->round;
+        }
+        else {
+            $order->{unitprice_tax_excluded} = Koha::Number::Price->new( $order->{unitprice} )->round;
+            $order->{unitprice_tax_included} = Koha::Number::Price->new(
+              $order->{unitprice_tax_excluded} * ( 1 + $order->{tax_rate} ) )->round;
+        }
+
+        # If the order is received, the tax is calculated from the unit price
+        if ( $order->{orderstatus} eq 'complete' ) {
+            $order->{tax_value} = Koha::Number::Price->new(
+              ( $order->{unitprice_tax_included} - $order->{unitprice_tax_excluded} )
+              * $order->{quantity} )->round;
+        } else {
+            # otherwise the ecost is used
+            $order->{tax_value} = Koha::Number::Price->new(
+                ( $order->{ecost_tax_included} - $order->{ecost_tax_excluded} ) *
+                  $order->{quantity} )->round;
+        }
+
+        $sth_update_order->execute(
+            $order->{unitprice_tax_excluded},
+            $order->{unitprice_tax_included},
+            $order->{rrp_tax_excluded},
+            $order->{rrp_tax_included},
+            $order->{ecost_tax_excluded},
+            $order->{ecost_tax_included},
+            $order->{tax_value},
+            $order->{ordernumber},
+        );
+    }
+
+    print "Upgrade to $DBversion done (Bug 13321 - Tax and prices calculation need to be fixed)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.043';
+if ( CheckVersion($DBversion) ) {
+    # Add the new columns
+    $dbh->do(q|
+        ALTER TABLE aqorders
+            ADD COLUMN tax_rate_on_ordering   decimal(6,4) default NULL AFTER tax_rate,
+            ADD COLUMN tax_rate_on_receiving  decimal(6,4) default NULL AFTER tax_rate_on_ordering,
+            ADD COLUMN tax_value_on_ordering  decimal(28,6) default NULL AFTER tax_value,
+            ADD COLUMN tax_value_on_receiving decimal(28,6) default NULL AFTER tax_value_on_ordering
+    |);
+
+    my $orders = $dbh->selectall_arrayref(q|
+        SELECT * FROM aqorders
+    |, { Slice => {} } );
+
+    my $sth_update_order = $dbh->prepare(q|
+        UPDATE aqorders
+        SET tax_rate_on_ordering = tax_rate,
+            tax_rate_on_receiving = tax_rate,
+            tax_value_on_ordering = ?,
+            tax_value_on_receiving = ?
+        WHERE ordernumber = ?
+    |);
+
+    require Koha::Number::Price;
+    for my $order (@$orders) {
+        my $tax_value_on_ordering =
+          $order->{quantity} *
+          $order->{ecost_tax_excluded} *
+          $order->{tax_rate};
+
+        my $tax_value_on_receiving =
+          ( defined $order->{unitprice_tax_excluded} )
+          ? $order->{quantity} * $order->{unitprice_tax_excluded} * $order->{tax_rate}
+          : undef;
+
+        $sth_update_order->execute( $tax_value_on_ordering,
+            $tax_value_on_receiving, $order->{ordernumber} );
+    }
+
+    # Remove the old columns
+    $dbh->do(q|
+        ALTER TABLE aqorders
+            CHANGE COLUMN tax_value tax_value_bak  decimal(28,6) default NULL,
+            CHANGE COLUMN tax_rate tax_rate_bak decimal(6,4) default NULL
+    |);
+
+    print "Upgrade to $DBversion done (Bug 13323 - Change the tax rate on receiving)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.044';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        ALTER TABLE `messages`
+        ADD `manager_id` int(11) NULL,
+        ADD FOREIGN KEY (`manager_id`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL;
+    });
+
+    print "Upgrade to $DBversion done (Bug 17397 - Show name of librarian who created circulation message)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.045';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        UPDATE systempreferences SET options = "now|dateexpiry|combination", explanation = "Set whether the borrower renewal date should be counted from the dateexpiry, from the current date or by combination: if the dateexpiry is in future use dateexpiry, else use current date " WHERE variable = "BorrowerRenewalPeriodBase";
+    });
+
+    print "Upgrade to $DBversion done (Bug 17443 - Make possible to renew patron by later of expiry and current date)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.046';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        ALTER TABLE issuingrules ADD COLUMN no_auto_renewal_after INT(4) DEFAULT NULL AFTER auto_renew;
+    });
+
+    print "Upgrade to $DBversion done (Bug 15581 - Add a circ rule to not allow auto-renewals after defined loan period)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.047';
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        UPDATE language_descriptions SET description = 'Čeština' WHERE subtag = 'cs' AND type = 'language' AND lang = 'cs'
+    });
+
+    print "Upgrade to $DBversion done (Bug 17518: Displayed language name for Czech is wrong)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '16.06.00.048';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q|
+        INSERT IGNORE INTO permissions (module_bit, code, description) VALUES
+        (13, 'upload_general_files', 'Upload any file'),
+        (13, 'upload_manage', 'Manage uploaded files');
+    |);
+
+    # Update user_permissions for current users (check count in uploaded_files)
+    # Note 9 == edit_catalogue and 13 == tools
+    # We do not insert if someone is superlibrarian, does not have edit_catalogue,
+    # or already has all tools
+    $dbh->do(q|
+        INSERT IGNORE INTO user_permissions (borrowernumber, module_bit, code)
+        SELECT borrowernumber, 13, 'upload_general_files'
+        FROM borrowers bo
+        WHERE flags<>1 AND flags & POW(2,13) = 0 AND
+            ( flags & POW(2,9) > 0 OR (
+                SELECT COUNT(*) FROM user_permissions
+                WHERE borrowernumber=bo.borrowernumber AND module_bit=9 ) > 0 )
+            AND ( SELECT COUNT(*) FROM uploaded_files ) > 0;
+    |);
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 17663 - Forgotten userpermissions)\n";
+}
+
+$DBversion = '16.06.00.049';
+if( CheckVersion( $DBversion ) ) {
+    $dbh->do(q|
+        INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) 
+        VALUES ('ReplytoDefault',  '',  NULL,  'The default email address to be set as replyto.',  'Free');
+    |);
+
+    $dbh->do(q|
+        INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type)
+        VALUES ('ReturnpathDefault',  '',  NULL,  'The default email address to be set as return-path',  'Free');
+    |);
+
+    SetVersion( $DBversion );
+    print "Upgrade to $DBversion done (Bug 17391 - ReturnpathDefault and ReplyToDefault missing from syspref.sql)\n";
+}
+
+$DBversion = "16.06.00.050";
+if ( CheckVersion($DBversion) ) {
+
+    # If index issn_idx still exists, we assume that dbrev 3.15.00.049 failed,
+    # and we repeat it (partially).
+    # Note: the db rev only pertains to biblioitems and is not needed for
+    # deletedbiblioitems.
+
+    my $temp = $dbh->selectall_arrayref( "SHOW INDEXES FROM biblioitems WHERE key_name = 'issn_idx'" );
+
+    if( @$temp > 0 ) {
+        $dbh->do( "ALTER TABLE biblioitems DROP INDEX isbn" );
+        $dbh->do( "ALTER TABLE biblioitems DROP INDEX issn" );
+        $dbh->do( "ALTER TABLE biblioitems DROP INDEX issn_idx" );
+        $dbh->do( "ALTER TABLE biblioitems CHANGE isbn isbn MEDIUMTEXT NULL DEFAULT NULL, CHANGE issn issn MEDIUMTEXT NULL DEFAULT NULL" );
+        $dbh->do( "ALTER TABLE biblioitems ADD INDEX isbn ( isbn ( 255 ) ), ADD INDEX issn ( issn ( 255 ) )" );
+        print "Upgrade to $DBversion done (Bug 8835). Removed issn_idx.\n";
+    } else {
+        print "Upgrade to $DBversion done (Bug 8835). Everything is fine.\n";
+    }
+
+    SetVersion($DBversion);
+}
+
+$DBversion = "16.11.00.000";
+if ( CheckVersion($DBversion) ) {
+    print "Upgrade to $DBversion done (Koha 16.11)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = "16.12.00.000";
+if ( CheckVersion($DBversion) ) {
+    print "Upgrade to $DBversion done (Koha 16.12 - Our battered suitcases were piled on the sidewalk again; we had longer ways to go. But no matter, the road is life.)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = "16.12.00.001";
+if ( CheckVersion($DBversion) ) {
+    $dbh->do(q{
+        ALTER TABLE borrower_modifications
+        ADD COLUMN extended_attributes text DEFAULT NULL
+        AFTER privacy
+    });
+
+    print "Upgrade to $DBversion done (Bug 17767 - Let Koha::Patron::Modification handle extended attributes)\n";
     SetVersion($DBversion);
 }
 
@@ -13005,12 +13774,13 @@ my $update_dir = C4::Context->config('intranetdir') . '/installer/data/mysql/ato
 opendir( my $dirh, $update_dir );
 foreach my $file ( sort readdir $dirh ) {
     next if $file !~ /\.(sql|perl)$/;  #skip other files
+    next if $file eq 'skeleton.perl'; # skip the skeleton file
     print "DEV atomic update: $file\n";
     if ( $file =~ /\.sql$/ ) {
         my $installer = C4::Installer->new();
         my $rv = $installer->load_sql( $update_dir . $file ) ? 0 : 1;
     } elsif ( $file =~ /\.perl$/ ) {
-        my $code = path( $update_dir . $file )->slurp_utf8;
+        my $code = read_file( $update_dir . $file );
         eval $code;
         say "Atomic update generated errors: $@" if $@;
     }
@@ -13127,4 +13897,29 @@ sub CheckVersion {
     }
 }
 
+sub constraint_exists {
+    my ( $table_name, $key_name ) = @_;
+    my $dbh = C4::Context->dbh;
+    my ($exists) = $dbh->selectrow_array(
+        qq|
+        SHOW INDEX FROM $table_name
+        WHERE key_name = ?
+        |, undef, $key_name
+    );
+    return $exists;
+}
+
+sub column_exists {
+    my ( $table_name, $column_name ) = @_;
+    my $dbh = C4::Context->dbh;
+    my ($exists) = $dbh->selectrow_array(
+        qq|
+        SHOW COLUMNS FROM $table_name
+        WHERE Field = ?
+        |, undef, $column_name
+    );
+    return $exists;
+
+}
+
 exit;