]> git.evergreen-ils.org Git - Evergreen.git/blob - docs/TechRef/Circ/custom-best-hold-selection.adoc
LP#1869794 new best hold sort order
[Evergreen.git] / docs / TechRef / Circ / custom-best-hold-selection.adoc
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     owning_lib_to_home_lib_prox      INT, -- copy owning lib <-> user home lib prox
103     aprox       INT, -- copy circ lib <-> pickup lib ADJUSTED prox on ahcm
104     priority    INT, -- group hold priority
105     cut         INT, -- cut-in-line
106     depth       INT, -- selection depth
107     htime       INT, -- time since last home-lib circ exceeds org-unit setting
108     rtime       INT  -- request time
109 );
110
111 -- At least one of these columns must contain a non-null value
112 ALTER TABLE config.best_hold_order ADD CHECK ((
113     pprox IS NOT NULL OR
114     hprox IS NOT NULL OR
115     owning_lib_to_home_lib_prox IS NOT NULL OR
116     aprox IS NOT NULL OR
117     priority IS NOT NULL OR
118     cut IS NOT NULL OR
119     depth IS NOT NULL OR
120     htime IS NOT NULL OR
121     rtime IS NOT NULL
122 ));
123
124 INSERT INTO config.best_hold_order (
125     name,
126     pprox, aprox, priority, cut, depth, rtime, htime, hprox
127 ) VALUES (
128     'Traditional',
129     1, 2, 3, 4, 5, 6, 7, 8
130 );
131
132 INSERT INTO config.best_hold_order (
133     name,
134     hprox, pprox, aprox, priority, cut, depth, rtime, htime
135 ) VALUES (
136     'Traditional with Holds-always-go-to-home-patrons',
137     1, 2, 3, 4, 5, 6, 7, 8
138 );
139
140 INSERT INTO config.best_hold_order (
141     name,
142     htime, hprox, pprox, aprox, priority, cut, depth, rtime
143 ) VALUES (
144     'Traditional with Holds-go-home',
145     1, 2, 3, 4, 5, 6, 7, 8
146 );
147
148 INSERT INTO config.best_hold_order (
149     name,
150     priority, cut, rtime, depth, pprox, hprox, aprox, htime
151 ) VALUES (
152     'FIFO',
153     1, 2, 3, 4, 5, 6, 7, 8
154 );
155
156 INSERT INTO config.best_hold_order (
157     name,
158     hprox, priority, cut, rtime, depth, pprox, aprox, htime
159 ) VALUES (
160     'FIFO with Holds-always-go-to-home-patrons',
161     1, 2, 3, 4, 5, 6, 7, 8
162 );
163
164 INSERT INTO config.best_hold_order (
165     name,
166     htime, priority, cut, rtime, depth, pprox, aprox, hprox
167 ) VALUES (
168     'FIFO with Holds-go-home',
169     1, 2, 3, 4, 5, 6, 7, 8
170 );
171
172 INSERT INTO config.best_hold_order (
173     name,
174     owning_lib_to_home_lib_prox, hprox, approx, pprox, aprox, priority, cut, depth, rtime
175 ) VALUES (
176     'Traditional with Holds-chase-home-lib-patrons',
177     1, 2, 3, 4, 5, 6, 7, 8, 9
178 );
179
180 INSERT INTO config.org_unit_setting_type (
181     name, label, description, datatype, fm_class, update_perm
182 ) VALUES (
183     'circ.hold_capture_order',
184     'Best-hold selection precedence',
185     'Defines the sort order of holds when selecting a hold to fill using a given copy at capture time',
186     'link',
187     'cbho',
188     'ADMIN_HOLD_CAPTURE_SORT'
189 );
190
191 INSERT INTO config.org_unit_setting_type (
192     name, label, description, datatype, update_perm
193 ) VALUES (
194     'circ.hold_go_home_interval',
195     'Max foreign-circulation time',
196     'Time a copy can spend circulating away from its circ lib before returning there to fill a hold (if one exists there)',
197     'interval',
198     'ADMIN_HOLD_CAPTURE_SORT'
199 );
200
201 INSERT INTO actor.org_unit_setting (
202     org_unit, name, value
203 ) VALUES (
204     1,
205     'circ.hold_go_home_interval',
206     '6 months'
207 );
208
209 UPDATE actor.org_unit_setting SET
210     name = 'circ.hold_capture_order',
211     value = (SELECT id FROM config.hold_capture_sort WHERE name = 'FIFO')
212 WHERE
213     name = 'circ.holds_fifo';
214 ------------------------------------------------------------------------------
215
216
217 When constructing ORDER BY clauses, the *htime* determinant will be
218 represented by a more complex expression than the other determinants.  The
219 likely form of this will be as follows:
220
221 [source,sql]
222 -----------------------------------------------
223 CASE WHEN
224     ['value of org setting circ.hold_go_home_interval'] <
225         NOW() - ['timestamp of last circulation at copy circ lib']
226     THEN hprox      -- sic
227     ELSE 999
228 END
229
230 -----------------------------------------------
231
232 Middle Layer
233 ~~~~~~~~~~~~
234
235 The 'open-ils.storage.action.hold_request.nearest_hold' method issues a query
236 with an ORDER BY clause.
237
238 This clause, previously selected from two hard-coded choices based on a
239 boolean value indicating use- or don't-use-FIFO, will now be
240 dynamically prepared based on the order specified in the
241 'circ.hold_capture_order' org-unit setting.
242
243 User Interface
244 ~~~~~~~~~~~~~~
245
246 A user interface will allow the creation of new best-hold orders and the
247 editing of existing ones, given sufficient user permission.
248
249 The name field (metadata) will be editable with a free-form text widget, and
250 the remaining (data) fields will be represented by objects that the user
251 manipulates via clickable buttons (also keyboard accessible) to indicate order.
252
253 ////
254 vim: ft=asciidoc
255 ////
256
257