Bug 41214: Only show cash register if UseCashRegisters sys pref is enabled

Test plan:
1) Add a new account:
http://localhost:8081/cgi-bin/koha/sip2/accounts/add
2) Notice the 'cash register' field does not show
3) Enable UseCashRegisters sys pref
4) Repeat 1 (or edit an existing account). Refresh the page.
5) Notice the 'cash register' field now shows

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
Signed-off-by: Matt Blenkinsop <matt.blenkinsop@openfifth.co.uk>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
Pedro Amorim 2025-11-07 10:24:44 +00:00 committed by Lucas Gass
parent 115629bab3
commit 4544e70b37
No known key found for this signature in database
GPG Key ID: 60B447398B0D36CA
5 changed files with 220 additions and 188 deletions

View File

@ -1,198 +1,202 @@
<template>
<label
v-if="attr.label"
:for="getElementId"
:class="{ required: attr.required }"
:style="{ ...attr.style }"
>{{ attr.label }}:</label
>
<template v-if="attr.type == 'number'">
<InputNumber
:id="getElementId"
v-model="resource[attr.name]"
:placeholder="attr.placeholder || attr.label"
:required="attr.required ? true : false"
:size="attr.size"
:maxlength="attr.maxlength"
:disabled="disabled"
@update:modelValue="checkForInputError()"
/>
</template>
<template v-else-if="attr.type == 'text'">
<InputText
:id="getElementId"
v-model="resource[attr.name]"
:placeholder="attr.placeholder || attr.label"
:required="attr.required ? true : false"
:disabled="disabled"
@update:modelValue="checkForInputError()"
/>
</template>
<template v-else-if="attr.type == 'textarea'">
<TextArea
:id="getElementId"
v-model="resource[attr.name]"
:rows="attr.textAreaRows"
:cols="attr.textAreaCols"
:placeholder="attr.placeholder || attr.label"
:required="attr.required ? true : false"
:disabled="disabled"
@update:modelValue="checkForInputError()"
/>
</template>
<template v-else-if="attr.type == 'checkbox'">
<InputCheckbox
:id="getElementId"
type="checkbox"
v-model="resource[attr.name]"
:changeMethod="attr.onChange && attr.onChange.bind(this, resource)"
:disabled="disabled"
/>
</template>
<template v-else-if="attr.type == 'radio'">
<template
v-for="(option, index) in attr.options"
:key="`radio-option-${index}`"
<template v-if="display">
<label
v-if="attr.label"
:for="getElementId"
:class="{ required: attr.required }"
:style="{ ...attr.style }"
>{{ attr.label }}:</label
>
<label
v-if="option.description"
:for="attr.name + '_' + option.value"
>{{ option.description }}:
<template v-if="attr.type == 'number'">
<InputNumber
:id="getElementId"
v-model="resource[attr.name]"
:placeholder="attr.placeholder || attr.label"
:required="attr.required ? true : false"
:size="attr.size"
:maxlength="attr.maxlength"
:disabled="disabled"
@update:modelValue="checkForInputError()"
/>
</template>
<template v-else-if="attr.type == 'text'">
<InputText
:id="getElementId"
v-model="resource[attr.name]"
:placeholder="attr.placeholder || attr.label"
:required="attr.required ? true : false"
:disabled="disabled"
@update:modelValue="checkForInputError()"
/>
</template>
<template v-else-if="attr.type == 'textarea'">
<TextArea
:id="getElementId"
v-model="resource[attr.name]"
:rows="attr.textAreaRows"
:cols="attr.textAreaCols"
:placeholder="attr.placeholder || attr.label"
:required="attr.required ? true : false"
:disabled="disabled"
@update:modelValue="checkForInputError()"
/>
</template>
<template v-else-if="attr.type == 'checkbox'">
<InputCheckbox
:id="getElementId"
type="checkbox"
v-model="resource[attr.name]"
:changeMethod="
attr.onChange && attr.onChange.bind(this, resource)
"
:disabled="disabled"
/>
</template>
<template v-else-if="attr.type == 'radio'">
<template
v-for="(option, index) in attr.options"
:key="`radio-option-${index}`"
>
<label
v-if="option.description"
:for="attr.name + '_' + option.value"
>{{ option.description }}:
<InputRadio
:name="attr.name"
:id="attr.name + '_' + option.value"
:value="option.value"
:checked="
(!Object.keys(resource).includes(attr.name) &&
attr.default == option.value) ||
(Object.keys(resource).includes(attr.name) &&
option.value == resource[attr.name])
"
v-model="resource[attr.name]"
@change="
attr.onChange && attr.onChange.bind(this, resource)
"
/>
</label>
</template>
</template>
<template v-else-if="attr.type == 'boolean'">
<label class="radio" :for="getElementId + '_yes'"
>{{ $__("Yes") }}:
<InputRadio
type="radio"
:name="attr.name"
:id="attr.name + '_' + option.value"
:value="option.value"
:checked="
(!Object.keys(resource).includes(attr.name) &&
attr.default == option.value) ||
(Object.keys(resource).includes(attr.name) &&
option.value == resource[attr.name])
"
:id="attr.name + '_yes'"
:value="true"
:checked="resource[attr.name] == true"
v-model="resource[attr.name]"
/>
</label>
<label class="radio" :for="getElementId + '_no'"
>{{ $__("No") }}:
<InputRadio
type="radio"
:name="attr.name"
:id="attr.name + '_no'"
:checked="resource[attr.name] == false"
:value="false"
v-model="resource[attr.name]"
@change="
attr.onChange && attr.onChange.bind(this, resource)
"
/>
</label>
</template>
</template>
<template v-else-if="attr.type == 'boolean'">
<label class="radio" :for="getElementId + '_yes'"
>{{ $__("Yes") }}:
<InputRadio
type="radio"
:name="attr.name"
:id="attr.name + '_yes'"
:value="true"
:checked="resource[attr.name] == true"
<template v-else-if="attr.type == 'select'">
<v-select
:id="getElementId"
v-model="resource[attr.name]"
/>
</label>
<label class="radio" :for="getElementId + '_no'"
>{{ $__("No") }}:
<InputRadio
type="radio"
:name="attr.name"
:id="attr.name + '_no'"
:checked="resource[attr.name] == false"
:value="false"
:label="attr.selectLabel"
:reduce="av => selectRequiredKey(av)"
:options="selectOptions"
:required="!resource[attr.name] && attr.required"
:disabled="disabled"
:multiple="attr.allowMultipleChoices"
@option:selected="attr.onSelected && attr.onSelected(resource)"
>
<template v-if="attr.required" #search="{ attributes, events }">
<input
:required="!resource[attr.name]"
class="vs__search"
v-bind="attributes"
v-on="events"
/>
</template>
</v-select>
</template>
<template v-else-if="attr.type == 'vendor'">
<component
:is="requiredComponent"
:id="getElementId"
v-bind="getComponentProps()"
v-on="getEventHandlers()"
v-model="resource[attr.name]"
/>
</label>
</template>
<template v-else-if="attr.type == 'select'">
<v-select
:id="getElementId"
v-model="resource[attr.name]"
:label="attr.selectLabel"
:reduce="av => selectRequiredKey(av)"
:options="selectOptions"
:required="!resource[attr.name] && attr.required"
:disabled="disabled"
:multiple="attr.allowMultipleChoices"
@option:selected="attr.onSelected && attr.onSelected(resource)"
></component>
</template>
<template v-else-if="attr.type == 'date'">
<component
:is="requiredComponent"
:id="getElementId"
v-bind="getComponentProps()"
v-on="getEventHandlers()"
v-model="resource[attr.name]"
></component>
</template>
<template v-else-if="attr.type == 'component' && attr.componentPath">
<component
v-if="isVModelRequired(attr.componentPath)"
:is="requiredComponent"
v-bind="getComponentProps()"
v-model="resource[attr.name]"
v-on="getEventHandlers()"
></component>
<component
v-else
:is="requiredComponent"
v-bind="getComponentProps()"
v-on="getEventHandlers()"
></component>
</template>
<template
v-else-if="attr.type == 'relationshipWidget' && attr.componentProps"
>
<template v-if="attr.required" #search="{ attributes, events }">
<input
:required="!resource[attr.name]"
class="vs__search"
v-bind="attributes"
v-on="events"
/>
</template>
</v-select>
<component
:is="requiredComponent"
:title="attr.group ? null : attr.label"
:apiClient="attr.apiClient"
:name="attr.name"
v-bind="getComponentProps()"
v-on="getEventHandlers()"
></component>
</template>
<template v-else-if="attr.type == 'relationshipSelect'">
<FormRelationshipSelect
v-bind="attr"
:resource="resource"
></FormRelationshipSelect>
</template>
<template v-else-if="attr.type == 'additional_fields'">
<AdditionalFieldsEntry
:resource="resource"
:additional_field_values="resource.extended_attributes"
:extended_attributes_resource_type="
attr.extended_attributes_resource_type
"
@additional-fields-changed="additionalFieldsChanged"
></AdditionalFieldsEntry>
</template>
<template v-else>
<span>{{
$__("Programming error: unknown type %s").format(attr.type)
}}</span>
</template>
<ToolTip v-if="attr.toolTip" :toolTip="attr.toolTip"></ToolTip>
<span v-if="attr.required" class="required">{{ $__("Required") }}</span>
<span style="margin-left: 5px" class="error" v-if="fieldInputError">
{{ attr.formErrorMessage }}
</span>
</template>
<template v-else-if="attr.type == 'vendor'">
<component
:is="requiredComponent"
:id="getElementId"
v-bind="getComponentProps()"
v-on="getEventHandlers()"
v-model="resource[attr.name]"
></component>
</template>
<template v-else-if="attr.type == 'date'">
<component
:is="requiredComponent"
:id="getElementId"
v-bind="getComponentProps()"
v-on="getEventHandlers()"
v-model="resource[attr.name]"
></component>
</template>
<template v-else-if="attr.type == 'component' && attr.componentPath">
<component
v-if="isVModelRequired(attr.componentPath)"
:is="requiredComponent"
v-bind="getComponentProps()"
v-model="resource[attr.name]"
v-on="getEventHandlers()"
></component>
<component
v-else
:is="requiredComponent"
v-bind="getComponentProps()"
v-on="getEventHandlers()"
></component>
</template>
<template
v-else-if="attr.type == 'relationshipWidget' && attr.componentProps"
>
<component
:is="requiredComponent"
:title="attr.group ? null : attr.label"
:apiClient="attr.apiClient"
:name="attr.name"
v-bind="getComponentProps()"
v-on="getEventHandlers()"
></component>
</template>
<template v-else-if="attr.type == 'relationshipSelect'">
<FormRelationshipSelect
v-bind="attr"
:resource="resource"
></FormRelationshipSelect>
</template>
<template v-else-if="attr.type == 'additional_fields'">
<AdditionalFieldsEntry
:resource="resource"
:additional_field_values="resource.extended_attributes"
:extended_attributes_resource_type="
attr.extended_attributes_resource_type
"
@additional-fields-changed="additionalFieldsChanged"
></AdditionalFieldsEntry>
</template>
<template v-else>
<span>{{
$__("Programming error: unknown type %s").format(attr.type)
}}</span>
</template>
<ToolTip v-if="attr.toolTip" :toolTip="attr.toolTip"></ToolTip>
<span v-if="attr.required" class="required">{{ $__("Required") }}</span>
<span style="margin-left: 5px" class="error" v-if="fieldInputError">
{{ attr.formErrorMessage }}
</span>
</template>
<script>
@ -273,7 +277,14 @@ export default {
return disabledAttr || false;
}
});
const display = computed(() => {
const displayAttr = props.display ?? props.attr.display ?? true;
if (typeof displayAttr === "function") {
return displayAttr(props.resource);
} else {
return displayAttr || false;
}
});
const fieldInputError = ref(false);
const checkForInputError = () => {
if (props.attr.formErrorHandler) {
@ -292,6 +303,7 @@ export default {
requiredComponent,
selectOptions,
disabled,
display,
fieldInputError,
checkForInputError,
};

View File

@ -26,13 +26,14 @@ import Breadcrumbs from "../Breadcrumbs.vue";
import { storeToRefs } from "pinia";
import Help from "../Help.vue";
import LeftMenu from "../LeftMenu.vue";
import { APIClient } from "../../fetch/api-client.js";
import Dialog from "../Dialog.vue";
import "vue-select/dist/vue-select.css";
export default {
setup() {
const SIP2Store = inject("SIP2Store");
const { authorisedValues } = storeToRefs(SIP2Store);
const { sysprefs, authorisedValues } = storeToRefs(SIP2Store);
const { loadAuthorisedValues } = SIP2Store;
const mainStore = inject("mainStore");
@ -43,9 +44,20 @@ export default {
onBeforeMount(() => {
loading();
loadAuthorisedValues(authorisedValues.value, SIP2Store).then(() => {
loaded();
initialized.value = true;
const fetchAuthorised = () => {
return loadAuthorisedValues(
authorisedValues.value,
SIP2Store
).then(() => {
loaded();
initialized.value = true;
});
};
const client = APIClient.sysprefs;
return client.sysprefs.get("UseCashRegisters").then(result => {
sysprefs.value.UseCashRegisters = result.value;
return fetchAuthorised();
});
});

View File

@ -20,6 +20,9 @@ export default {
},
emits: ["select-resource"],
setup(props) {
const SIP2Store = inject("SIP2Store");
const { sysprefs } = storeToRefs(SIP2Store);
const explodeValues = (value, delimiter) => {
if (!value) return null;
return Array.isArray(value) ? value : value.split(delimiter);
@ -420,6 +423,7 @@ export default {
relationshipOptionLabelAttr: "name", // attr of the related resource used for display
relationshipRequiredKey: "cash_register_id",
hideIn: ["List"],
display: account => sysprefs.value.UseCashRegisters == 1,
group: "Details",
toolTip: __(
"Only required if system preference UseCashRegisters is enabled"

View File

@ -1,6 +1,7 @@
import { computed, inject, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { build_url } from "../composables/datatables";
import { isRef } from "vue";
import { storeToRefs } from "pinia";
import {
$__,

View File

@ -4,6 +4,9 @@ import { withAuthorisedValueActions } from "../composables/authorisedValues";
export const useSIP2Store = defineStore("sip2", () => {
const store = reactive({
sysprefs: {
UseCashRegisters: 0,
},
authorisedValues: {
av_lost: "LOST",
},