mirror of
https://github.com/frappe/books.git
synced 2024-11-08 14:50:56 +00:00
fix(ux): common purpose entries displayed in specific lists
This commit is contained in:
parent
013bf3af4f
commit
808abd224f
@ -153,7 +153,10 @@ export class Party extends Doc {
|
||||
condition: (doc: Doc) =>
|
||||
!doc.notInserted && (doc.role as PartyRole) !== 'Customer',
|
||||
action: async (partyDoc, router) => {
|
||||
router.push(`/list/PurchaseInvoice/party/${partyDoc.name}`);
|
||||
await router.push({
|
||||
path: '/list/PurchaseInvoice',
|
||||
query: { filters: JSON.stringify({ party: partyDoc.name }) },
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -161,11 +164,12 @@ export class Party extends Doc {
|
||||
condition: (doc: Doc) =>
|
||||
!doc.notInserted && (doc.role as PartyRole) !== 'Supplier',
|
||||
action: async (partyDoc, router) => {
|
||||
const doc = await fyo.doc.getNewDoc('SalesInvoice', {
|
||||
const doc = fyo.doc.getNewDoc('SalesInvoice', {
|
||||
party: partyDoc.name,
|
||||
account: partyDoc.defaultAccount as string,
|
||||
});
|
||||
router.push({
|
||||
|
||||
await router.push({
|
||||
path: `/edit/SalesInvoice/${doc.name}`,
|
||||
query: {
|
||||
schemaName: 'SalesInvoice',
|
||||
@ -182,7 +186,10 @@ export class Party extends Doc {
|
||||
condition: (doc: Doc) =>
|
||||
!doc.notInserted && (doc.role as PartyRole) !== 'Supplier',
|
||||
action: async (partyDoc, router) => {
|
||||
router.push(`/list/SalesInvoice/party/${partyDoc.name}`);
|
||||
router.push({
|
||||
path: '/list/SalesInvoice',
|
||||
query: { filters: JSON.stringify({ party: partyDoc.name }) },
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
|
@ -147,7 +147,7 @@ export function getStatusText(status: DocStatus | InvoiceStatus): string {
|
||||
case 'Saved':
|
||||
return t`Saved`;
|
||||
case 'NotSaved':
|
||||
return t`NotSaved`;
|
||||
return t`Not Saved`;
|
||||
case 'Submitted':
|
||||
return t`Submitted`;
|
||||
case 'Cancelled':
|
||||
|
@ -3,6 +3,7 @@ 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';
|
||||
|
||||
@ -145,23 +146,8 @@ export default {
|
||||
return createFilters;
|
||||
}
|
||||
|
||||
createFilters = {};
|
||||
|
||||
const filters = await this.getFilters();
|
||||
for (const key of Object.keys(filters)) {
|
||||
const value = filters[key];
|
||||
if (value === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
createFilters[key] = value;
|
||||
}
|
||||
|
||||
return createFilters;
|
||||
return getCreateFiltersFromListViewFilters(filters);
|
||||
},
|
||||
async getFilters() {
|
||||
const { schemaName, fieldname } = this.df;
|
||||
|
@ -230,17 +230,26 @@ export default {
|
||||
}
|
||||
|
||||
if (group.route) {
|
||||
routeTo(group.route);
|
||||
routeTo(this.getPath(group));
|
||||
}
|
||||
},
|
||||
onItemClick(item) {
|
||||
if (item.action) {
|
||||
item.action();
|
||||
}
|
||||
|
||||
if (item.route) {
|
||||
routeTo(item.route);
|
||||
routeTo(this.getPath(item));
|
||||
}
|
||||
},
|
||||
getPath(item) {
|
||||
const { route: path, filters } = item;
|
||||
if (!filters) {
|
||||
return path;
|
||||
}
|
||||
|
||||
return { path, query: { filters: JSON.stringify(filters) } };
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -89,13 +89,15 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { clone } from 'lodash';
|
||||
import Button from 'src/components/Button';
|
||||
import Paginator from 'src/components/Paginator.vue';
|
||||
import Row from 'src/components/Row';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { isNumeric } from 'src/utils';
|
||||
import { openQuickEdit, routeTo } from 'src/utils/ui';
|
||||
import { defineComponent } from 'vue';
|
||||
import { objectForEach } from 'utils/index';
|
||||
import { defineComponent, toRaw } from 'vue';
|
||||
import ListCell from './ListCell';
|
||||
|
||||
export default defineComponent({
|
||||
@ -194,6 +196,8 @@ export default defineComponent({
|
||||
filters = { ...this.filters };
|
||||
}
|
||||
|
||||
filters = objectForEach(clone(filters), toRaw);
|
||||
|
||||
const orderBy = !!fyo.getField(this.schemaName, 'date')
|
||||
? 'date'
|
||||
: 'created';
|
||||
|
@ -44,7 +44,7 @@ import FilterDropdown from 'src/components/FilterDropdown.vue';
|
||||
import Modal from 'src/components/Modal.vue';
|
||||
import PageHeader from 'src/components/PageHeader.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { docsPathMap } from 'src/utils/misc';
|
||||
import { docsPathMap, getCreateFiltersFromListViewFilters } from 'src/utils/misc';
|
||||
import { docsPath, routeTo } from 'src/utils/ui';
|
||||
import List from './List.vue';
|
||||
|
||||
@ -77,6 +77,10 @@ export default {
|
||||
|
||||
this.listConfig = getListConfig(this.schemaName);
|
||||
docsPath.value = docsPathMap[this.schemaName] ?? docsPathMap.Entries;
|
||||
|
||||
if (this.fyo.store.isDevelopment) {
|
||||
window.lv = this;
|
||||
}
|
||||
},
|
||||
deactivated() {
|
||||
docsPath.value = '';
|
||||
@ -86,10 +90,11 @@ export default {
|
||||
this.listFilters = listFilters;
|
||||
},
|
||||
async makeNewDoc() {
|
||||
const doc = await fyo.doc.getNewDoc(this.schemaName, this.filters ?? {});
|
||||
const filters = getCreateFiltersFromListViewFilters(this.filters ?? {});
|
||||
const doc = fyo.doc.getNewDoc(this.schemaName, filters);
|
||||
const path = this.getFormPath(doc.name);
|
||||
|
||||
routeTo(path);
|
||||
await routeTo(path);
|
||||
doc.on('afterSync', () => {
|
||||
const path = this.getFormPath(doc.name);
|
||||
this.$router.replace(path);
|
||||
|
@ -80,7 +80,7 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/list/:schemaName/:fieldname?/:value?/:pageTitle?',
|
||||
path: '/list/:schemaName/:pageTitle?',
|
||||
name: 'ListView',
|
||||
components: {
|
||||
default: ListView,
|
||||
@ -88,18 +88,19 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
props: {
|
||||
default: (route) => {
|
||||
const { schemaName, fieldname, value, pageTitle } = route.params;
|
||||
let { filters } = route.params;
|
||||
const { schemaName } = route.params;
|
||||
const pageTitle = route.params.pageTitle ?? '';
|
||||
|
||||
if (filters === undefined && fieldname && value) {
|
||||
// @ts-ignore
|
||||
filters = { [fieldname as string]: value };
|
||||
const filters = {};
|
||||
const filterString = route.query.filters;
|
||||
if (typeof filterString === 'string') {
|
||||
Object.assign(filters, JSON.parse(filterString));
|
||||
}
|
||||
|
||||
return {
|
||||
schemaName,
|
||||
filters,
|
||||
pageTitle: pageTitle ?? '',
|
||||
pageTitle,
|
||||
};
|
||||
},
|
||||
edit: (route) => {
|
||||
|
@ -85,7 +85,13 @@ export function getGetStartedConfig() {
|
||||
label: t`Add Items`,
|
||||
icon: 'item',
|
||||
description: t`Add products or services that you sell to your customers`,
|
||||
action: () => routeTo(`/list/Item/for/Sales/${t`Sales Items`}`),
|
||||
action: () =>
|
||||
routeTo({
|
||||
path: `/list/Item/${t`Sales Items`}`,
|
||||
query: {
|
||||
filters: JSON.stringify({ for: 'Sales' }),
|
||||
},
|
||||
}),
|
||||
fieldname: 'salesItemCreated',
|
||||
documentation:
|
||||
'https://docs.frappebooks.com/setting-up/initial-entries.html#add-sales-items',
|
||||
@ -95,7 +101,13 @@ export function getGetStartedConfig() {
|
||||
label: t`Add Customers`,
|
||||
icon: 'customer',
|
||||
description: t`Add a few customers to create your first sales invoice`,
|
||||
action: () => routeTo(`/list/Party/role/Customer/${t`Customers`}`),
|
||||
action: () =>
|
||||
routeTo({
|
||||
path: `/list/Party/${t`Customers`}`,
|
||||
query: {
|
||||
filters: JSON.stringify({ role: 'Customer' }),
|
||||
},
|
||||
}),
|
||||
fieldname: 'customerCreated',
|
||||
documentation:
|
||||
'https://docs.frappebooks.com/setting-up/initial-entries.html#add-customers',
|
||||
@ -122,7 +134,12 @@ export function getGetStartedConfig() {
|
||||
icon: 'item',
|
||||
description: t`Add products or services that you buy from your suppliers`,
|
||||
action: () =>
|
||||
routeTo(`/list/Item/for/Purchases/${t`Purchase Items`}`),
|
||||
routeTo({
|
||||
path: `/list/Item/${t`Purchase Items`}`,
|
||||
query: {
|
||||
filters: JSON.stringify({ for: 'Purchases' }),
|
||||
},
|
||||
}),
|
||||
fieldname: 'purchaseItemCreated',
|
||||
},
|
||||
{
|
||||
@ -130,7 +147,11 @@ export function getGetStartedConfig() {
|
||||
label: t`Add Suppliers`,
|
||||
icon: 'supplier',
|
||||
description: t`Add a few suppliers to create your first purchase invoice`,
|
||||
action: () => routeTo(`/list/Party/role/Supplier/${t`Suppliers`}`),
|
||||
action: () =>
|
||||
routeTo({
|
||||
path: `/list/Party/${t`Suppliers`}`,
|
||||
query: { filters: JSON.stringify({ role: 'Supplier' }) },
|
||||
}),
|
||||
fieldname: 'supplierCreated',
|
||||
},
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ import { ModelNameEnum } from 'models/types';
|
||||
import SetupWizardSchema from 'schemas/app/SetupWizard.json';
|
||||
import { Schema } from 'schemas/types';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { QueryFilter } from 'utils/db/types';
|
||||
|
||||
export function getDatesAndPeriodList(
|
||||
period: 'This Year' | 'This Quarter' | 'This Month'
|
||||
@ -96,7 +97,7 @@ export const docsPathMap: Record<string, string | undefined> = {
|
||||
[ModelNameEnum.PurchaseInvoice]: 'transactions/purchase-invoices',
|
||||
[ModelNameEnum.Payment]: 'transactions/payments',
|
||||
[ModelNameEnum.JournalEntry]: 'transactions/journal-entries',
|
||||
|
||||
|
||||
// Inventory
|
||||
[ModelNameEnum.StockMovement]: 'inventory/stock-movement',
|
||||
[ModelNameEnum.Shipment]: 'inventory/shipment',
|
||||
@ -136,3 +137,23 @@ export async function convertFileToDataURL(file: File, type: string) {
|
||||
const array = new Uint8Array(buffer);
|
||||
return await getDataURL(type, array);
|
||||
}
|
||||
|
||||
export function getCreateFiltersFromListViewFilters(filters: QueryFilter) {
|
||||
const createFilters: Record<string, string | number | boolean | null> = {};
|
||||
|
||||
for (const key in filters) {
|
||||
let value: typeof filters[string] | undefined | number = filters[key];
|
||||
|
||||
if (Array.isArray(value) && value[0] === 'in' && Array.isArray(value[1])) {
|
||||
value = value[1].filter((v) => v !== 'Both')[0];
|
||||
}
|
||||
|
||||
if (value === undefined || Array.isArray(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
createFilters[key] = value;
|
||||
}
|
||||
|
||||
return createFilters;
|
||||
}
|
||||
|
@ -153,9 +153,11 @@ function getCreateList(fyo: Fyo): SearchItem[] {
|
||||
},
|
||||
].map(({ label, filter, schemaName }) => {
|
||||
const fk = Object.keys(filter)[0] as 'for' | 'role';
|
||||
const ep = `${fk}/${filter[fk]}`;
|
||||
const route = {
|
||||
path: `/list/${schemaName}/${label}`,
|
||||
query: { filters: JSON.stringify({ [fk]: filter[fk] }) },
|
||||
};
|
||||
|
||||
const route = `/list/${schemaName}/${ep}/${label}`;
|
||||
return {
|
||||
label,
|
||||
group: 'Create',
|
||||
@ -235,29 +237,47 @@ function getListViewList(fyo: Fyo): SearchItem[] {
|
||||
);
|
||||
|
||||
const filteredLists = [
|
||||
{ label: t`Customers`, route: `/list/Party/role/Customer/${t`Customers`}` },
|
||||
{ label: t`Suppliers`, route: `/list/Party/role/Supplier/${t`Suppliers`}` },
|
||||
{
|
||||
label: t`Customers`,
|
||||
route: `/list/Party/${t`Customers`}`,
|
||||
filters: { role: ['Customer', 'Both'] },
|
||||
},
|
||||
{
|
||||
label: t`Suppliers`,
|
||||
route: `/list/Party/${t`Suppliers`}`,
|
||||
filters: { role: ['Supplier', 'Both'] },
|
||||
},
|
||||
{
|
||||
label: t`Sales Items`,
|
||||
route: `/list/Item/for/Sales/${t`Sales Items`}`,
|
||||
route: `/list/Item/${t`Sales Items`}`,
|
||||
filters: { for: ['in', ['Sales', 'Both']] },
|
||||
},
|
||||
{
|
||||
label: t`Sales Payments`,
|
||||
route: `/list/Payment/paymentType/Receive/${t`Sales Payments`}`,
|
||||
route: `/list/Payment/${t`Sales Payments`}`,
|
||||
filters: { paymentType: 'Receive' },
|
||||
},
|
||||
{
|
||||
label: t`Purchase Items`,
|
||||
route: `/list/Item/for/Purchases/${t`Purchase Items`}`,
|
||||
route: `/list/Item/${t`Purchase Items`}`,
|
||||
filters: { for: ['in', ['Purchases', 'Both']] },
|
||||
},
|
||||
{
|
||||
label: t`Common Items`,
|
||||
route: `/list/Item/for/Both/${t`Common Items`}`,
|
||||
route: `/list/Item/${t`Common Items`}`,
|
||||
filters: { for: 'Both' },
|
||||
},
|
||||
{
|
||||
label: t`Purchase Payments`,
|
||||
route: `/list/Payment/paymentType/Pay/${t`Purchase Payments`}`,
|
||||
route: `/list/Payment/${t`Purchase Payments`}`,
|
||||
filters: { paymentType: 'Pay' },
|
||||
},
|
||||
].map((i) => ({ ...i, group: 'List' } as SearchItem));
|
||||
].map((i) => {
|
||||
const label = i.label;
|
||||
const route = encodeURI(`${i.route}?filters=${JSON.stringify(i.filters)}`);
|
||||
|
||||
return { label, route, group: 'List' } as SearchItem;
|
||||
});
|
||||
|
||||
return [standardLists, filteredLists].flat();
|
||||
}
|
||||
|
@ -163,20 +163,23 @@ async function getCompleteSidebar(): Promise<SidebarConfig> {
|
||||
{
|
||||
label: t`Sales Payments`,
|
||||
name: 'payments',
|
||||
route: `/list/Payment/paymentType/Receive/${t`Sales Payments`}`,
|
||||
route: `/list/Payment/${t`Sales Payments`}`,
|
||||
schemaName: 'Payment',
|
||||
filters: { paymentType: 'Receive' },
|
||||
},
|
||||
{
|
||||
label: t`Customers`,
|
||||
name: 'customers',
|
||||
route: `/list/Party/role/Customer/${t`Customers`}`,
|
||||
route: `/list/Party/${t`Customers`}`,
|
||||
schemaName: 'Party',
|
||||
filters: { role: ['in', ['Customer', 'Both']] },
|
||||
},
|
||||
{
|
||||
label: t`Sales Items`,
|
||||
name: 'sales-items',
|
||||
route: `/list/Item/for/Sales/${t`Sales Items`}`,
|
||||
route: `/list/Item/${t`Sales Items`}`,
|
||||
schemaName: 'Item',
|
||||
filters: { for: ['in', ['Sales', 'Both']] },
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -195,20 +198,23 @@ async function getCompleteSidebar(): Promise<SidebarConfig> {
|
||||
{
|
||||
label: t`Purchase Payments`,
|
||||
name: 'payments',
|
||||
route: `/list/Payment/paymentType/Pay/${t`Purchase Payments`}`,
|
||||
route: `/list/Payment/${t`Purchase Payments`}`,
|
||||
schemaName: 'Payment',
|
||||
filters: { paymentType: 'Pay' },
|
||||
},
|
||||
{
|
||||
label: t`Suppliers`,
|
||||
name: 'suppliers',
|
||||
route: `/list/Party/role/Supplier/${t`Suppliers`}`,
|
||||
route: `/list/Party/${t`Suppliers`}`,
|
||||
schemaName: 'Party',
|
||||
filters: { role: ['in', ['Supplier', 'Both']] },
|
||||
},
|
||||
{
|
||||
label: t`Purchase Items`,
|
||||
name: 'purchase-items',
|
||||
route: `/list/Item/for/Purchases/${t`Purchase Items`}`,
|
||||
route: `/list/Item/${t`Purchase Items`}`,
|
||||
schemaName: 'Item',
|
||||
filters: { for: ['in', ['Purchases', 'Both']] },
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -227,14 +233,16 @@ async function getCompleteSidebar(): Promise<SidebarConfig> {
|
||||
{
|
||||
label: t`Party`,
|
||||
name: 'party',
|
||||
route: '/list/Party/role/Both',
|
||||
route: '/list/Party',
|
||||
schemaName: 'Party',
|
||||
filters: { role: 'Both' },
|
||||
},
|
||||
{
|
||||
label: t`Common Items`,
|
||||
name: 'common-items',
|
||||
route: `/list/Item/for/Both/${t`Common Items`}`,
|
||||
route: `/list/Item/${t`Common Items`}`,
|
||||
schemaName: 'Item',
|
||||
filters: { for: 'Both' },
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Doc } from "fyo/model/doc";
|
||||
import { FieldTypeEnum } from "schemas/types";
|
||||
import { QueryFilter } from "utils/db/types";
|
||||
|
||||
export interface MessageDialogButton {
|
||||
label: string;
|
||||
@ -42,6 +43,7 @@ export interface SidebarRoot {
|
||||
iconHeight?: string;
|
||||
hidden?: () => boolean;
|
||||
items?: SidebarItem[];
|
||||
filters?: QueryFilter
|
||||
}
|
||||
|
||||
export interface SidebarItem {
|
||||
|
@ -142,7 +142,6 @@ export function openSettings(tab: SettingsTab) {
|
||||
}
|
||||
|
||||
export async function routeTo(route: string | RouteLocationRaw) {
|
||||
const routeOptions = route;
|
||||
if (
|
||||
typeof route === 'string' &&
|
||||
route === router.currentRoute.value.fullPath
|
||||
@ -150,11 +149,7 @@ export async function routeTo(route: string | RouteLocationRaw) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof route === 'string') {
|
||||
return await router.push(route);
|
||||
}
|
||||
|
||||
return await router.push(routeOptions);
|
||||
return await router.push(route);
|
||||
}
|
||||
|
||||
export async function deleteDocWithPrompt(doc: Doc) {
|
||||
|
@ -225,3 +225,18 @@ export function removeAtIndex<T>(array: T[], index: number): T[] {
|
||||
|
||||
return [...array.slice(0, index), ...array.slice(index + 1)];
|
||||
}
|
||||
|
||||
export function objectForEach<T extends object | unknown>(
|
||||
obj: T,
|
||||
func: Function
|
||||
) {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return func(obj);
|
||||
}
|
||||
|
||||
for (const key in obj) {
|
||||
obj[key] = objectForEach(obj[key], func);
|
||||
}
|
||||
|
||||
return func(obj);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user