Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.67% covered (danger)
0.67%
2 / 297
0.00% covered (danger)
0.00%
0 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
NewGenLib
0.67% covered (danger)
0.67%
2 / 297
0.00% covered (danger)
0.00%
0 / 12
2701.74
0.00% covered (danger)
0.00%
0 / 1
 init
20.00% covered (danger)
20.00%
2 / 10
0.00% covered (danger)
0.00%
0 / 1
7.61
 getHolding
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 getMyFines
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 1
30
 getMyHolds
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
90
 getMyProfile
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
30
 getMyTransactions
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
30
 getStatus
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 getStatuses
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 patronLogin
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
12
 getNewItems
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 getPurchaseHistory
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getItemStatus
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
72
1<?php
2
3/**
4 * ILS Driver for NewGenLib
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Verus Solutions Pvt.Ltd 2010.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  ILS_Drivers
25 * @author   Verus Solutions <info@verussolutions.biz>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org/wiki/development:plugins:ils_drivers Wiki
28 */
29
30namespace VuFind\ILS\Driver;
31
32use PDO;
33use PDOException;
34use VuFind\Date\DateException;
35use VuFind\Exception\ILS as ILSException;
36
37use function count;
38use function is_array;
39
40/**
41 * ILS Driver for NewGenLib
42 *
43 * @category VuFind
44 * @package  ILS_Drivers
45 * @author   Verus Solutions <info@verussolutions.biz>
46 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
47 * @link     https://vufind.org/wiki/development:plugins:ils_drivers Wiki
48 */
49class NewGenLib extends AbstractBase
50{
51    /**
52     * Database connection
53     *
54     * @var PDO
55     */
56    protected $db;
57
58    /**
59     * Initialize the driver.
60     *
61     * Validate configuration and perform all resource-intensive tasks needed to
62     * make the driver active.
63     *
64     * @throws ILSException
65     * @return void
66     */
67    public function init()
68    {
69        if (empty($this->config)) {
70            throw new ILSException('Configuration needs to be set.');
71        }
72
73        try {
74            $connectStr = 'pgsql:host=' . $this->config['Catalog']['hostname'] .
75                ' user=' . $this->config['Catalog']['user'] .
76                ' dbname=' . $this->config['Catalog']['database'] .
77                ' password=' . $this->config['Catalog']['password'] .
78                ' port=' . $this->config['Catalog']['port'];
79            $this->db = new PDO($connectStr);
80        } catch (PDOException $e) {
81            throw $e;
82        }
83    }
84
85    /**
86     * Get Holding
87     *
88     * This is responsible for retrieving the holding information of a certain
89     * record.
90     *
91     * @param string $RecordID The record id to retrieve the holdings for
92     * @param array  $patron   Patron data
93     * @param array  $options  Extra options (not currently used)
94     *
95     * @throws DateException
96     * @throws ILSException
97     * @return array           On success, an associative array with the following
98     * keys: id, availability (boolean), status, location, reserve, callnumber,
99     * duedate, number, barcode.
100     *
101     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
102     */
103    public function getHolding($RecordID, array $patron = null, array $options = [])
104    {
105        $holding = $this->getItemStatus($RecordID);
106        for ($i = 0; $i < count($holding); $i++) {
107            // add extra data
108            $duedateql = 'select due_date from cir_transaction where ' .
109                "accession_number='" . $holding[$i]['number'] .
110                "' and document_library_id='" . $holding[$i]['library_id'] .
111                "' and status='A'";
112            try {
113                $sqlStmt2 = $this->db->prepare($duedateql);
114                $sqlStmt2->execute();
115            } catch (PDOException $e1) {
116                $this->throwAsIlsException($e1);
117            }
118            $duedate = '';
119            while ($rowDD = $sqlStmt2->fetch(PDO::FETCH_ASSOC)) {
120                $duedate = $rowDD['due_date'];
121            }
122            // add needed entries
123            $holding[$i]['duedate'] = $duedate;
124            // field with link to place holdings or recalls
125            //$holding[$i]['link'] = "test";
126
127            // remove not needed entries
128            unset($holding[$i]['library_id']);
129        }
130
131        return $holding;
132    }
133
134    /**
135     * Get Patron Fines
136     *
137     * This is responsible for retrieving all fines by a specific patron.
138     *
139     * @param array $patron The patron array from patronLogin
140     *
141     * @throws DateException
142     * @throws ILSException
143     * @return mixed        Array of the patron's fines on success.
144     */
145    public function getMyFines($patron)
146    {
147        $MyFines = [];
148        $pid = $patron['cat_username'];
149        $fine = 'Overdue';
150        $LibId = 1;
151        $mainsql = 'select d.volume_id as volume_id, c.status as status, ' .
152            'v.volume_id as volume_id, d.accession_number as ' .
153            'accession_number, v.cataloguerecordid as cataloguerecordid, ' .
154            'v.owner_library_id as owner_library_id, c.patron_id as patron_id, ' .
155            'c.due_date as due_date, c.ta_date as ta_date, c.fine_amt as ' .
156            'fine_amt, c.ta_id as ta_id,c.library_id as library_id from ' .
157            'document d,cat_volume v,cir_transaction c where ' .
158            "d.volume_id=v.volume_id and v.owner_library_id='" . $LibId .
159            "' and c.accession_number=d.accession_number and " .
160            "c.document_library_id=d.library_id and c.patron_id='" .
161            $pid . "' and c.status in('B','LOST') and c.fine_amt>0";
162
163        try {
164            $sqlStmt = $this->db->prepare($mainsql);
165            $sqlStmt->execute();
166        } catch (PDOException $e) {
167            $this->throwAsIlsException($e);
168        }
169        $id = '';
170        while ($row = $sqlStmt->fetch(PDO::FETCH_ASSOC)) {
171            $id = $row['cataloguerecordid'] . '_' . $row['owner_library_id'];
172            $amount = $row['fine_amt'] * 100;
173            $checkout = $row['ta_date'];
174            $duedate = $row['due_date'];
175            $paidamtsql = 'select sum(f.fine_amt_paid) as fine_amt_paid from ' .
176                'cir_transaction_fine f where f.ta_id=' . $row['ta_id'] .
177                ' and f.library_id=' . $row['library_id'];
178            try {
179                $sqlStmt1 = $this->db->prepare($paidamtsql);
180                $sqlStmt1->execute();
181            } catch (PDOException $e1) {
182                $this->throwAsIlsException($e1);
183            }
184            $paidamt = '';
185            $balance = '';
186            while ($rowpaid = $sqlStmt1->fetch(PDO::FETCH_ASSOC)) {
187                $paidamt = $rowpaid['fine_amt_paid'] * 100;
188                $balance = $amount - $paidamt;
189            }
190
191            $MyFines[] = ['amount' => $amount,
192                'checkout' => $checkout,
193                'fine' => $fine,
194                'balance' => $balance,
195                'duedate' => $duedate,
196                'id' => $id];
197        }
198
199        return $MyFines;
200    }
201
202    /**
203     * Get Patron Holds
204     *
205     * This is responsible for retrieving all holds by a specific patron.
206     *
207     * @param array $patron The patron array from patronLogin
208     *
209     * @throws DateException
210     * @throws ILSException
211     * @return array        Array of the patron's holds on success.
212     */
213    public function getMyHolds($patron)
214    {
215        $holds = [];
216        $PatId = $patron['cat_username'];
217        $LibId = 1;
218        //SQL Statement
219        $mainsql = 'select d.volume_id as volume_id, c.status as status, ' .
220            'v.volume_id as volume_id, d.accession_number as accession_number, ' .
221            'v.cataloguerecordid as cataloguerecordid, v.owner_library_id as ' .
222            'owner_library_id, c.patron_id as patron_id from ' .
223            'document d,cat_volume v,cir_transaction c where ' .
224            "d.volume_id=v.volume_id and v.owner_library_id='" . $LibId .
225            "' and c.accession_number=d.accession_number and " .
226            "c.document_library_id=d.library_id and c.patron_id='" . $PatId .
227            "' and c.status='C'";
228        try {
229            $sqlStmt = $this->db->prepare($mainsql);
230            $sqlStmt->execute();
231        } catch (PDOException $e) {
232            $this->throwAsIlsException($e);
233        }
234        while ($row = $sqlStmt->fetch(PDO::FETCH_ASSOC)) {
235            $type = 'RECALLED ITEM - Return the item to the library';
236            $rIdql = 'select due_date, ta_date from cir_transaction ' .
237                "where patron_id='" . $row['patron_id'] . "'";
238            try {
239                $sqlStmt2 = $this->db->prepare($rIdql);
240                $sqlStmt2->execute();
241            } catch (PDOException $e1) {
242                $this->throwAsIlsException($e1);
243            }
244            $RecordId = $row['cataloguerecordid'] . '_' . $row['owner_library_id'];
245            $duedate = '';
246            $tadate = '';
247            while ($rowDD = $sqlStmt2->fetch(PDO::FETCH_ASSOC)) {
248                $duedate = $rowDD['due_date'];
249                $tadate = $rowDD['ta_date'];
250            }
251            $holds[] = ['type' => $type,
252                'id' => $RecordId,
253                'location' => null,
254                'reqnum' => null,
255                'expire' => $duedate . ' ' . $type,
256                'create' => $tadate];
257        }
258        //SQL Statement 2
259        $mainsql2 = 'select v.cataloguerecordid as cataloguerecordid, ' .
260            'v.owner_library_id as owner_library_id, v.volume_id as volume_id, ' .
261            'r.volume_id as volume_id, r.queue_no as queue_no, ' .
262            'r.reservation_date as reservation_date, r.status as status ' .
263            "from cir_reservation r, cat_volume v where r.patron_id='" . $PatId .
264            "' and r.library_id='" . $LibId .
265            "' and r.volume_id=v.volume_id and r.status in ('A', 'B')";
266        try {
267            $sqlStmt2 = $this->db->prepare($mainsql2);
268            $sqlStmt2->execute();
269        } catch (PDOException $e) {
270            $this->throwAsIlsException($e);
271        }
272        while ($row2 = $sqlStmt2->fetch(PDO::FETCH_ASSOC)) {
273            $location = '';
274            $type2 = '';
275            switch ($row2['status']) {
276                case 'A':
277                    $location = 'Checked out - No copy available in the library';
278                    $type2 = $row2['queue_no'];
279                    break;
280                case 'B':
281                    $location = 'Item available at the circulation desk';
282                    $type2 = 'INTIMATED';
283                    break;
284            }
285            $RecordId2 = $row2['cataloguerecordid'] . '_' .
286                $row2['owner_library_id'];
287            $holds[] = ['type' => $type2,
288                'id' => $RecordId2,
289                'location' => $location,
290                'reqnum' => $row2['queue_no'],
291                'expire' => null . ' ' . $type2,
292                'create' => $row2['reservation_date']];
293        }
294        return $holds;
295    }
296
297    /**
298     * Get Patron Profile
299     *
300     * This is responsible for retrieving the profile for a specific patron.
301     *
302     * @param array $patron The patron array
303     *
304     * @throws ILSException
305     * @return array        Array of the patron's profile data on success.
306     */
307    public function getMyProfile($patron)
308    {
309        $profile = null;
310        $catusr = $patron['cat_username'];
311        $catpswd = $patron['cat_password'];
312        $sql = 'select p.patron_id as patron_id,p.user_password as ' .
313            'user_password, p.fname as fname, p.lname as lname, p.address1 as ' .
314            'address1, p.address2 as address2, p.pin as pin, p.phone1 as phone1 ' .
315            "from patron p where p.patron_id='" . $catusr .
316            "' and p.user_password='" . $catpswd . "'";
317        try {
318            $sqlStmt = $this->db->prepare($sql);
319            $sqlStmt->execute();
320        } catch (PDOException $e) {
321            $this->throwAsIlsException($e);
322        }
323        while ($row = $sqlStmt->fetch(PDO::FETCH_ASSOC)) {
324            if ($catusr != $row['patron_id'] || $catpswd != $row['user_password']) {
325                return null;
326            } else {
327                $profile = ['firstname' => $row['fname'],
328                    'lastname' => $row['lname'],
329                    'address1' => $row['address1'],
330                    'address2' => $row['address2'],
331                    'zip' => $row['pin'],
332                    'phone' => $row['phone1'],
333                    'group' => null];
334            }
335        }
336        return $profile;
337    }
338
339    /**
340     * Get Patron Transactions
341     *
342     * This is responsible for retrieving all transactions (i.e. checked out items)
343     * by a specific patron.
344     *
345     * @param array $patron The patron array from patronLogin
346     *
347     * @throws DateException
348     * @throws ILSException
349     * @return array        Array of the patron's transactions on success.
350     */
351    public function getMyTransactions($patron)
352    {
353        $transactions = [];
354        $PatId = $patron['cat_username'];
355        $mainsql = 'select c.due_date as due_date, c.status as status, c.ta_id ' .
356            'as ta_id, c.library_id as library_id, c.accession_number as ' .
357            'accession_number, v.cataloguerecordid as cataloguerecordid, ' .
358            'v.owner_library_id as owner_library_id, c.patron_id as ' .
359            'patron_id from document d,cat_volume v,cir_transaction c where ' .
360            "d.volume_id=v.volume_id and v.owner_library_id='1' and " .
361            'c.accession_number=d.accession_number and ' .
362            "c.document_library_id=d.library_id and c.patron_id='" .
363            $PatId . "' and c.status in('A','C')";
364        try {
365            $sqlStmt = $this->db->prepare($mainsql);
366            $sqlStmt->execute();
367        } catch (PDOException $e) {
368            $this->throwAsIlsException($e);
369        }
370        while ($row = $sqlStmt->fetch(PDO::FETCH_ASSOC)) {
371            $countql = 'select count(*) as total from cir_transaction c, ' .
372                "cir_transaction_renewal r where r.ta_id='" . $row['ta_id'] .
373                "' and r.library_id='" . $row['library_id'] .
374                "' and c.status='A'";
375            try {
376                $sql = $this->db->prepare($countql);
377                $sql->execute();
378            } catch (PDOException $e) {
379                $this->throwAsIlsException($e);
380            }
381            $RecordId = $row['cataloguerecordid'] . '_' . $row['owner_library_id'];
382            $count = '';
383            while ($srow = $sql->fetch(PDO::FETCH_ASSOC)) {
384                $count = 'Renewed = ' . $srow['total'];
385            }
386            $transactions[] = ['duedate' => $row['due_date'] . ' ' . $count,
387                'id' => $RecordId,
388                'barcode' => $row['accession_number'],
389                'renew' => $count,
390                'reqnum' => null];
391        }
392        return $transactions;
393    }
394
395    /**
396     * Get Status
397     *
398     * This is responsible for retrieving the status information of a certain
399     * record.
400     *
401     * @param string $RecordID The record id to retrieve the holdings for
402     *
403     * @throws ILSException
404     * @return mixed           On success, an associative array with the following
405     * keys: id, availability (boolean), status, location, reserve, callnumber.
406     */
407    public function getStatus($RecordID)
408    {
409        $status = $this->getItemStatus($RecordID);
410        if (!is_array($status)) {
411            return $status;
412        }
413        // remove not needed entries within the items within the result array
414        for ($i = 0; $i < count($status); $i++) {
415            unset($status[$i]['number']);
416            unset($status[$i]['barcode']);
417            unset($status[$i]['library_id']);
418        }
419        return $status;
420    }
421
422    /**
423     * Get Statuses
424     *
425     * This is responsible for retrieving the status information for a
426     * collection of records.
427     *
428     * @param array $StatusResult The array of record ids to retrieve the status for
429     *
430     * @throws ILSException
431     * @return array              An array of getStatus() return values on success.
432     */
433    public function getStatuses($StatusResult)
434    {
435        $status = [];
436        foreach ($StatusResult as $id) {
437            $status[] = $this->getStatus($id);
438        }
439        return $status;
440    }
441
442    /**
443     * Patron Login
444     *
445     * This is responsible for authenticating a patron against the catalog.
446     *
447     * @param string $username The patron username
448     * @param string $password The patron's password
449     *
450     * @throws ILSException
451     * @return mixed          Associative array of patron info on successful login,
452     * null on unsuccessful login.
453     */
454    public function patronLogin($username, $password)
455    {
456        //SQL Statement
457        $sql = 'select p.patron_id as patron_id, p.library_id as library_id, ' .
458            'p.fname as fname, p.lname as lname, p.user_password as ' .
459            'user_password, p.membership_start_date as membership_start_date, ' .
460            'p.membership_expiry_date as membership_expiry_date, p.email as ' .
461            'email from patron p where p.patron_id=:patronId' .
462            "' and p.user_password=:password and p.membership_start_date " .
463            '<= current_date and p.membership_expiry_date > current_date';
464
465        try {
466            $sqlStmt = $this->db->prepare($sql);
467            $sqlStmt->execute([':patronId' => $username, ':password' => $password]);
468        } catch (PDOException $e) {
469            $this->throwAsIlsException($e);
470        }
471        $row = $sqlStmt->fetch(PDO::FETCH_ASSOC);
472        if (!$row) {
473            return null;
474        }
475        return [
476            'id' => $row['patron_id'],
477            'firstname' => $row['fname'],
478            'lastname' => $row['lname'],
479            'cat_username' => $username,
480            'cat_password' => $password,
481            'email' => $row['email'],
482            'major' => null,
483            'college' => null,
484        ];
485    }
486
487    /**
488     * Get New Items
489     *
490     * Retrieve the IDs of items recently added to the catalog.
491     *
492     * @param int $page    Page number of results to retrieve (counting starts at 1)
493     * @param int $limit   The size of each page of results to retrieve
494     * @param int $daysOld The maximum age of records to retrieve in days (max. 30)
495     * @param int $fundId  optional fund ID to use for limiting results (use a value
496     * returned by getFunds, or exclude for no limit); note that "fund" may be a
497     * misnomer - if funds are not an appropriate way to limit your new item
498     * results, you can return a different set of values from getFunds. The
499     * important thing is that this parameter supports an ID returned by getFunds,
500     * whatever that may mean.
501     *
502     * @throws ILSException
503     * @return array       Associative array with 'count' and 'results' keys
504     *
505     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
506     */
507    public function getNewItems($page, $limit, $daysOld, $fundId = null)
508    {
509        // Do some initial work in solr so we aren't repeating it inside this loop.
510        $retVal = [];
511        $retVal[][] = [];
512
513        $offset = ($page - 1) * $limit;
514        $sql = 'select cataloguerecordid,owner_library_id from cataloguerecord ' .
515            "where created_on + interval '$daysOld days' >= " .
516            "current_timestamp offset $offset limit $limit";
517        try {
518            $sqlStmt = $this->db->prepare($sql);
519            $sqlStmt->execute();
520        } catch (PDOException $e) {
521            $this->throwAsIlsException($e);
522        }
523
524        $results = [];
525        while ($row = $sqlStmt->fetch(PDO::FETCH_ASSOC)) {
526            $id = $row['cataloguerecordid'] . '_' . $row['owner_library_id'];
527            $results[] = $id;
528        }
529        $retVal = ['count' => count($results), 'results' => []];
530        foreach ($results as $result) {
531            $retVal['results'][] = ['id' => $result];
532        }
533        return $retVal;
534    }
535
536    /**
537     * Get Purchase History
538     *
539     * This is responsible for retrieving the acquisitions history data for the
540     * specific record (usually recently received issues of a serial).
541     *
542     * @param string $id The record id to retrieve the info for
543     *
544     * @throws ILSException
545     * @return array     An array with the acquisitions data on success.
546     *
547     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
548     */
549    public function getPurchaseHistory($id)
550    {
551        // TODO
552        return [];
553    }
554
555    /**
556     * Support method to get information about the items attached to a record
557     *
558     * @param string $RecordID Record ID
559     *
560     * @return array
561     */
562    protected function getItemStatus($RecordID)
563    {
564        $StatusResult = [];
565        $pieces = explode('_', $RecordID);
566        $CatId = $pieces[0];
567        $LibId = $pieces[1];
568        //SQL Statement
569        $mainsql = 'select d.status as status, d.location_id as location_id, ' .
570            'd.call_number as call_number, d.accession_number as accession_number,' .
571            ' d.barcode as barcode, d.library_id as library_id from ' .
572            'document d,cat_volume v where d.volume_id=v.volume_id and ' .
573            "v.cataloguerecordid='" . $CatId . "' and v.owner_library_id=" . $LibId;
574
575        try {
576            $sqlSmt = $this->db->prepare($mainsql);
577            $sqlSmt->execute();
578        } catch (PDOException $e) {
579            $this->throwAsIlsException($e);
580        }
581        $reserve = 'N';
582        while ($row = $sqlSmt->fetch(PDO::FETCH_ASSOC)) {
583            switch ($row['status']) {
584                case 'B':
585                    $status = 'Available';
586                    $available = true;
587                    $reserve = 'N';
588                    break;
589                case 'A':
590                    // Instead of relying on status = 'On holds shelf',
591                    // I might want to see if:
592                    // action.hold_request.current_copy = asset.copy.id
593                    // and action.hold_request.capture_time is not null
594                    // and I think action.hold_request.fulfillment_time is null
595                    $status = 'Checked Out';
596                    $available = false;
597                    $reserve = 'N';
598                    break;
599                default:
600                    $status = 'Not Available';
601                    $available = false;
602                    $reserve = 'N';
603                    break;
604            }
605            $locationsql = "select location from location where location_id='" .
606                $row['location_id'] . "' and library_id=" . $row['library_id'];
607            try {
608                $sqlSmt1 = $this->db->prepare($locationsql);
609                $sqlSmt1->execute();
610            } catch (PDOException $e1) {
611                $this->throwAsIlsException($e1);
612            }
613            $location = '';
614            while ($rowLoc = $sqlSmt1->fetch(PDO::FETCH_ASSOC)) {
615                $location = $rowLoc['location'];
616            }
617            $StatusResult[] = ['id' => $RecordID,
618                'status' => $status,
619                'location' => $location,
620                'reserve' => $reserve,
621                'callnumber' => $row['call_number'],
622                'availability' => $available,
623                'number' => $row['accession_number'],
624                'barcode' => $row['barcode'],
625                'library_id' => $row['library_id']];
626        }
627        return $StatusResult;
628    }
629}