diff --git a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/InvoicingBillingPeriodStatistics.vue b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/InvoicingBillingPeriodStatistics.vue index 25ed5f2e..f3646eb7 100644 --- a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/InvoicingBillingPeriodStatistics.vue +++ b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/InvoicingBillingPeriodStatistics.vue @@ -8,6 +8,8 @@ import {view} from "../../imports/InvoicingBillingPeriodImportView.vue"; import {departments} from "@/components/pagination/departmentTabs.vue"; import {SessionUser} from "@/components/session/token/SessionUser.vue"; import {BTooltip} from "buefy"; +import { exportRowsToExcel } from '@/services/TableExcelExportService.js'; +import { extractVisibleRowsFromTable } from '@/services/AutoTableExportService.js'; import { getDepartmentRelativeBookedAmount as calculateDepartmentRelativeBookedAmount, getBookedDepartment75SourceBookedTotal, @@ -380,6 +382,24 @@ const hasDepartment75CombinedBasis = computed(() => { || vehicleSubscriptionDistribution.value?.total_subscription_price !== undefined; }); +const isDepartment75CombinedFullyLoaded = computed(() => { + return fixed_pricing_department_distribution.value?.total_fixed_price !== undefined + && vehicleSubscriptionDistribution.value?.total_subscription_price !== undefined; +}); + +const department75Table = ref(null); + +const downloadExcel = () => { + if (!department75Table.value) return; + + // @ts-ignore + const rows = extractVisibleRowsFromTable(department75Table.value); + exportRowsToExcel(rows, { + filename: `invoicing-period-department-75-${dates.computed.formattedStartDate.value}-${dates.computed.formattedEndDate.value}.xlsx`, + sheetName: 'Department 75 Distribution' + }); +}; + const formatCurrencyAmount = (amount: any) => { return SessionUser.functions.currency.toLocal(toFiniteNumber(amount)); }; @@ -509,12 +529,14 @@ const formatCurrencyAmountOrDash = (amount: any) => {
@@ -576,6 +598,57 @@ const formatCurrencyAmountOrDash = (amount: any) => {
+ +
+ + + +
diff --git a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/Right.vue b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/Right.vue index 7eeb6a2d..27d4fdd9 100644 --- a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/Right.vue +++ b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/Right.vue @@ -386,6 +386,7 @@ const getPeriodRequestParameters = () => ({ page: periodPaging.page, limit: periodPaging.limit, search: periodPaging.search.trim(), + flagTab: periodPaging.flagTab, includeRequiresAction: periodPaging.includeRequiresAction ? 1 : 0, includeBooked: periodPaging.includeBooked ? 1 : 0, }); @@ -1003,6 +1004,7 @@ watch( periodPaging.page, periodPaging.limit, periodPaging.search, + periodPaging.flagTab, periodPaging.includeRequiresAction, periodPaging.includeBooked, ], diff --git a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/imports/InvoicingBillingPeriodImportPaging.js b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/imports/InvoicingBillingPeriodImportPaging.js index e329f500..21b0b78c 100644 --- a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/imports/InvoicingBillingPeriodImportPaging.js +++ b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/imports/InvoicingBillingPeriodImportPaging.js @@ -24,6 +24,7 @@ export const periodPaging = reactive({ page: 1, limit: DEFAULT_LIMIT, search: "", + flagTab: "all", includeRequiresAction: true, includeBooked: true, meta: defaultMeta(), @@ -82,6 +83,7 @@ export const resetPeriodPagingState = ({ clearCache = true } = {}) => { periodPaging.page = 1; periodPaging.limit = DEFAULT_LIMIT; periodPaging.search = ""; + periodPaging.flagTab = "all"; periodPaging.includeRequiresAction = true; periodPaging.includeBooked = true; periodPaging.meta = defaultMeta(); @@ -125,6 +127,7 @@ export const buildPeriodCacheKey = ({ page, limit, search, + flagTab, includeRequiresAction, includeBooked, }) => @@ -135,6 +138,7 @@ export const buildPeriodCacheKey = ({ normalizePage(page), normalizeLimit(limit), String(search || "").trim(), + String(flagTab || "all").trim(), includeRequiresAction ? "1" : "0", includeBooked ? "1" : "0", ] diff --git a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/views/InvoicingBillingPeriodViewAll.vue b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/views/InvoicingBillingPeriodViewAll.vue index 72441f1c..f11ad2c0 100644 --- a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/views/InvoicingBillingPeriodViewAll.vue +++ b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/views/InvoicingBillingPeriodViewAll.vue @@ -156,6 +156,80 @@ const customersInCurrentView = computed( () => view.variables.sharedVariables.value?.types?.[view.computed.componentName.value] ?? [] ); +type PeriodFlagTab = "all" | "red" | "yellow" | "none" | "filters"; +type CustomerFlagTab = "red" | "yellow" | "none"; + +const selectedFlagTab = computed({ + get: () => (periodPaging.flagTab as PeriodFlagTab) || "all", + set: (value) => { + if (periodPaging.flagTab !== value) { + periodPaging.flagTab = value; + periodPaging.page = 1; + } + }, +}); + +const getCustomerFlagTabType = (customer: any): CustomerFlagTab => { + const flagCounts = getCustomerActiveFlagCounts(customer); + if (flagCounts.manual > 0) { + return "red"; + } + + if (flagCounts.automatic > 0) { + return "yellow"; + } + + return "none"; +}; + +const toNonNegativeInteger = (value: any) => { + const parsed = Number.parseInt(String(value ?? "0"), 10); + return Number.isInteger(parsed) && parsed > 0 ? parsed : 0; +}; + +const periodFlagTabCounts = computed(() => { + const currentTypeName = view.computed.componentName.value; + const backendCounts = periodPaging.typeCounts?.[currentTypeName]; + if (backendCounts && typeof backendCounts === "object") { + const all = toNonNegativeInteger(backendCounts.total); + const red = Math.min(all, toNonNegativeInteger(backendCounts.manual_flags)); + const yellow = Math.min(Math.max(0, all - red), toNonNegativeInteger(backendCounts.automatic_flags)); + return { + all, + red, + yellow, + none: Math.max(0, all - red - yellow), + }; + } + + const counts = { all: 0, red: 0, yellow: 0, none: 0 }; + customersInCurrentView.value.forEach((customer: any) => { + counts.all += 1; + counts[getCustomerFlagTabType(customer)] += 1; + }); + return counts; +}); + +const filteredCustomersInCurrentView = computed(() => { + return customersInCurrentView.value; +}); + +const getPeriodFlagTabIconClass = (tab: PeriodFlagTab) => { + if (tab === "red") { + return "has-text-danger"; + } + + if (tab === "yellow") { + return "has-text-warning"; + } + + if (tab === "none") { + return "has-text-success"; + } + + return "has-text-grey-dark"; +}; + const isPossibleDuplicatesView = computed(() => view.variables.currentView.value === "possible_duplicates"); const possibleDuplicateGroupsInCurrentView = computed(() => @@ -227,6 +301,16 @@ const getTransactionIds = (customer: any) => { .map((transaction: any) => transaction.id); }; +const getAllTransactionIds = (customer: any) => { + if (!customer.transactions || customer.transactions.length === 0) { + return []; + } + + return customer.transactions + .map((transaction: any) => transaction.id) + .filter((transactionId: any) => transactionId !== null && transactionId !== undefined); +}; + const getExcludedTransactionIds = (customer: any) => { if (!customer.transactions || customer.transactions.length === 0) { return []; @@ -513,7 +597,7 @@ const isFlagInCustomerCardScope = (customer: any, flag: any) => { return Number(flag?.customer_number || flag?.target_id || 0) === Number(customer?.customer_number || 0); } - const transactionIds = getTransactionIds(customer); + const transactionIds = getAllTransactionIds(customer); const transactionIdSet = toPositiveIntegerSet(transactionIds); if (["order", "order_field", "order_item", "order_item_field"].includes(targetType)) { @@ -672,12 +756,12 @@ const getTransactionQueryParameters = () => { show_fixed_pricing: true, }; }; +