2
0
mirror of https://github.com/frappe/books.git synced 2024-12-23 03:19:01 +00:00

Merge pull request #988 from AbleKSaju/feat-multi-label-link

feat: MultiLabelLink functionality in POS
This commit is contained in:
Akshay 2024-10-29 11:59:16 +05:30 committed by GitHub
commit 5f99a0df5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 203 additions and 1 deletions

View File

@ -0,0 +1,199 @@
<script>
import { t } from 'fyo';
import Badge from 'src/components/Badge.vue';
import { fyo } from 'src/initFyo';
import { fuzzyMatch } from 'src/utils';
import { getCreateFiltersFromListViewFilters } from 'src/utils/misc';
import { markRaw } from 'vue';
import AutoComplete from './AutoComplete.vue';
export default {
name: 'MultiLabelLink',
extends: AutoComplete,
data() {
return { results: [] };
},
watch: {
value: {
immediate: true,
handler(newValue) {
this.setLinkValue(newValue);
},
},
},
props: {
secondaryLink: String,
},
mounted() {
if (this.value) {
this.setLinkValue();
}
},
methods: {
async setLinkValue(newValue, isInput) {
if (isInput) {
return (this.linkValue = newValue || '');
}
const value = newValue ?? this.value;
const { fieldname, target } = this.df ?? {};
const linkDisplayField = fyo.schemaMap[target ?? '']?.linkDisplayField;
if (!linkDisplayField) {
return (this.linkValue = value);
}
const linkDoc = await this.doc?.loadAndGetLink(fieldname);
this.linkValue = linkDoc?.get(linkDisplayField) ?? '';
},
getTargetSchemaName() {
return this.df.target;
},
async getOptions() {
const schemaName = this.getTargetSchemaName();
if (!schemaName) {
return [];
}
if (this.results?.length) {
return this.results;
}
const schema = fyo.schemaMap[schemaName];
const filters = await this.getFilters();
const fields = [
...new Set([
'name',
this.secondaryLink,
schema.titleField,
this.df.groupBy,
]),
].filter(Boolean);
const results = await fyo.db.getAll(schemaName, {
filters,
fields,
});
return (this.results = results
.map((r) => {
const option = {
label: r[this.secondaryLink]
? `${r[schema.titleField]} ` + ` ${r[this.secondaryLink]}`
: r[schema.titleField],
value: r.name,
value2: r[this.secondaryLink],
};
if (this.df.groupBy) {
option.group = r[this.df.groupBy];
}
return option;
})
.filter(Boolean));
},
async getSuggestions(keyword = '') {
let options = await this.getOptions();
if (keyword) {
options = options
.map((item) => ({ ...fuzzyMatch(keyword, item.label), item }))
.filter(({ isMatch }) => isMatch)
.sort((a, b) => a.distance - b.distance)
.map(({ item }) => item);
}
if (this.doc && this.df.create) {
options = options.concat(this.getCreateNewOption());
}
if (options.length === 0 && !this.df.emptyMessage) {
return [
{
component: markRaw({
template:
'<span class="text-gray-600 dark:text-gray-400">{{ t`No results found` }}</span>',
}),
action: () => {},
actionOnly: true,
},
];
}
return options;
},
getCreateNewOption() {
return {
label: t`Create`,
action: () => this.openNewDoc(),
actionOnly: true,
component: markRaw({
template:
'<div class="flex items-center font-semibold">{{ t`Create` }}' +
'<Badge color="blue" class="ms-2" v-if="isNewValue">{{ linkValue }}</Badge>' +
'</div>',
computed: {
value: () => this.value,
linkValue: () => this.linkValue,
isNewValue: () => {
const values = this.suggestions.map((d) => d.label);
return this.linkValue && !values.includes(this.linkValue);
},
},
components: { Badge },
}),
};
},
async openNewDoc() {
const schemaName = this.df.target;
const name =
this.linkValue || fyo.doc.getTemporaryName(fyo.schemaMap[schemaName]);
const filters = await this.getCreateFilters();
const { openQuickEdit } = await import('src/utils/ui');
const doc = fyo.doc.getNewDoc(schemaName, { name, ...filters });
openQuickEdit({ doc });
doc.once('afterSync', () => {
this.$router.back();
this.results = [];
this.triggerChange(doc.name);
});
},
async getCreateFilters() {
const { schemaName, fieldname } = this.df;
const getCreateFilters =
fyo.models[schemaName]?.createFilters?.[fieldname];
let createFilters = await getCreateFilters?.(this.doc);
if (createFilters !== undefined) {
return createFilters;
}
const filters = await this.getFilters();
return getCreateFiltersFromListViewFilters(filters);
},
async getFilters() {
const { schemaName, fieldname } = this.df;
const getFilters = fyo.models[schemaName]?.filters?.[fieldname];
if (getFilters === undefined) {
return {};
}
if (this.doc) {
return (await getFilters(this.doc)) ?? {};
}
try {
return (await getFilters()) ?? {};
} catch {
return {};
}
},
},
};
</script>

View File

@ -382,9 +382,10 @@
" "
> >
<!-- Customer Search --> <!-- Customer Search -->
<Link <MultiLabelLink
v-if="sinvDoc.fieldMap" v-if="sinvDoc.fieldMap"
class="flex-shrink-0" class="flex-shrink-0"
secondary-link="phone"
:border="true" :border="true"
:value="sinvDoc.party" :value="sinvDoc.party"
:df="sinvDoc.fieldMap.party" :df="sinvDoc.fieldMap.party"
@ -567,6 +568,7 @@ import AlertModal from './AlertModal.vue';
import SavedInvoiceModal from './SavedInvoiceModal.vue'; import SavedInvoiceModal from './SavedInvoiceModal.vue';
import CouponCodeModal from './CouponCodeModal.vue'; import CouponCodeModal from './CouponCodeModal.vue';
import { AppliedCouponCodes } from 'models/baseModels/AppliedCouponCodes/AppliedCouponCodes'; import { AppliedCouponCodes } from 'models/baseModels/AppliedCouponCodes/AppliedCouponCodes';
import MultiLabelLink from 'src/components/Controls/MultiLabelLink.vue';
export default defineComponent({ export default defineComponent({
name: 'POS', name: 'POS',
@ -578,6 +580,7 @@ export default defineComponent({
ItemsTable, ItemsTable,
ItemsGrid, ItemsGrid,
Link, Link,
MultiLabelLink,
AlertModal, AlertModal,
OpenPOSShiftModal, OpenPOSShiftModal,
PageHeader, PageHeader,