Bug 32030: ERM - Add vendor to license
authorJonathan Druart <jonathan.druart@bugs.koha-community.org>
Thu, 28 Jul 2022 08:30:55 +0000 (10:30 +0200)
committerTomas Cohen Arazi <tomascohen@theke.io>
Tue, 8 Nov 2022 12:44:19 +0000 (09:44 -0300)
ALTER TABLE erm_agreement_licenses DROP FOREIGN KEY erm_licenses_ibfk_1;
ALTER TABLE erm_agreement_licenses DROP FOREIGN KEY erm_licenses_ibfk_2;
ALTER TABLE erm_agreement_licenses ADD CONSTRAINT `erm_agreement_licenses_ibfk_1` FOREIGN KEY (`agreement_id`) REFERENCES `erm_agreements` (`agreement_id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE erm_agreement_licenses ADD CONSTRAINT `erm_agreement_licenses_ibfk_2` FOREIGN KEY (`license_id`) REFERENCES `erm_licenses` (`license_id`) ON DELETE CASCADE ON UPDATE CASCADE;

ALTER TABLE erm_licenses ADD COLUMN vendor_id INT(11) DEFAULT NULL AFTER license_id;
ALTER TABLE erm_licenses ADD CONSTRAINT `erm_licenses_ibfk_1` FOREIGN KEY (`vendor_id`) REFERENCES `aqbooksellers` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;

Signed-off-by: Jonathan Field <jonathan.field@ptfs-europe.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
13 files changed:
Koha/ERM/Agreement.pm
Koha/ERM/License.pm
api/v1/swagger/definitions/erm_agreement.yaml
api/v1/swagger/definitions/erm_license.yaml
api/v1/swagger/paths/erm_licenses.yaml
installer/data/mysql/atomicupdate/erm.pl
installer/data/mysql/kohastructure.sql
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsShow.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesList.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesShow.vue
koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js

index cc867ef..2c66928 100644 (file)
@@ -23,6 +23,7 @@ use MIME::Types;
 use Koha::Database;
 use Koha::DateUtils qw( dt_from_string );
 use Koha::Exceptions;
+use Koha::Acquisition::Bookseller;
 
 use base qw(Koha::Object);
 
@@ -257,6 +258,19 @@ sub agreement_packages {
     return Koha::ERM::EHoldings::Package::Agreements->_new_from_dbic($packages_agreements_rs);
 }
 
+=head3 vendor
+
+Return the vendor for this agreement
+
+=cut
+
+sub vendor {
+    my ( $self ) = @_;
+    my $vendor_rs = $self->_result->vendor;
+    return unless $vendor_rs;
+    return Koha::Acquisition::Bookseller->_new_from_dbic($vendor_rs);
+}
+
 =head2 Internal methods
 
 =head3 _type
index cd798ff..86f20ac 100644 (file)
@@ -21,6 +21,8 @@ use Koha::Database;
 
 use base qw(Koha::Object);
 
+use Koha::Acquisition::Bookseller;
+
 =head1 NAME
 
 Koha::ERM::License - Koha ERM License Object class
@@ -31,6 +33,19 @@ Koha::ERM::License - Koha ERM License Object class
 
 =cut
 
+=head3 vendor
+
+Return the vendor for this license
+
+=cut
+
+sub vendor {
+    my ( $self ) = @_;
+    my $vendor_rs = $self->_result->vendor;
+    return unless $vendor_rs;
+    return Koha::Acquisition::Bookseller->_new_from_dbic($vendor_rs);
+}
+
 =head2 Internal methods
 
 =head3 _type
index 8e4bf4b..88f80f1 100644 (file)
@@ -64,6 +64,11 @@ properties:
     description: documents
     items:
       $ref: erm_agreement_document.yaml
+  vendor:
+    description: Information about the vendor
+    type:
+      - object
+      - "null"
 
 additionalProperties: false
 required:
index 3431f52..f9b52dc 100644 (file)
@@ -5,6 +5,11 @@ properties:
     type: integer
     description: internally assigned license identifier
     readOnly: true
+  vendor_id:
+    description: foreign key to aqbooksellers
+    type:
+      - integer
+      - "null"
   name:
     description: name of the license
     type: string
@@ -33,6 +38,12 @@ properties:
       - "null"
     format: date
     description: End of the license
+  vendor:
+    description: Information about the vendor
+    type:
+      - object
+      - "null"
+
 additionalProperties: false
 required:
   - license_id
index 74b8897..ad2dd8c 100644 (file)
         name: license_id
         required: false
         type: integer
+      - description: Case insensitive search on agreement vendor_id
+        in: query
+        name: vendor_id
+        required: false
+        type: integer
       - description: Case insensitive search on license name
         in: query
         name: name
index f4a9693..df7d09f 100755 (executable)
@@ -97,12 +97,14 @@ return {
             $dbh->do(q{
                 CREATE TABLE `erm_licenses` (
                     `license_id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'primary key',
+                    `vendor_id` INT(11) DEFAULT NULL COMMENT 'foreign key to aqbooksellers',
                     `name` VARCHAR(255) NOT NULL COMMENT 'name of the license',
                     `description` LONGTEXT DEFAULT NULL COMMENT 'description of the license',
                     `type` VARCHAR(80) NOT NULL COMMENT 'type of the license',
                     `status` VARCHAR(80) NOT NULL COMMENT 'current status of the license',
                     `started_on` DATE COMMENT 'start of the license',
                     `ended_on` DATE COMMENT 'end of the license',
+                    CONSTRAINT `erm_licenses_ibfk_1` FOREIGN KEY (`vendor_id`) REFERENCES `aqbooksellers` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
                     PRIMARY KEY(`license_id`)
                 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
             });
