diff --git a/fyo/models/NumberSeries.ts b/fyo/models/NumberSeries.ts index 661b516b..3b9f485f 100644 --- a/fyo/models/NumberSeries.ts +++ b/fyo/models/NumberSeries.ts @@ -1,11 +1,29 @@ import { Doc } from 'fyo/model/doc'; -import { ReadOnlyMap } from 'fyo/model/types'; +import { ReadOnlyMap, ValidationMap } from 'fyo/model/types'; +import { ValidationError } from 'fyo/utils/errors'; + +const invalidNumberSeries = /[/\=\?\&\%]/; function getPaddedName(prefix: string, next: number, padZeros: number): string { return prefix + next.toString().padStart(padZeros ?? 4, '0'); } export default class NumberSeries extends Doc { + validations: ValidationMap = { + name: (value) => { + if (typeof value !== 'string') { + return; + } + + if (invalidNumberSeries.test(value)) { + throw new ValidationError( + this.fyo + .t`The following characters cannot be used ${'/, ?, &, =, %'} in a Number Series name.` + ); + } + }, + }; + setCurrent() { let current = this.get('current') as number | null; diff --git a/src/components/Controls/Barcode.vue b/src/components/Controls/Barcode.vue index 219f0141..3bb5af64 100644 --- a/src/components/Controls/Barcode.vue +++ b/src/components/Controls/Barcode.vue @@ -35,9 +35,11 @@ export default defineComponent({ return { timerId: null, barcode: '', + cooldown: '', } as { - timerId: null | ReturnType; + timerId: null | ReturnType; barcode: string; + cooldown: string; }; }, mounted() { @@ -64,6 +66,17 @@ export default defineComponent({ return this.error(this.t`Invalid barcode value ${barcode}.`); } + /** + * Between two entries of the same item, this adds + * a cooldown period of 100ms. This is to prevent + * double entry. + */ + if (this.cooldown === barcode) { + return; + } + this.cooldown = barcode; + setTimeout(() => (this.cooldown = ''), 100); + const items = (await this.fyo.db.getAll('Item', { filters: { barcode }, fields: ['name'], @@ -97,12 +110,10 @@ export default defineComponent({ return await this.setItemFromBarcode(); } - if (this.timerId !== null) { - clearInterval(this.timerId); - } + this.clearInterval(); this.barcode += key; - this.timerId = setInterval(async () => { + this.timerId = setTimeout(async () => { await this.setItemFromBarcode(); this.barcode = ''; }, 20); @@ -115,9 +126,15 @@ export default defineComponent({ await this.selectItem(this.barcode); this.barcode = ''; - if (this.timerId !== null) { - clearInterval(this.timerId); + this.clearInterval(); + }, + clearInterval() { + if (this.timerId === null) { + return; } + + clearInterval(this.timerId); + this.timerId = null; }, error(message: string) { showToast({ type: 'error', message }); diff --git a/src/components/Controls/Link.vue b/src/components/Controls/Link.vue index 03a0683f..f8e40c12 100644 --- a/src/components/Controls/Link.vue +++ b/src/components/Controls/Link.vue @@ -131,7 +131,8 @@ export default { }, async openNewDoc() { const schemaName = this.df.target; - const name = this.linkValue; + const name = + this.linkValue || fyo.doc.getTemporaryName(fyo.schemaMap[schemaName]); const filters = await this.getCreateFilters(); const { openQuickEdit } = await import('src/utils/ui');