Skip to content

Commit 172c637

Browse files
authored
Merge branch 'main' into batch-action-owner-restriction
2 parents f6eb6b9 + a0be11d commit 172c637

23 files changed

Lines changed: 728 additions & 857 deletions

.github/workflows/go.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212
- '**.xsd'
1313
- '**.html'
1414
- '**.sql'
15-
- '**/sqlc.yaml'
15+
- '**.yaml'
1616
- '**/Makefile'
1717
- '**/Dockerfile' #run this workflow first to ensure tests are passing
1818
- '**/chart/**' #trigger also when chart templates chnage to force republish
@@ -26,7 +26,7 @@ on:
2626
- '**.xsd'
2727
- '**.html'
2828
- '**.sql'
29-
- '**/sqlc.yaml'
29+
- '**.yaml'
3030
- '**/Makefile'
3131
- '**/Dockerfile' #run this workflow first to ensure tests are passing
3232
- '**/chart/**' #trigger also when chart templates change to force republish

broker/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
/broker
33
/data
44
/pg_data
5+
/patron_request/service/statemodels/state-models.json

broker/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ generate-sqlc: $(SQL_GEN_OUT)
7777
generate-api: $(OAPI_GEN) $(PR_OAPI_GEN) $(PS_OAPI_GEN) $(SCHED_OAPI_GEN)
7878

7979
$(STATE_MODELS_JSON): $(STATE_MODELS_YAML)
80+
mkdir -p $(@D)
8081
$(GO) run github.com/mikefarah/yq/v4@v4.52.5 eval -o=json $< > $@.tmp
8182
mv -f $@.tmp $@
8283