@@ -117,8 +119,8 @@ return {
                     `physical_location` VARCHAR(80) DEFAULT NULL COMMENT 'physical location of the license',
                     `notes` mediumtext DEFAULT NULL COMMENT 'notes about this license',
                     `uri` varchar(255) DEFAULT NULL COMMENT 'URI of the license',
-                    CONSTRAINT `erm_licenses_ibfk_1` FOREIGN KEY (`agreement_id`) REFERENCES `erm_agreements` (`agreement_id`) ON DELETE CASCADE ON UPDATE CASCADE,
-                    CONSTRAINT `erm_licenses_ibfk_2` FOREIGN KEY (`license_id`) REFERENCES `erm_licenses` (`license_id`) ON DELETE CASCADE ON UPDATE CASCADE,
+                    CONSTRAINT `erm_agreement_licenses_ibfk_1` FOREIGN KEY (`agreement_id`) REFERENCES `erm_agreements` (`agreement_id`) ON DELETE CASCADE ON UPDATE CASCADE,
+                    CONSTRAINT `erm_agreement_licenses_ibfk_2` FOREIGN KEY (`license_id`) REFERENCES `erm_licenses` (`license_id`) ON DELETE CASCADE ON UPDATE CASCADE,
                     PRIMARY KEY(`agreement_license_id`),
                     UNIQUE KEY `erm_agreement_licenses_uniq` (`agreement_id`, `license_id`)
                 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
index 7eeb7f6..8128681 100644 (file)
@@ -2830,12 +2830,14 @@ CREATE TABLE `erm_agreement_user_roles` (
 DROP TABLE IF EXISTS `erm_licenses`;
 CREATE TABLE `erm_licenses` (
     `license_id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'primary key',
+    `vendor_id` INT(11) DEFAULT NULL COMMENT 'foreign key to aqbooksellers',
     `name` VARCHAR(255) NOT NULL COMMENT 'name of the license',
     `description` LONGTEXT DEFAULT NULL COMMENT 'description of the license',
     `type` VARCHAR(80) NOT NULL COMMENT 'type of the license',
     `status` VARCHAR(80) NOT NULL COMMENT 'current status of the license',
     `started_on` DATE COMMENT 'start of the license',
     `ended_on` DATE COMMENT 'end of the license',
+    CONSTRAINT `erm_licenses_ibfk_1` FOREIGN KEY (`vendor_id`) REFERENCES `aqbooksellers` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
     PRIMARY KEY(`license_id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
@@ -2852,8 +2854,8 @@ CREATE TABLE `erm_agreement_licenses` (
     `physical_location` VARCHAR(80) DEFAULT NULL COMMENT 'physical location of the license',
     `notes` mediumtext DEFAULT NULL COMMENT 'notes about this license',
     `uri` varchar(255) DEFAULT NULL COMMENT 'URI of the license',
-    CONSTRAINT `erm_licenses_ibfk_1` FOREIGN KEY (`agreement_id`) REFERENCES `erm_agreements` (`agreement_id`) ON DELETE CASCADE ON UPDATE CASCADE,
-    CONSTRAINT `erm_licenses_ibfk_2` FOREIGN KEY (`license_id`) REFERENCES `erm_licenses` (`license_id`) ON DELETE CASCADE ON UPDATE CASCADE,
+    CONSTRAINT `erm_agreement_licenses_ibfk_1` FOREIGN KEY (`agreement_id`) REFERENCES `erm_agreements` (`agreement_id`) ON DELETE CASCADE ON UPDATE CASCADE,
+    CONSTRAINT `erm_agreement_licenses_ibfk_2` FOREIGN KEY (`license_id`) REFERENCES `erm_licenses` (`license_id`) ON DELETE CASCADE ON UPDATE CASCADE,
     PRIMARY KEY(`agreement_license_id`),
     UNIQUE KEY `erm_agreement_licenses_uniq` (`agreement_id`, `license_id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
index 28c5299..cfe5696 100644 (file)
@@ -332,6 +332,7 @@ export default {
                 apiUrl += '/' + agreement.agreement_id
             }
             delete agreement.agreement_id
+            delete agreement.vendor
             agreement.is_perpetual = agreement.is_perpetual ? true : false
 
             if (agreement.vendor_id == "") {
index 240da65..10dec21 100644 (file)
                             <a
                                 :href="`/cgi-bin/koha/acqui/booksellers.pl?booksellerid=${agreement.vendor_id}`"
                             >
-                                {{
-                                    vendors.find(
-                                        (e) => e.id == agreement.vendor_id
-                                    ).name
-                                }}</a
-                            >
+                                {{ agreement.vendor.name }}
+                            </a>
                         </span>
                     </li>
                     <li>
 </template>
 
 <script>
-import { useVendorStore } from "../../stores/vendors"
 import { useAVStore } from "../../stores/authorised_values"
 import { fetchAgreement } from "../../fetch"
-import { storeToRefs } from "pinia"
 
 export default {
     setup() {
         const format_date = $date
         const patron_to_html = $patron_to_html
 
-        const vendorStore = useVendorStore()
-        const { vendors } = storeToRefs(vendorStore)
-
         const AVStore = useAVStore()
         const { get_lib_from_av } = AVStore
 
@@ -323,7 +314,6 @@ export default {
             format_date,
             patron_to_html,
             get_lib_from_av,
-            vendors,
         }
     },
     data() {
index 7e4f181..4dcf88c 100644 (file)
                             <span class="required">{{ $t("Required") }}</span>
                         </li>
                         <li>
+                            <label for="license_vendor_id"
+                                >{{ $t("Vendor") }}:</label
+                            >
+                            <select
+                                id="license_vendor_id"
+                                v-model="license.vendor_id"
+                            >
+                                <option value=""></option>
+                                <option
+                                    v-for="vendor in vendors"
+                                    :key="vendor.vendor_id"
+                                    :value="vendor.id"
+                                    :selected="
+                                        vendor.id == license.vendor_id
+                                            ? true
+                                            : false
+                                    "
+                                >
+                                    {{ vendor.name }}
+                                </option>
+                            </select>
+                        </li>
+
+                        <li>
                             <label for="license_description"
                                 >{{ $t("Description") }}:
                             </label>
 
 <script>
 import flatPickr from 'vue-flatpickr-component'
+import { useVendorStore } from "../../stores/vendors"
 import { useAVStore } from "../../stores/authorised_values"
 import { setMessage, setError } from "../../messages"
 import { fetchLicense } from '../../fetch'
@@ -129,6 +154,8 @@ import { storeToRefs } from "pinia"
 export default {
 
     setup() {
+        const vendorStore = useVendorStore()
+        const { vendors } = storeToRefs(vendorStore)
         const AVStore = useAVStore()
         const {
             av_license_types,
@@ -136,6 +163,7 @@ export default {
         } = storeToRefs(AVStore)
 
         return {
+            vendors,
             av_license_types,
             av_license_statuses,
         }
@@ -147,6 +175,7 @@ export default {
             license: {
                 license_id: null,
                 name: '',
+                vendor_id: null,
                 description: '',
                 type: '',
                 status: '',
@@ -190,6 +219,11 @@ export default {
                 apiUrl += '/' + license.license_id
             }
             delete license.license_id
+            delete license.vendor
+
+            if (license.vendor_id == "") {
+                license.vendor_id = null
+            }
 
             license.started_on = license.started_on ? $date_to_rfc3339(license.started_on) : null
             license.ended_on = license.ended_on ? $date_to_rfc3339(license.ended_on) : null
index 0e0196b..e220bc1 100644 (file)
@@ -12,6 +12,7 @@
 <script>
 import Toolbar from "./LicensesToolbar.vue"
 import { createVNode, render } from 'vue'
+import { useVendorStore } from "../../stores/vendors"
 import { useAVStore } from "../../stores/authorised_values"
 import { storeToRefs } from "pinia"
 import { fetchLicenses } from "../../fetch"
@@ -19,6 +20,9 @@ import { useDataTable } from "../../composables/datatables"
 
 export default {
     setup() {
+        const vendorStore = useVendorStore()
+        const { vendors } = storeToRefs(vendorStore)
+
         const AVStore = useAVStore()
         const { get_lib_from_av, map_av_dt_filter } = AVStore
 
@@ -26,6 +30,7 @@ export default {
         useDataTable(table_id)
 
         return {
+            vendors,
             get_lib_from_av,
             map_av_dt_filter,
             table_id,
@@ -67,6 +72,15 @@ export default {
             let default_search = this.$route.query.q
             let table_id = this.table_id
 
+            window['vendors'] = this.vendors.map(e => {
+                e['_id'] = e['id']
+                e['_str'] = e['name']
+                return e
+            })
+            let vendors_map = this.vendors.reduce((map, e) => {
+                map[e.id] = e
+                return map
+            }, {})
             let avs = ['av_license_types', 'av_license_statuses']
             avs.forEach(function (av_cat) {
                 window[av_cat] = map_av_dt_filter(av_cat)
@@ -99,6 +113,16 @@ export default {
                         }
                     },
                     {
+                        title: __("Vendor"),
+                        data: "vendor_id",
+                        searchable: true,
+                        orderable: true,
+                        render: function (data, type, row, meta) {
+                            return row.vendor_id != undefined ? escape_str(vendors_map[row.vendor_id].name) : ""
+                        }
+                    },
+
+                    {
                         title: __("Description"),
                         data: "description",
                         searchable: true,
@@ -189,8 +213,9 @@ export default {
                     })
                 },
                 preDrawCallback: function (settings) {
-                    $("#" + table_id).find("thead th").eq(2).attr('data-filter', 'av_license_types')
-                    $("#" + table_id).find("thead th").eq(3).attr('data-filter', 'av_license_statuses')
+                    $("#" + table_id).find("thead th").eq(1).attr('data-filter', 'vendors')
+                    $("#" + table_id).find("thead th").eq(3).attr('data-filter', 'av_license_types')
+                    $("#" + table_id).find("thead th").eq(4).attr('data-filter', 'av_license_statuses')
                 }
 
             }, license_table_settings, 1)
index 231ca2b..7cf6a2a 100644 (file)
                         </span>
                     </li>
                     <li>
+                        <label>{{ $t("Vendor") }}:</label>
+                        <span v-if="license.vendor_id">
+                            <a
+                                :href="`/cgi-bin/koha/acqui/booksellers.pl?booksellerid=${license.vendor_id}`"
+                            >
+                                {{ license.vendor.name }}
+                            </a>
+                        </span>
+                    </li>
+                    <li>
                         <label>{{ $t("Description") }}:</label>
                         <span>
                             {{ license.description }}
@@ -72,7 +82,6 @@
 
 <script>
 import { useAVStore } from "../../stores/authorised_values"
-import { storeToRefs } from "pinia"
 import { fetchLicense } from "../../fetch"
 
 export default {
@@ -92,6 +101,8 @@ export default {
             license: {
                 license_id: null,
                 name: '',
+                vendor_id: null,
+                vendor: null,
                 description: '',
                 type: '',
                 status: '',
index f9922dd..865f557 100644 (file)
@@ -7,7 +7,7 @@ export const fetchAgreement = async function (agreement_id) {
     await fetch(apiUrl, {
         headers: {
             "x-koha-embed":
-                "periods,user_roles,user_roles.patron,agreement_licenses,agreement_licenses.license,agreement_relationships,agreement_relationships.related_agreement,documents,agreement_packages,agreement_packages.package",
+                "periods,user_roles,user_roles.patron,agreement_licenses,agreement_licenses.license,agreement_relationships,agreement_relationships.related_agreement,documents,agreement_packages,agreement_packages.package,vendor",
         },
     })
         .then(checkError)
@@ -42,7 +42,11 @@ export const fetchLicense = async function (license_id) {
     if (!license_id) return;
     const apiUrl = "/api/v1/erm/licenses/" + license_id;
     let license;
-    await fetch(apiUrl)
+    await fetch(apiUrl, {
+        headers: {
+            "x-koha-embed": "vendor",
+        },
+    })
         .then(checkError)
         .then(
             (result) => {
@@ -58,7 +62,11 @@ export const fetchLicense = async function (license_id) {
 export const fetchLicenses = async function () {
     const apiUrl = "/api/v1/erm/licenses";
     let licenses;
-    await fetch(apiUrl)
+    await fetch(apiUrl, {
+        headers: {
+            "x-koha-embed": "vendor.name",
+        },
+    })
         .then(checkError)
         .then(
             (result) => {