d4221f5005f2a5f674e325f198737bb26a484962
[sitka/overdrive-evergreen-opac.git] / src / od_data.coffee
1 define [
2         'lodash'
3         'moment'
4 ], (
5         _
6         M
7 ) ->
8
9         # A base class defining utilitarian methods
10         class U
11                 constructor: (x) ->
12                         return unless x
13                         t = @
14                         t extends x
15                         return
16
17                 # Mutate an ISO 8601 date string into a Moment object.  If the argument is
18                 # just a date value, then it specifies an absolute date in ISO 8601 format.
19                 # If the argument is a pair, then it specifies a date relative to now.  For
20                 # an ISO 8601 date, we correct for what seems to be an error in time zone,
21                 # Zulu time is really East Coast time.
22                 momentize: (date, unit) ->
23                         switch arguments.length
24                                 when 1
25                                         if date then M(date.replace /Z$/, '-0400') else M()
26                                 when 2
27                                         if date then M().add date, unit else M()
28                                 else M()
29
30
31         class Metadata extends U
32                 constructor: (x) ->
33                         super x
34
35                         # Convert ID to upper case to match same case found in EG catalogue
36                         @id = @id.toUpperCase()
37                         # Provide a simplified notion of author: first name in creators
38                         # list having a role of author
39                         @author = (v.name for v in @creators when v.role is 'Author')[0] or ''
40
41                         return
42
43
44         class Availability extends U
45                 constructor: (x, email_address) ->
46                         super x
47
48                         @zero()
49                         @hold email_address if @actions?.hold
50
51                         return @
52
53                 # Add zero values
54                 zero: ->
55                         @copiesOwned     = 0 unless @copiesOwned
56                         @copiesAvailable = 0 unless @copiesAvailable
57                         @numberOfHolds   = 0 unless @numberOfHolds
58                         return @
59
60                 hold: (email_address) ->
61                         # The reserve ID is empty in the actions.hold.fields; we have to fill it ourselves.
62                         _.where(@actions.hold.fields, name: 'reserveId')[0].value = @id
63                         # We jam the email address from the prefs page into the fields object from the server
64                         # so that the new form will display it.
65                         if email_address
66                                 _.where(@actions.hold.fields, name: 'emailAddress')[0].value = email_address
67                         return @
68
69
70         class Holds extends U
71                 constructor: (x) ->
72                         super x
73
74                         @add()
75                         .remove()
76                         .moments()
77                         .count()
78                         .sort()
79
80                         return
81
82                 # Ensure there is always a holds list, even if it's empty
83                 add: ->
84                         @holds = [] if @holds is undefined
85                         return @
86
87                 # Delete action to release a suspension if a hold is not
88                 # suspended, because such actions are redundant
89                 remove: ->
90                         delete x.actions.releaseSuspension for x in @holds when not x.holdSuspension
91                         return @
92
93                 # For each hold, convert any ISO 8601 date strings into a
94                 # Moment object (at local time zone)
95                 moments: ->
96                         for x in @holds
97                                 x.holdPlacedDate = @momentize x.holdPlacedDate
98                                 x.holdExpires = @momentize x.holdExpires
99                                 if x.holdSuspension
100                                         x.holdSuspension.numberOfDays = @momentize x.holdSuspension.numberOfDays, 'days'
101                         return @
102
103                 # Count the number of holds that can be checked out now
104                 count: ->
105                         @ready = _.countBy @holds, (x) -> if x.actions.checkout then 'forCheckout' else 'other'
106                         @ready.forCheckout = 0 unless @ready.forCheckout
107                         return @
108
109                 # Sort the holds list by position and placed date
110                 # and sort ready holds first
111                 sort: ->
112                         @holds = _(@holds)
113                                 .sortBy ['holdListPosition', 'holdPlacedDate']
114                                 .sortBy (x) -> x.actions.checkout
115                                 .value()
116                         return @
117
118
119         class Checkouts extends U
120                 constructor: (x) ->
121                         super x
122
123                         @add()
124                         .moments()
125                         .sort()
126
127                         return
128
129                 # Ensure there is always a checkouts list, even if it's empty
130                 add: ->
131                         @checkouts = [] if @checkouts is undefined
132                         return @
133
134                 # For each checkout, convert any ISO 8601 date strings into a
135                 # Moment object (at local time zone)
136                 moments: ->
137                         for x in @checkouts
138                                 x.expires = @momentize x.expires
139                         return @
140
141                 # Sort the checkout list by expiration date
142                 sort: ->
143                         @checkouts = _.sortBy @checkouts, 'expires'
144                         return @
145
146
147         class Interests
148                 constructor: (h, c) ->
149                         return {
150                                 nHolds: h.totalItems
151                                 nHoldsReady: h.ready.forCheckout
152                                 nCheckouts: c.totalItems
153                                 nCheckoutsReady: c.totalCheckouts
154                                 ofHolds: h.holds
155                                 ofCheckouts: c.checkouts
156                                 # The following property is a map from product ID to a hold or
157                                 # a checkout object, eg, interests.byID(124)
158                                 byID: do (hs = h.holds, cs = c.checkouts) ->
159                                         byID = {}
160                                         for v, n in hs
161                                                 v.type = 'hold'
162                                                 byID[v.reserveId] = v
163                                         for v, n in cs
164                                                 v.type = 'checkout'
165                                                 byID[v.reserveId] = v
166                                         return byID
167                         }
168         
169         return {
170                 Metadata:     Metadata
171                 Availability: Availability
172                 Holds:        Holds
173                 Checkouts:    Checkouts
174                 Interests:    Interests
175         }