broker/adapter/api_directory.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ func (a *ApiDirectory) FilterAndSort(ctx common.ExtendedContext, entries []Suppl
168168
for _, sup := range entries {
169169
var supMatch SupplierMatch
170170
supMatch.Symbol = sup.Symbol
171+
supMatch.Location = sup.Location
172+
supMatch.ShelvingLocation = sup.ShelvingLocation
173+
supMatch.ItemLoanPolicy = sup.ItemLoanPolicy
174+
supMatch.LocationPreference = sup.LocationPreference
175+
supMatch.ShelvingPreference = sup.ShelvingPreference
171176
supNetworks := getPeerNetworks(sup.CustomData)
172177
supMatch.Networks = make([]NetworkMatch, 0, len(supNetworks))
173178
for name := range supNetworks {
@@ -258,7 +263,7 @@ func (a *ApiDirectory) FilterAndSort(ctx common.ExtendedContext, entries []Suppl
258263
}
259264
return cmp.Compare(a.Name, b.Name)
260265
})
261-
if cost < math.MaxFloat64 {
266+
if cost < math.MaxFloat64 && holdingMatchesPolicy(sup) {
262267
supMatch.Match = true
263268
supMatch.Cost = fmt.Sprintf("%.2f", cost)
264269
sup.Cost = cost
@@ -279,7 +284,7 @@ func (a *ApiDirectory) FilterAndSort(ctx common.ExtendedContext, entries []Suppl
279284
}
280285
return CompareSuppliers(a, b)
281286
})
282-
slices.SortFunc(filtered, func(a, b Supplier) int {
287+
slices.SortStableFunc(filtered, func(a, b Supplier) int {
283288
return CompareSuppliers(a, b)
284289
})
285290
return filtered, rotaInfo
@@ -335,13 +340,40 @@ func CompareSuppliers(a, b SupplierOrdering) int {
335340
if sort != 0 {
336341
return sort
337342
}
343+
sort = cmp.Compare(b.GetLocationPreference(), a.GetLocationPreference())
344+
if sort != 0 {
345+
return sort
346+
}
347+
sort = cmp.Compare(b.GetShelvingPreference(), a.GetShelvingPreference())
348+
if sort != 0 {
349+
return sort
350+
}
338351
sort = cmp.Compare(a.GetRatio(), b.GetRatio())
339352
if sort != 0 {
340353
return sort
341354
}
342355
return cmp.Compare(a.GetSymbol(), b.GetSymbol())
343356
}
344357

358+
func holdingMatchesPolicy(sup Supplier) bool {
359+
if sup.LocationPreference < 0 || sup.ShelvingPreference < 0 {
360+
return false
361+
}
362+
policy := sup.CustomData.HoldingsPolicy
363+
if policy == nil {
364+
return true
365+
}
366+
if policy.ItemLoanPolicies == nil {
367+
return true
368+
}
369+
for _, itemPolicy := range *policy.ItemLoanPolicies {
370+
if itemPolicy.Code == sup.ItemLoanPolicy && !itemPolicy.Lendable {
371+
return false
372+
}
373+
}
374+
return true
375+
}
376+
345377
func getPeerNetworks(peerData directory.Entry) map[string]Network {
346378
networks := map[string]Network{}
347379
if peerData.Networks != nil {

broker/adapter/directory.go

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,36 @@ type SupplierOrdering interface {
3636
GetSymbol() string
3737
GetPriority() int
3838
GetCost() float64
39+
GetLocationPreference() int
40+
GetShelvingPreference() int
3941
GetRatio() float32
4042
IsLocal() bool
4143
}
4244

4345
type Supplier struct {
44-
LocalIdentifier string
45-
PeerId string
46-
CustomData directory.Entry
47-
Symbol string
48-
Priority int
49-
Cost float64
50-
Local bool
51-
Ratio float32
52-
SupplierStatus pgtype.Text
46+
LocalIdentifier string
47+
PeerId string
48+
CustomData directory.Entry
49+
Symbol string
50+
Priority int
51+
Cost float64
52+
Local bool
53+
Ratio float32
54+
SupplierStatus pgtype.Text
55+
Location string
56+
ShelvingLocation string
57+
ItemLoanPolicy string
58+
LocationPreference int
59+
ShelvingPreference int
5360
}
5461

55-
func (s Supplier) GetSymbol() string { return s.Symbol }
56-
func (s Supplier) GetPriority() int { return s.Priority }
57-
func (s Supplier) GetCost() float64 { return s.Cost }
58-
func (s Supplier) IsLocal() bool { return s.Local }
59-
func (s Supplier) GetRatio() float32 { return s.Ratio }
62+
func (s Supplier) GetSymbol() string { return s.Symbol }
63+
func (s Supplier) GetPriority() int { return s.Priority }
64+
func (s Supplier) GetCost() float64 { return s.Cost }
65+
func (s Supplier) GetLocationPreference() int { return s.LocationPreference }
66+
func (s Supplier) GetShelvingPreference() int { return s.ShelvingPreference }
67+
func (s Supplier) IsLocal() bool { return s.Local }
68+
func (s Supplier) GetRatio() float32 { return s.Ratio }
6069

6170
type Network struct {
6271
Name string `json:"name"`
@@ -96,14 +105,19 @@ type TierMatch struct {
96105
}
97106

98107
type SupplierMatch struct {
99-
Match bool `json:"match"`
100-
Networks []NetworkMatch `json:"networks"`
101-
Tiers []TierMatch `json:"tiers"`
102-
Symbol string `json:"symbol"`
103-
Priority int `json:"priority"`
104-
Cost string `json:"cost"`
105-
Local bool `json:"local"`
106-
Ratio float32 `json:"ratio"`
108+
Match bool `json:"match"`
109+
Networks []NetworkMatch `json:"networks"`
110+
Tiers []TierMatch `json:"tiers"`
111+
Symbol string `json:"symbol"`
112+
Priority int `json:"priority"`
113+
Cost string `json:"cost"`
114+
Local bool `json:"local"`
115+
Ratio float32 `json:"ratio"`
116+
Location string `json:"location,omitempty"`
117+
ShelvingLocation string `json:"shelvingLocation,omitempty"`
118+
ItemLoanPolicy string `json:"itemLoanPolicy,omitempty"`
119+
LocationPreference int `json:"locationPreference"`
120+
ShelvingPreference int `json:"shelvingPreference"`
107121
}
108122

109123
func (s SupplierMatch) GetSymbol() string { return s.Symbol }
@@ -112,8 +126,10 @@ func (s SupplierMatch) GetCost() float64 {
112126
f, _ := strconv.ParseFloat(s.Cost, 64)
113127
return f
114128
}
115-
func (s SupplierMatch) IsLocal() bool { return s.Local }
116-
func (s SupplierMatch) GetRatio() float32 { return s.Ratio }
129+
func (s SupplierMatch) IsLocal() bool { return s.Local }
130+
func (s SupplierMatch) GetRatio() float32 { return s.Ratio }
131+
func (s SupplierMatch) GetLocationPreference() int { return s.LocationPreference }
132+
func (s SupplierMatch) GetShelvingPreference() int { return s.ShelvingPreference }
117133

118134
type RotaInfo struct {
119135
Request Request `json:"request"`

broker/catalog/catalog.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Holding struct {
2323
LocalIdentifier string
2424
Location string
2525
ShelvingLocation string
26+
ItemLoanPolicy string
2627
CallNumber string
2728
ItemId string
2829
}

broker/catalog/holdings_parser_opac.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package catalog
33
import (
44
"encoding/xml"
55
"fmt"
6+
"strings"
67

78
"github.com/indexdata/crosslink/directory"
89
"github.com/indexdata/crosslink/marcxml"
@@ -24,10 +25,12 @@ func (p *OpacHoldingsParser) Parse(record []byte, params LookupParams) ([]Holdin
2425
for _, holding := range opacRecord.Holdings.Holding {
2526
availableNow := false
2627
itemId := ""
28+
itemLoanPolicy := ""
2729
for _, circ := range holding.Circulations.Circulation {
2830
// regrettably, YAZ uses 0 or 1 to indicate availability, instead of a boolean value
2931
if circ.AvailableNow.Value == "1" {
3032
itemId = circ.ItemId
33+
itemLoanPolicy = strings.TrimSpace(circ.AvailableThru)
3134
availableNow = true
3235
break
3336
}
@@ -38,6 +41,7 @@ func (p *OpacHoldingsParser) Parse(record []byte, params LookupParams) ([]Holdin
3841
ShelvingLocation: holding.ShelvingLocation,
3942
CallNumber: holding.CallNumber,
4043
ItemId: itemId,
44+
ItemLoanPolicy: itemLoanPolicy,
4145
})
4246
}
4347
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package catalog
2+
3+
import (
4+
"testing"
5+
6+
"github.com/indexdata/crosslink/directory"
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestOpacHoldingsParserReadsItemLoanPolicy(t *testing.T) {
12+
record := []byte(`<opacRecord>
13+
<bibliographicRecord/>
14+
<holdings>
15+
<holding>
16+
<localLocation>MAIN</localLocation>
17+
<shelvingLocation>STACKS</shelvingLocation>
18+
<callNumber>QA 1</callNumber>
19+
<circulations>
20+
<circulation>
21+
<availableNow value="0"/>
22+
<availableThru>IGNORED</availableThru>
23+
<itemId>unavailable-item</itemId>
24+
<renewable value="0"/>
25+
<onHold value="0"/>
26+
</circulation>
27+
<circulation>
28+
<availableNow value="1"/>
29+
<availableThru> NORMAL </availableThru>
30+
<itemId>available-item</itemId>
31+
<renewable value="1"/>
32+
<onHold value="0"/>
33+
</circulation>
34+
</circulations>
35+
</holding>
36+
</holdings>
37+
</opacRecord>`)
38+
parser := NewOpacHoldingsParser(directory.OpacHoldingsParserConfig{})
39+
40+
holdings, err := parser.Parse(record, LookupParams{})
41+
42+
require.NoError(t, err)
43+
if assert.Len(t, holdings, 1) {
44+
assert.Equal(t, "available-item", holdings[0].ItemId)
45+
assert.Equal(t, "NORMAL", holdings[0].ItemLoanPolicy)
46+
}
47+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
DROP INDEX IF EXISTS idx_event_batch_action_task_timestamp;
2+
3+
CREATE INDEX idx_event_batch_action_task_timestamp
4+
ON event ((event_data -> 'batchActionData' ->> 'taskId'), timestamp DESC)
5+
WHERE event_name = 'invoke-batch-action';
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
DROP INDEX IF EXISTS idx_event_batch_action_task_timestamp;
2+
3+
CREATE INDEX idx_event_batch_action_task_timestamp
4+
ON event ((event_data -> 'batchActionData' ->> 'taskId'), timestamp DESC)
5+
WHERE event_name IN ('invoke-batch-action', 'invoke-background-action');

0 commit comments

Comments
 (0)