]> git.evergreen-ils.org Git - Evergreen.git/blob - docs/TechRef/Circ/custom-best-hold-selection.txt
LP#1684011: My Account summary ebook link correction
[Evergreen.git] / docs / TechRef / Circ / custom-best-hold-selection.txt
1 Custom Best-Hold Selection
2 ==========================
3
4 Background
5 ----------
6
7 In the Evergreen ILS, during opportunistic capture (which occurs at copy
8 checkin time), the copy being checked in is evaluated by the system for its
9 fitness to fulfill outstanding holds.  When the copy might fulfill more than
10 one hold, a set of 'determinants' are used to rank the possible holds that
11 might be fulfilled, so that the best hold may be chosen.
12
13 Evergreen currently uses one of two possible sets of 'determinants' to rank
14 the holds that a given copy might fulfill.  An org-unit setting determines
15 which set of 'determinants' is used.
16
17 We will call these sets the "best-hold selection sort orders".  The best-hold
18 selection sort orders available for use at hold capture time are:
19
20 Traditional
21 ~~~~~~~~~~~
22   . 'pprox' - Proximity of capturing location to pickup library
23   . 'priority' - Group hold priority
24   . 'cut' - Hold cut-in-line
25   . 'depth' - Hold selection depth (deeper/narrower first)
26   . 'rtime' - Hold request time
27
28 FIFO
29 ~~~~
30   . 'priority' - Group hold priority
31   . 'cut' - Hold cut-in-line
32   . 'rtime' - Hold request time
33   . 'depth' - Hold selection depth (deeper/narrower first)
34   . 'pprox' - Proximity of capturing location to pickup library
35
36 In either of these scenarios, a case could be made for changing the order of
37 several fields. However, the use of these is currently controlled only by a
38 single org-unit setting to turn on or off FIFO (if FIFO is "off," the
39 Traditional set is used).
40
41 Adding more org-unit settings to control yet more hard-coded orderings is a
42 path to madness, and therefore we should support custom field ordering for
43 best-hold selection.
44
45 Proposal
46 --------
47
48 To that end, we propose a new table to define field importance, and a new org-
49 unit setting to replace "FIFO Holds" and select the appropriate definition for
50 the capturing location. The UI for creating or editing hold order definitions
51 should consist of a list for ordering the options, controlled by up-and-down
52 buttons both clickable and accessible by keyboard.  There will also be a field
53 for naming the definition and a save button.
54
55 This org-unit setting will be retrieved at capture time, instead of the FIFO
56 setting, and inspected by open-ils.storage.action.hold_request.nearest_hold.
57 If no value is set, the equivalent of the "traditional" order will be used.
58
59 An upgrade script will change all FIFO settings to version of the new setting
60 which points to the system-supplied definition that implements FIFO as it
61 stands today, thus avoiding functional changes and configuration problems.
62
63 Design
64 ------
65
66 Database Sketch
67 ~~~~~~~~~~~~~~~
68
69 The 'config.best_hold_order' database table will have two metadata columns
70 and eight data columns.
71
72 Each of the eight data columns corresponds to a similarly named column used for
73 ranking in the best-hold selection process (i.e., the 'determinants').  In a
74 given row, the value of each of these columns corresponds to its relative
75 priority in the ranking decision (lowest value representing the highest
76 priority).
77
78 Data columns with a null value have the effect of omitting the corresponding
79 determinant in the ORDER BY clause for best-hold selection when the given
80 best-hold selector order set is in play.
81
82 One of the 'determinants', *aprox*, depends on the Calculated Proximity
83 Adjustment enhancement (documented elsewhere).
84
85 The 'determinant' *rtime*, which in practice is virtually unique among the
86 set of all holds at a site, will always terminate the list of determinants
87 used in constructing the ORDER BY clause whenever it appears.  In other words,
88 because *rtime* will never tie anyway, no more comparisons after rtime have
89 any meaning.
90
91 The default best-hold order sets sketched here are subject to refinement and
92 are not guaranteed to represent the final product.
93
94 [source,sql]
95 ------------------------------------------------------------------------------
96
97 CREATE TABLE config.best_hold_order(
98     id          SERIAL      PRIMARY KEY,    -- (metadata)
99     name        TEXT        UNIQUE,   -- i18n (metadata)
100     pprox       INT, -- copy capture <-> pickup lib prox
101     hprox       INT, -- copy circ lib <-> request lib prox
102     aprox       INT, -- copy circ lib <-> pickup lib ADJUSTED prox on ahcm
103     priority    INT, -- group hold priority
104     cut         INT, -- cut-in-line
105     depth       INT, -- selection depth
106     htime       INT, -- time since last home-lib circ exceeds org-unit setting
107     rtime       INT  -- request time
108 );
109
110 -- At least one of these columns must contain a non-null value
111 ALTER TABLE config.best_hold_order ADD CHECK ((
112     pprox IS NOT NULL OR
113     hprox IS NOT NULL OR
114     aprox IS NOT NULL OR
115     priority IS NOT NULL OR
116     cut IS NOT NULL OR
117     depth IS NOT NULL OR
118     htime IS NOT NULL OR
119     rtime IS NOT NULL
120 ));
121
122 INSERT INTO config.best_hold_order (
123     name,
124     pprox, aprox, priority, cut, depth, rtime, htime, hprox
125 ) VALUES (
126     'Traditional',
127     1, 2, 3, 4, 5, 6, 7, 8
128 );
129
130 INSERT INTO config.best_hold_order (
131     name,
132     hprox, pprox, aprox, priority, cut, depth, rtime, htime
133 ) VALUES (
134     'Traditional with Holds-always-go-to-home-patrons',
135     1, 2, 3, 4, 5, 6, 7, 8
136 );
137
138 INSERT INTO config.best_hold_order (
139     name,
140     htime, hprox, pprox, aprox, priority, cut, depth, rtime
141 ) VALUES (
142     'Traditional with Holds-go-home',
143     1, 2, 3, 4, 5, 6, 7, 8
144 );
145
146 INSERT INTO config.best_hold_order (
147     name,
148     priority, cut, rtime, depth, pprox, hprox, aprox, htime
149 ) VALUES (
150     'FIFO',
151     1, 2, 3, 4, 5, 6, 7, 8
152 );
153
154 INSERT INTO config.best_hold_order (
155     name,
156     hprox, priority, cut, rtime, depth, pprox, aprox, htime
157 ) VALUES (
158     'FIFO with Holds-always-go-to-home-patrons',
159     1, 2, 3, 4, 5, 6, 7, 8
160 );
161
162 INSERT INTO config.best_hold_order (
163     name,
164     htime, priority, cut, rtime, depth, pprox, aprox, hprox
165 ) VALUES (
166     'FIFO with Holds-go-home',
167     1, 2, 3, 4, 5, 6, 7, 8
168 );
169
170 INSERT INTO config.org_unit_setting_type (
171     name, label, description, datatype, fm_class, update_perm
172 ) VALUES (
173     'circ.hold_capture_order',
174     'Best-hold selection precedence',
175     'Defines the sort order of holds when selecting a hold to fill using a given copy at capture time',
176     'link',
177     'cbho',
178     'ADMIN_HOLD_CAPTURE_SORT'
179 );
180
181 INSERT INTO config.org_unit_setting_type (
182     name, label, description, datatype, update_perm
183 ) VALUES (
184     'circ.hold_go_home_interval',
185     'Max foreign-circulation time',
186     'Time a copy can spend circulating away from its circ lib before returning there to fill a hold (if one exists there)',
187     'interval',
188     'ADMIN_HOLD_CAPTURE_SORT'
189 );
190
191 INSERT INTO actor.org_unit_setting (
192     org_unit, name, value
193 ) VALUES (
194     1,
195     'circ.hold_go_home_interval',
196     '6 months'
197 );
198
199 UPDATE actor.org_unit_setting SET
200     name = 'circ.hold_capture_order',
201     value = (SELECT id FROM config.hold_capture_sort WHERE name = 'FIFO')
202 WHERE
203     name = 'circ.holds_fifo';
204 ------------------------------------------------------------------------------
205
206
207 When constructing ORDER BY clauses, the *htime* determinant will be
208 represented by a more complex expression than the other determinants.  The
209 likely form of this will be as follows:
210
211 [source,sql]
212 -----------------------------------------------
213 CASE WHEN
214     ['value of org setting circ.hold_go_home_interval'] <
215         NOW() - ['timestamp of last circulation at copy circ lib']
216     THEN hprox      -- sic
217     ELSE 999
218 END
219
220 -----------------------------------------------
221
222 Middle Layer
223 ~~~~~~~~~~~~
224
225 The 'open-ils.storage.action.hold_request.nearest_hold' method issues a query
226 with an ORDER BY clause.
227
228 This clause, previously selected from two hard-coded choices based on a
229 boolean value indicating use- or don't-use-FIFO, will now be
230 dynamically prepared based on the order specified in the
231 'circ.hold_capture_order' org-unit setting.
232
233 User Interface
234 ~~~~~~~~~~~~~~
235
236 A user interface will allow the creation of new best-hold orders and the
237 editing of existing ones, given sufficient user permission.
238
239 The name field (metadata) will be editable with a free-form text widget, and
240 the remaining (data) fields will be represented by objects that the user
241 manipulates via clickable buttons (also keyboard accessible) to indicate order.
242
243 ////
244 vim: ft=asciidoc
245 ////
246
247