Bugzilla – Attachment 193901 Details for
Bug 10190
Overdue notice triggers based on item type
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 10190: remove has_rules sentinel from circulation_rules table
84631c7.patch (text/plain), 12.77 KB, created by
Martin Renvoize (ashimema)
on 2026-02-25 15:33:20 UTC
(
hide
)
Description:
Bug 10190: remove has_rules sentinel from circulation_rules table
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2026-02-25 15:33:20 UTC
Size:
12.77 KB
patch
obsolete
>From 84631c74c802afb33abf572be119c5ee111ab1c4 Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@openfifth.co.uk> >Date: Wed, 25 Feb 2026 13:46:40 +0000 >Subject: [PATCH] Bug 10190: remove has_rules sentinel from circulation_rules > table > >has_rules was a purely frontend marker stored as a circulation rule to >signal that a context had explicitly-saved overdue trigger rules. The >backend never reads it; the information is fully derivable from whether >any of delay/notice/mtt/restrict are non-null for a given context. > >Replace all has_rules DB reads/writes with a hasExplicitRulesForTrigger() >helper that checks the four real rule suffixes directly. has_rules remains >as a computed in-memory concept in the Vue store (derived in findEffectiveRule) >so templates require no changes. > >Also adds an atomicupdate to delete existing has_rules rows from the DB, >and removes the has_rules insert from the bug_10190 migration script. >--- > Koha/CirculationRules.pm | 4 -- > .../data/mysql/atomicupdate/bug_10190.pl | 4 -- > .../CirculationTriggersFormAdd.vue | 2 - > ...lationTriggersFormConfirmTriggerDelete.vue | 14 +++- > .../prog/js/vue/stores/circulation-rules.js | 67 ++++++++++++------- > 5 files changed, 52 insertions(+), 39 deletions(-) > >diff --git a/Koha/CirculationRules.pm b/Koha/CirculationRules.pm >index ef67e367f37..8e6b4df3ef5 100644 >--- a/Koha/CirculationRules.pm >+++ b/Koha/CirculationRules.pm >@@ -194,10 +194,6 @@ our $RULE_KINDS = { > scope => [ 'branchcode', 'categorycode', 'itemtype' ], > can_be_blank => 0, > }, >- overdue_X_has_rules => { >- scope => [ 'branchcode', 'categorycode', 'itemtype' ], >- can_be_blank => 0, >- }, > renewalperiod => { > scope => [ 'branchcode', 'categorycode', 'itemtype' ], > }, >diff --git a/installer/data/mysql/atomicupdate/bug_10190.pl b/installer/data/mysql/atomicupdate/bug_10190.pl >index 39e0cf5d8c8..aabdb48a38d 100755 >--- a/installer/data/mysql/atomicupdate/bug_10190.pl >+++ b/installer/data/mysql/atomicupdate/bug_10190.pl >@@ -113,10 +113,6 @@ return { > $insert->execute( $branchcode, $categorycode, $itemtype, "overdue_${i}_restrict", $restrict ); > } > >- # has_rules is a UI sentinel that marks an explicit ruleset for this context/trigger. >- # It is not used by the backend (overdue_notices.pl). >- $insert->execute( $branchcode, $categorycode, $itemtype, "overdue_${i}_has_rules", 1 ); >- > $migrated++; > } > } >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue >index 7cb9efb70df..44c8894e896 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue >@@ -599,8 +599,6 @@ export default { > ); > } > >- ruleSetToSubmit[`overdue_${this.triggerNumber}_has_rules`] = true; >- > // in edit mode, check for changes from elsewhere to the rule set being edited > if (this.editMode === "edit") { > const ruleSetInDb = await this.getSelectedRuleSet(this.context); >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormConfirmTriggerDelete.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormConfirmTriggerDelete.vue >index ccc989f754a..38aa1b8f507 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormConfirmTriggerDelete.vue >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormConfirmTriggerDelete.vue >@@ -49,8 +49,12 @@ import { storeToRefs } from "pinia"; > export default { > setup() { > const circRulesStore = inject("circRulesStore"); >- const { handleContext, findEffectiveRule, deleteRuleSet } = >- circRulesStore; >+ const { >+ handleContext, >+ findEffectiveRule, >+ deleteRuleSet, >+ hasExplicitRulesForTrigger, >+ } = circRulesStore; > const { libraries, allCurrentLibraryRawRuleSets, ruleSuffixes } = > storeToRefs(circRulesStore); > return { >@@ -60,6 +64,7 @@ export default { > allCurrentLibraryRawRuleSets, > ruleSuffixes, > deleteRuleSet, >+ hasExplicitRulesForTrigger, > }; > }, > data() { >@@ -108,7 +113,10 @@ export default { > }; > > if ( >- ruleSet[`overdue_${this.triggerNumber}_has_rules`] === null >+ !this.hasExplicitRulesForTrigger( >+ ruleSet, >+ this.triggerNumber >+ ) > ) { > return; > } >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/circulation-rules.js b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/circulation-rules.js >index 5129a704107..27ad9875cde 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/circulation-rules.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/circulation-rules.js >@@ -32,7 +32,6 @@ export const useCircRulesStore = defineStore("circRules", () => { > { code: "sms", name: "SMS" }, > { code: "print", name: "Print" }, > ], >- regex: /overdue_(\d+)_has_rules/, > // rule sets > allDefaultLibraryRawRuleSets: [], // source of truth for default library > allCurrentLibraryRawRuleSets: [], // source of truth for current library >@@ -97,10 +96,15 @@ export const useCircRulesStore = defineStore("circRules", () => { > } > return value.includes(type) ? $__("Yes") : $__("No"); > }, >+ hasExplicitRulesForTrigger(ruleSet, triggerNumber) { >+ return ["delay", "notice", "mtt", "restrict"].some( >+ suffix => ruleSet[`overdue_${triggerNumber}_${suffix}`] != null >+ ); >+ }, > hasConflict(oldRuleSet, newRuleSet, triggerNumber) { > if ( > !oldRuleSet || >- oldRuleSet[`overdue_${triggerNumber}_has_rules`] === null >+ !this.hasExplicitRulesForTrigger(oldRuleSet, triggerNumber) > ) { > return false; > } >@@ -125,8 +129,8 @@ export const useCircRulesStore = defineStore("circRules", () => { > }, > isOnlyRuleSetForTrigger(triggerNumber) { > return ( >- this.allCurrentLibraryRawRuleSets.filter( >- ruleSet => ruleSet[`overdue_${triggerNumber}_has_rules`] >+ this.allCurrentLibraryRawRuleSets.filter(ruleSet => >+ this.hasExplicitRulesForTrigger(ruleSet, triggerNumber) > ).length === 1 > ); > }, >@@ -163,12 +167,20 @@ export const useCircRulesStore = defineStore("circRules", () => { > ruleSet?.context.item_type_id === context.item_type_id > ); > >- // if handling 'has_rules', stop here >+ // if handling 'has_rules', derive from actual rules rather than DB > if (ruleSuffix === "has_rules") { >+ const hasExplicit = this.currentAndDefaultRawRuleSets.some( >+ ruleSet => >+ ruleSet?.context.library_id === context.library_id && >+ ruleSet?.context.patron_category_id === >+ context.patron_category_id && >+ ruleSet?.context.item_type_id === >+ context.item_type_id && >+ this.hasExplicitRulesForTrigger(ruleSet, triggerNumber) >+ ); > return { >- value: existingRule?.[`overdue_${triggerNumber}_has_rules`], >- isFallback: >- !existingRule?.[`overdue_${triggerNumber}_has_rules`], >+ value: hasExplicit ? true : null, >+ isFallback: !hasExplicit, > }; > } > >@@ -178,8 +190,10 @@ export const useCircRulesStore = defineStore("circRules", () => { > value: existingRule[ > `overdue_${triggerNumber}_${ruleSuffix}` > ], >- isFallback: >- !existingRule[`overdue_${triggerNumber}_has_rules`], >+ isFallback: !this.hasExplicitRulesForTrigger( >+ existingRule, >+ triggerNumber >+ ), > }; > } > >@@ -289,7 +303,7 @@ export const useCircRulesStore = defineStore("circRules", () => { > i <= this.triggerCounts[this.currentLibraryId]; > i++ > ) { >- if (ruleSet[`overdue_${i}_has_rules`] === null) { >+ if (!this.hasExplicitRulesForTrigger(ruleSet, i)) { > continue; > } > this.ruleSuffixes.forEach(ruleSuffix => { >@@ -326,18 +340,23 @@ export const useCircRulesStore = defineStore("circRules", () => { > // - Rule sets exists that override default triggers. Therefore, their triggerCount is the same as default's. > // - Rule sets exists for triggers for which there is no default. > // => such triggers are follow up addition to the existing default sequence. >- // => the triggerCount for this library will be higher than default's, and equal to the highest trigger number for this library for which has_rules is not null. >+ // => the triggerCount for this library will be higher than default's, and equal to the highest trigger number for this library that has any explicit rules. > >- const ruleNames = Object.keys(this.allDefaultLibraryRawRuleSets[0]); > // Set the triggerCount for the default library rule set > if (this.currentLibraryId === "*") { >- this.triggerCounts["*"] = ruleNames.filter( >- ruleSuffix => >- this.regex.test(ruleSuffix) && >- this.allDefaultLibraryRawRuleSets.some( >- ruleSet => ruleSet[ruleSuffix] !== null >- ) >- ).length; >+ const triggerNumRegex = >+ /^overdue_(\d+)_(delay|notice|mtt|restrict)$/; >+ const triggerNums = new Set(); >+ this.allDefaultLibraryRawRuleSets.forEach(ruleSet => { >+ Object.keys(ruleSet).forEach(key => { >+ const match = key.match(triggerNumRegex); >+ if (match && ruleSet[key] !== null) { >+ triggerNums.add(parseInt(match[1])); >+ } >+ }); >+ }); >+ this.triggerCounts["*"] = >+ triggerNums.size > 0 ? Math.max(...triggerNums) : 0; > return; > } > >@@ -351,9 +370,8 @@ export const useCircRulesStore = defineStore("circRules", () => { > // Set a library-specific trigger count: at least one rule set exists -> start from the first trigger for which there is no default rule set > let i = this.triggerCounts["*"] + 1; > while ( >- ruleNames.includes(`overdue_${i}_has_rules`) && >- this.allCurrentLibraryRawRuleSets.some( >- ruleSet => ruleSet[`overdue_${i}_has_rules`] !== null >+ this.allCurrentLibraryRawRuleSets.some(ruleSet => >+ this.hasExplicitRulesForTrigger(ruleSet, i) > ) > ) { > i++; >@@ -391,7 +409,6 @@ export const useCircRulesStore = defineStore("circRules", () => { > if (ruleSet[`overdue_${triggerNumber}_mtt`] !== null) { > rulesForDeletion[`overdue_${triggerNumber}_mtt`] = null; > } >- rulesForDeletion[`overdue_${triggerNumber}_has_rules`] = null; > this.updateCircRuleSets(rulesForDeletion, triggerNumber); > }, > async getAllRawRuleSets() { >@@ -473,8 +490,6 @@ export const useCircRulesStore = defineStore("circRules", () => { > existingRuleSet[`overdue_${triggerNumber}_restrict`]; > circRuleSet[`overdue_${triggerNumber}_mtt`] = > existingRuleSet[`overdue_${triggerNumber}_mtt`]; >- circRuleSet[`overdue_${triggerNumber}_has_rules`] = >- existingRuleSet[`overdue_${triggerNumber}_has_rules`]; > const client = APIClient.circRule; > await client.circ_rules.update(circRuleSet); > }, >-- >2.53.0 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 10190
:
170357
|
170358
|
170359
|
170360
|
170361
|
170362
|
170363
|
170364
|
170365
|
170366
|
170367
|
170368
|
170369
|
170370
|
170371
|
170372
|
170373
|
170374
|
170375
|
170376
|
170380
|
170449
|
171727
|
171728
|
171729
|
171730
|
171731
|
171732
|
171733
|
171734
|
171735
|
171736
|
171737
|
171738
|
171739
|
171740
|
171741
|
171742
|
171743
|
171744
|
171745
|
171746
|
171747
|
171748
|
171749
|
171750
|
171751
|
171752
|
171753
|
171754
|
171755
|
172588
|
172589
|
172590
|
172591
|
172592
|
172593
|
172594
|
172595
|
172596
|
172597
|
172598
|
172599
|
172600
|
172601
|
172602
|
172603
|
172604
|
172605
|
172606
|
172607
|
172608
|
172609
|
172612
|
172614
|
172617
|
172619
|
172621
|
172622
|
172623
|
172624
|
172625
|
172626
|
172630
|
172631
|
172632
|
172633
|
172634
|
172635
|
172636
|
172637
|
172638
|
172639
|
172640
|
172641
|
172642
|
172643
|
172644
|
172645
|
172646
|
172647
|
172648
|
172649
|
172650
|
172651
|
172652
|
172653
|
172654
|
172655
|
172656
|
172657
|
172658
|
172659
|
172660
|
172661
|
172662
|
172663
|
178643
|
178644
|
178645
|
178646
|
178647
|
178648
|
178649
|
178650
|
178651
|
178652
|
178653
|
178654
|
178655
|
178656
|
178657
|
178658
|
178659
|
178660
|
178661
|
178662
|
178663
|
178664
|
178665
|
178666
|
178667
|
178668
|
178669
|
178670
|
178671
|
178672
|
178673
|
178674
|
178675
|
188075
|
188076
|
188077
|
188078
|
188079
|
188080
|
188081
|
188082
|
188083
|
188084
|
188085
|
188086
|
188087
|
188088
|
188476
|
189345
|
189863
|
189864
|
189865
|
189866
|
189867
|
189868
|
191749
|
191750
|
191751
|
191752
|
191753
|
191754
|
191755
|
191756
|
191757
|
191758
|
191759
|
191760
|
191761
|
191762
|
191763
|
191795
|
191796
|
191805
|
191854
|
191873
|
192871
|
192872
|
192873
|
192874
|
192875
|
192876
|
192877
|
192878
|
192879
|
192880
|
192881
|
192882
|
192883
|
192884
|
192885
|
192886
|
192887
|
192888
|
192889
|
192890
|
192891
|
192892
|
192893
|
192894
|
192895
|
192896
|
192897
|
192898
|
192899
|
193864
|
193866
|
193867
|
193868
|
193869
|
193870
|
193871
|
193872
|
193873
|
193874
|
193875
|
193876
|
193877
|
193878
|
193879
|
193880
|
193881
|
193882
|
193883
|
193884
|
193885
|
193886
|
193887
|
193888
|
193889
|
193890
|
193891
|
193892
|
193893
|
193894
|
193895
|
193896
|
193897
|
193898
|
193899
|
193900
|
193901
|
193902
|
193903
|
193904
|
193905
|
193979
|
194045
|
194046
|
194047
|
194048
|
194049
|
194050
|
194051
|
194052
|
194053
|
194054
|
194055
|
194056
|
194057
|
194058
|
194059
|
194060
|
194061
|
194062
|
194063
|
194064
|
194065
|
194066
|
194067
|
194068
|
194069
|
194070
|
194071
|
194072
|
194073
|
194074
|
194075
|
194076
|
194077
|
194078
|
194079
|
194080
|
194081
|
194082
|
194083
|
194084
|
194085
|
194086
|
194087
|
194088
|
194090
|
194094