Fix invoicing period invoice action
This commit is contained in:
+146
-58
@@ -42,7 +42,9 @@ const doesCustomerHaveTransactionsDifferentDays = (customer: any) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
const datesSet = new Set(customer.transactions.map((transaction: any) => new Date(transaction.date).toISOString().split("T")[0]));
|
||||
const datesSet = new Set(
|
||||
customer.transactions.map((transaction: any) => new Date(transaction.date).toISOString().split("T")[0])
|
||||
);
|
||||
return datesSet.size > 1;
|
||||
};
|
||||
|
||||
@@ -57,9 +59,9 @@ const onFilterChanged = (filters: any) => {
|
||||
tmpFilters.value = filters;
|
||||
};
|
||||
|
||||
const customersInCurrentView = computed(() => (
|
||||
view.variables.sharedVariables.value?.types?.[view.computed.componentName.value] ?? []
|
||||
));
|
||||
const customersInCurrentView = computed(
|
||||
() => view.variables.sharedVariables.value?.types?.[view.computed.componentName.value] ?? []
|
||||
);
|
||||
|
||||
const getTransactionIds = (customer: any) => {
|
||||
if (!customer.transactions || customer.transactions.length === 0) {
|
||||
@@ -83,23 +85,41 @@ const getExcludedTransactionIds = (customer: any) => {
|
||||
|
||||
const transactionIdsInvoiceCollectionCache = ref<{ [key: number]: number | null }>({});
|
||||
|
||||
const queueInvoiceCollections = (invoiceCollectionIds: number[]) => {
|
||||
const uniqueInvoiceCollectionIds = Array.from(
|
||||
new Set(
|
||||
invoiceCollectionIds.filter(
|
||||
(invoiceCollectionId) => Number.isInteger(invoiceCollectionId) && invoiceCollectionId > 0
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (uniqueInvoiceCollectionIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
invoiceQueue.addInvoiceCollectionsToQueue(uniqueInvoiceCollectionIds);
|
||||
invoiceQueue.processInvoiceCollectionQueue();
|
||||
};
|
||||
|
||||
const onClickInvoiceNow = async (customer: any, transactionIds: number[]) => {
|
||||
if (transactionIds.length === 0) {
|
||||
if (customer?.meta?.fixed_pricing) {
|
||||
const month = dates.variables.start.value.getMonth() + 1;
|
||||
const year = dates.variables.start.value.getFullYear();
|
||||
|
||||
await SessionUser.objects.collectedOrderInvoices.functions.createVehicleSubscriptionInvoice(customer.customer_number, month, year)
|
||||
await SessionUser.objects.collectedOrderInvoices.functions
|
||||
.createVehicleSubscriptionInvoice(customer.customer_number, month, year)
|
||||
.then((response: any) => {
|
||||
const newInvoiceCollectionId = response?.data?.data?.id;
|
||||
if (!newInvoiceCollectionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
SessionUser.objects.collectedOrderInvoices.functions.add_fixed_pricing(newInvoiceCollectionId)
|
||||
SessionUser.objects.collectedOrderInvoices.functions
|
||||
.add_fixed_pricing(newInvoiceCollectionId)
|
||||
.then(() => {
|
||||
invoiceQueue.addInvoiceCollectionsToQueue([newInvoiceCollectionId]);
|
||||
invoiceQueue.processInvoiceCollectionQueue();
|
||||
queueInvoiceCollections([newInvoiceCollectionId]);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error("Error adding fixed pricing to invoice collection:", error);
|
||||
@@ -112,17 +132,18 @@ const onClickInvoiceNow = async (customer: any, transactionIds: number[]) => {
|
||||
const month = dates.variables.start.value.getMonth() + 1;
|
||||
const year = dates.variables.start.value.getFullYear();
|
||||
|
||||
await SessionUser.objects.collectedOrderInvoices.functions.createVehicleSubscriptionInvoice(customer.customer_number, month, year)
|
||||
await SessionUser.objects.collectedOrderInvoices.functions
|
||||
.createVehicleSubscriptionInvoice(customer.customer_number, month, year)
|
||||
.then((response: any) => {
|
||||
const newInvoiceCollectionId = response?.data?.data?.id;
|
||||
if (!newInvoiceCollectionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
SessionUser.objects.collectedOrderInvoices.functions.add_vehicle_subscriptions(newInvoiceCollectionId)
|
||||
SessionUser.objects.collectedOrderInvoices.functions
|
||||
.add_vehicle_subscriptions(newInvoiceCollectionId)
|
||||
.then(() => {
|
||||
invoiceQueue.addInvoiceCollectionsToQueue([newInvoiceCollectionId]);
|
||||
invoiceQueue.processInvoiceCollectionQueue();
|
||||
queueInvoiceCollections([newInvoiceCollectionId]);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error("Error adding vehicle subscriptions to invoice collection:", error);
|
||||
@@ -136,21 +157,23 @@ const onClickInvoiceNow = async (customer: any, transactionIds: number[]) => {
|
||||
return;
|
||||
}
|
||||
|
||||
fetchMissingInvoiceCollections(transactionIds).then(() => {
|
||||
const invoiceCollectionIds = transactionIds
|
||||
.map((transactionId) => transactionIdsInvoiceCollectionCache.value[transactionId])
|
||||
.filter((invoiceCollectionId): invoiceCollectionId is number => invoiceCollectionId !== null);
|
||||
const uniqueInvoiceCollectionIds = Array.from(new Set(invoiceCollectionIds));
|
||||
|
||||
if (uniqueInvoiceCollectionIds.length > 0) {
|
||||
invoiceQueue.addInvoiceCollectionsToQueue(uniqueInvoiceCollectionIds);
|
||||
invoiceQueue.processInvoiceCollectionQueue();
|
||||
}
|
||||
});
|
||||
await fetchMissingInvoiceCollections(customer, transactionIds);
|
||||
queueInvoiceCollections(getInvoiceCollectionIdsForTransactionIds(customer, transactionIds));
|
||||
};
|
||||
|
||||
const fetchMissingInvoiceCollections = async (transactionIds: number[]) => {
|
||||
const uncachedTransactionIds = transactionIds.filter((transactionId) => !(transactionId in transactionIdsInvoiceCollectionCache.value));
|
||||
const getTransactionById = (customer: any, transactionId: number) => {
|
||||
return Array.isArray(customer?.transactions)
|
||||
? customer.transactions.find((transaction: any) => Number(transaction?.id) === Number(transactionId))
|
||||
: null;
|
||||
};
|
||||
|
||||
const fetchMissingInvoiceCollections = async (customer: any, transactionIds: number[]) => {
|
||||
const uncachedTransactionIds = transactionIds.filter(
|
||||
(transactionId) =>
|
||||
!(transactionId in transactionIdsInvoiceCollectionCache.value) &&
|
||||
getTransactionInvoiceCollectionId(getTransactionById(customer, transactionId) ?? { id: transactionId }) === null
|
||||
);
|
||||
|
||||
if (uncachedTransactionIds.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -174,32 +197,51 @@ const getTransactionInvoiceCollectionId = (transaction: any) => {
|
||||
: null;
|
||||
};
|
||||
|
||||
const getInvoiceCollectionIdsForTransactionIds = (customer: any, transactionIds: number[]) => {
|
||||
return transactionIds
|
||||
.map((transactionId) =>
|
||||
getTransactionInvoiceCollectionId(getTransactionById(customer, transactionId) ?? { id: transactionId })
|
||||
)
|
||||
.filter((invoiceCollectionId): invoiceCollectionId is number => invoiceCollectionId !== null);
|
||||
};
|
||||
|
||||
const isInvoiceCollectionQueuedLocally = (invoiceCollectionId: number | null | undefined) => {
|
||||
if (!invoiceCollectionId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return invoiceQueue.invoiceCollectionQueueInProgress.value.includes(invoiceCollectionId)
|
||||
|| invoiceQueue.invoiceCollectionQueue.value.includes(invoiceCollectionId);
|
||||
return (
|
||||
invoiceQueue.invoiceCollectionQueueInProgress.value.includes(invoiceCollectionId) ||
|
||||
invoiceQueue.invoiceCollectionQueue.value.includes(invoiceCollectionId)
|
||||
);
|
||||
};
|
||||
|
||||
const getCustomerActionableTransactions = (customer: any) => {
|
||||
return getTransactionsInView(customer).filter((transaction: any) => transaction?.booked !== true && transaction?.excluded !== true);
|
||||
return getTransactionsInView(customer).filter(
|
||||
(transaction: any) => transaction?.booked !== true && transaction?.excluded !== true
|
||||
);
|
||||
};
|
||||
|
||||
const getLocalQueuedInvoiceCollectionIdsForCustomer = (customer: any) => {
|
||||
return Array.from(new Set(
|
||||
getCustomerActionableTransactions(customer)
|
||||
.map((transaction: any) => getTransactionInvoiceCollectionId(transaction))
|
||||
.filter((invoiceCollectionId): invoiceCollectionId is number => (
|
||||
Number.isInteger(invoiceCollectionId) && (invoiceCollectionId ?? 0) > 0 && isInvoiceCollectionQueuedLocally(invoiceCollectionId)
|
||||
))
|
||||
));
|
||||
return Array.from(
|
||||
new Set(
|
||||
getCustomerActionableTransactions(customer)
|
||||
.map((transaction: any) => getTransactionInvoiceCollectionId(transaction))
|
||||
.filter(
|
||||
(invoiceCollectionId): invoiceCollectionId is number =>
|
||||
Number.isInteger(invoiceCollectionId) &&
|
||||
(invoiceCollectionId ?? 0) > 0 &&
|
||||
isInvoiceCollectionQueuedLocally(invoiceCollectionId)
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const getCustomerQueueStatuses = (customer: any) => {
|
||||
const backendStatuses = Array.isArray(customer?.queue?.statuses)
|
||||
? Array.from(new Set(customer.queue.statuses.filter((status: string) => typeof status === "string" && status.length > 0)))
|
||||
? Array.from(
|
||||
new Set(customer.queue.statuses.filter((status: string) => typeof status === "string" && status.length > 0))
|
||||
)
|
||||
: [];
|
||||
|
||||
if (backendStatuses.length > 0) {
|
||||
@@ -212,12 +254,12 @@ const getCustomerQueueStatuses = (customer: any) => {
|
||||
}
|
||||
|
||||
const statuses = [];
|
||||
const hasProcessing = queuedInvoiceCollectionIds.some((invoiceCollectionId) => (
|
||||
const hasProcessing = queuedInvoiceCollectionIds.some((invoiceCollectionId) =>
|
||||
invoiceQueue.invoiceCollectionQueueInProgress.value.includes(invoiceCollectionId)
|
||||
));
|
||||
const hasQueued = queuedInvoiceCollectionIds.some((invoiceCollectionId) => (
|
||||
);
|
||||
const hasQueued = queuedInvoiceCollectionIds.some((invoiceCollectionId) =>
|
||||
invoiceQueue.invoiceCollectionQueue.value.includes(invoiceCollectionId)
|
||||
));
|
||||
);
|
||||
|
||||
if (hasProcessing) {
|
||||
statuses.push(ECONOMIC_QUEUE_STATUS.PROCESSING);
|
||||
@@ -241,7 +283,11 @@ const isCustomerQueueBlocked = (customer: any) => {
|
||||
|
||||
return actionableTransactions.every((transaction: any) => {
|
||||
const invoiceCollectionId = getTransactionInvoiceCollectionId(transaction);
|
||||
return Number.isInteger(invoiceCollectionId) && (invoiceCollectionId ?? 0) > 0 && isInvoiceCollectionQueuedLocally(invoiceCollectionId);
|
||||
return (
|
||||
Number.isInteger(invoiceCollectionId) &&
|
||||
(invoiceCollectionId ?? 0) > 0 &&
|
||||
isInvoiceCollectionQueuedLocally(invoiceCollectionId)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -269,8 +315,10 @@ const isAllCustomerTransactionsBooked = (customer: any, transactionIds: number[]
|
||||
.filter((transaction: any) => transaction.excluded === true)
|
||||
.map((transaction: any) => transaction.id);
|
||||
|
||||
return transactionIds.every((transactionId) => bookedTransactionIds.includes(transactionId))
|
||||
|| transactionIds.every((transactionId) => excludedTransactionIds.includes(transactionId));
|
||||
return (
|
||||
transactionIds.every((transactionId) => bookedTransactionIds.includes(transactionId)) ||
|
||||
transactionIds.every((transactionId) => excludedTransactionIds.includes(transactionId))
|
||||
);
|
||||
};
|
||||
|
||||
const getTransactionQueryParameters = () => {
|
||||
@@ -286,15 +334,16 @@ const getTransactionQueryParameters = () => {
|
||||
<div data-testid="invoicing-period-view-all" :data-current-view="view.variables.currentView.value">
|
||||
<InvoicingBillingPeriodStatistics />
|
||||
<InvoicingBillingPeriodFilters @filterChanged="(filters) => onFilterChanged(filters)" />
|
||||
<div style="min-height: 300px;"><!--Spacer--></div>
|
||||
<div style="min-height: 300px"><!--Spacer--></div>
|
||||
|
||||
<div class="columns is-multiline is-mobile">
|
||||
<template
|
||||
v-for="customer in customersInCurrentView"
|
||||
:key="customer.customer_number"
|
||||
>
|
||||
<template v-for="customer in customersInCurrentView" :key="customer.customer_number">
|
||||
<div class="column is-12" v-show="tmpFilters.isCustomerVisible(customer) ?? true">
|
||||
<WhiteBox class="mb-2" :has-border="true" :data-testid="`invoicing-period-customer-${customer.customer_number}`">
|
||||
<WhiteBox
|
||||
class="mb-2"
|
||||
:has-border="true"
|
||||
:data-testid="`invoicing-period-customer-${customer.customer_number}`"
|
||||
>
|
||||
<div class="columns is-vcentered is-clickable" @click="onClickCustomer(customer)">
|
||||
<div class="column">
|
||||
<ColorIndicator
|
||||
@@ -329,22 +378,61 @@ const getTransactionQueryParameters = () => {
|
||||
<div class="column is-narrow">
|
||||
<p v-if="customer.transactions.length !== 0">
|
||||
{{ view.functions.filterExcluded(customer.transactions).length }}
|
||||
{{ view.functions.filterExcluded(customer.transactions).length > 1 ? SessionUser.objects.orders.meta.labels.multiple : SessionUser.objects.orders.meta.labels.single }}
|
||||
{{
|
||||
view.functions.filterExcluded(customer.transactions).length > 1
|
||||
? SessionUser.objects.orders.meta.labels.multiple
|
||||
: SessionUser.objects.orders.meta.labels.single
|
||||
}}
|
||||
</p>
|
||||
<p v-else>
|
||||
{{ SessionUser.objects.global.language.none }} {{ SessionUser.objects.orders.meta.labels.multiple }}
|
||||
</p>
|
||||
<p v-else>{{ SessionUser.objects.global.language.none }} {{ SessionUser.objects.orders.meta.labels.multiple }}</p>
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
<p>{{ SessionUser.functions.currency.toLocal(view.functions.getCustomerViewTotalNetAmount(customer, { includeFixedPricing: true, includeVehicleSubscriptions: true, includeTransactions: true })) }}</p>
|
||||
<p>
|
||||
{{
|
||||
SessionUser.functions.currency.toLocal(
|
||||
view.functions.getCustomerViewTotalNetAmount(customer, {
|
||||
includeFixedPricing: true,
|
||||
includeVehicleSubscriptions: true,
|
||||
includeTransactions: true,
|
||||
})
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<p
|
||||
v-if="view.functions.getCustomerViewTotalNetAmount(customer, { includeFixedPricing: true, includeVehicleSubscriptions: true, includeTransactions: true }) !== view.functions.getCustomerViewTotalNetAmount(customer, { includeFixedPricing: false, includeVehicleSubscriptions: false, includeTransactions: true })"
|
||||
v-if="
|
||||
view.functions.getCustomerViewTotalNetAmount(customer, {
|
||||
includeFixedPricing: true,
|
||||
includeVehicleSubscriptions: true,
|
||||
includeTransactions: true,
|
||||
}) !==
|
||||
view.functions.getCustomerViewTotalNetAmount(customer, {
|
||||
includeFixedPricing: false,
|
||||
includeVehicleSubscriptions: false,
|
||||
includeTransactions: true,
|
||||
})
|
||||
"
|
||||
class="has-text-grey-light is-size-7"
|
||||
>
|
||||
({{ SessionUser.functions.currency.toLocal(view.functions.getCustomerViewTotalNetAmount(customer, { includeFixedPricing: false, includeVehicleSubscriptions: false, includeTransactions: true })) }})
|
||||
({{
|
||||
SessionUser.functions.currency.toLocal(
|
||||
view.functions.getCustomerViewTotalNetAmount(customer, {
|
||||
includeFixedPricing: false,
|
||||
includeVehicleSubscriptions: false,
|
||||
includeTransactions: true,
|
||||
})
|
||||
)
|
||||
}})
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="column is-narrow"
|
||||
v-if="isAllCustomerTransactionsBooked(customer, getCustomerTransactionsInView(customer)) && !customer.requires_action && !isCustomerQueueBlocked(customer)"
|
||||
v-if="
|
||||
isAllCustomerTransactionsBooked(customer, getCustomerTransactionsInView(customer)) &&
|
||||
!customer.requires_action &&
|
||||
!isCustomerQueueBlocked(customer)
|
||||
"
|
||||
>
|
||||
<span class="tag is-success is-light is-small">
|
||||
<span class="icon is-small">
|
||||
@@ -369,8 +457,9 @@ const getTransactionQueryParameters = () => {
|
||||
<div class="column is-narrow" v-else>
|
||||
<button
|
||||
v-if="tmpFilters.displayRequiresAction && customer.requires_action"
|
||||
type="button"
|
||||
class="button is-small is-dark"
|
||||
@click.stop="onClickInvoiceNow(customer, getTransactionIds(customer))"
|
||||
@click.prevent.stop="onClickInvoiceNow(customer, getTransactionIds(customer))"
|
||||
:data-testid="`invoicing-period-customer-invoice-${customer.customer_number}`"
|
||||
>
|
||||
<span class="icon is-small">
|
||||
@@ -433,5 +522,4 @@ const getTransactionQueryParameters = () => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -626,14 +626,96 @@ test.describe("Invoicing period tab", () => {
|
||||
await expect(odenseBookedCell).not.toContainText("450");
|
||||
});
|
||||
|
||||
test("@smoke period view shows invoice action only for customers requiring action", async ({ page }) => {
|
||||
test("@smoke period view invoices required-action customers without opening collection tab", async ({ page }) => {
|
||||
await openPeriodView(page);
|
||||
|
||||
const orderLookups = [];
|
||||
const economicInvoiceRequests = [];
|
||||
const popupUrls = [];
|
||||
|
||||
page.on("popup", (popup) => {
|
||||
popupUrls.push(popup.url());
|
||||
});
|
||||
|
||||
await page.route("**/order**", async (route) => {
|
||||
if (route.request().method() !== "GET" || !matchesApiPath(route.request().url(), "/order")) {
|
||||
await route.fallback();
|
||||
return;
|
||||
}
|
||||
|
||||
const url = new URL(route.request().url());
|
||||
const orderId = Number(url.searchParams.get("id") || 0);
|
||||
orderLookups.push(orderId);
|
||||
await route.fulfill(
|
||||
json({
|
||||
success: true,
|
||||
data: {
|
||||
id: orderId,
|
||||
invoice_collection_id: 55501,
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
await page.route("**/collected-invoices/economic**", async (route) => {
|
||||
if (matchesApiPath(route.request().url(), "/collected-invoices/economic/queue/status")) {
|
||||
await route.fulfill(
|
||||
json({
|
||||
data: {
|
||||
job: {
|
||||
id: 77001,
|
||||
status: "COMPLETED",
|
||||
progress_percent: 100,
|
||||
progress_message: "Done",
|
||||
result: {},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
route.request().method() !== "POST" ||
|
||||
!matchesApiPath(route.request().url(), "/collected-invoices/economic")
|
||||
) {
|
||||
await route.fallback();
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = JSON.parse(route.request().postData() || "{}");
|
||||
economicInvoiceRequests.push(payload);
|
||||
await route.fulfill(
|
||||
json({
|
||||
data: {
|
||||
job: {
|
||||
id: 77001,
|
||||
status: "QUEUED",
|
||||
progress_percent: 0,
|
||||
progress_message: "Queued",
|
||||
result: null,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
await page.getByTestId("invoicing-period-view-selector-all").click();
|
||||
await expect(page.getByTestId("invoicing-period-customer-4001")).toBeVisible();
|
||||
await expect(page.getByTestId("invoicing-period-customer-invoice-4001")).toBeVisible();
|
||||
await expect(page.getByTestId("invoicing-period-customer-4002")).toBeVisible();
|
||||
await expect(page.getByTestId("invoicing-period-customer-invoice-4002")).toHaveCount(0);
|
||||
|
||||
await page.getByTestId("invoicing-period-customer-invoice-4001").click();
|
||||
|
||||
await expect.poll(() => orderLookups).toEqual([9001]);
|
||||
await expect.poll(() => economicInvoiceRequests.length).toBe(1);
|
||||
expect(economicInvoiceRequests[0]).toEqual({
|
||||
id: 55501,
|
||||
send_as_is: false,
|
||||
});
|
||||
await page.waitForTimeout(250);
|
||||
expect(popupUrls).toEqual([]);
|
||||
await expect(page).toHaveURL(/activeTab=period/);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @vitest-environment jsdom
|
||||
import { computed, nextTick } from "vue";
|
||||
import { mount } from "@vue/test-utils";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { sharedVariablesRef, currentViewRef, startDateRef, endDateRef, queueRef, inProgressRef } = vi.hoisted(() => {
|
||||
const { ref } = require("vue");
|
||||
@@ -120,6 +120,8 @@ vi.mock(
|
||||
);
|
||||
|
||||
import InvoicingBillingPeriodViewAll from "@/views/dashboards/superUserDashboard/InvoicingBillingPeriod/views/InvoicingBillingPeriodViewAll.vue";
|
||||
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
||||
import { invoiceQueue } from "@/views/dashboards/superUserDashboard/InvoicingBillingPeriod/imports/InvoicingBillingPeriodImportInvoiceQueue.vue";
|
||||
|
||||
const mountView = () =>
|
||||
mount(InvoicingBillingPeriodViewAll, {
|
||||
@@ -143,6 +145,10 @@ describe("Invoicing period queue state", () => {
|
||||
currentViewRef.value = "all";
|
||||
queueRef.value = [];
|
||||
inProgressRef.value = [];
|
||||
SessionUser.objects.orders.get.multiple.mockReset();
|
||||
SessionUser.objects.orders.get.multiple.mockResolvedValue([]);
|
||||
invoiceQueue.addInvoiceCollectionsToQueue.mockReset();
|
||||
invoiceQueue.processInvoiceCollectionQueue.mockReset();
|
||||
sharedVariablesRef.value = {
|
||||
types: {
|
||||
all: [
|
||||
@@ -209,6 +215,10 @@ describe("Invoicing period queue state", () => {
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("renders a disabled queued CTA when the backend marks the customer as action-blocked", async () => {
|
||||
const wrapper = mountView();
|
||||
await nextTick();
|
||||
@@ -226,4 +236,55 @@ describe("Invoicing period queue state", () => {
|
||||
expect(wrapper.find("[data-testid='invoicing-period-customer-queue-1002']").exists()).toBe(false);
|
||||
expect(wrapper.get("[data-testid='invoicing-period-customer-invoice-1002']").text()).toContain("Invoice now");
|
||||
});
|
||||
|
||||
it("queues period invoice collections without opening the invoice collection page", async () => {
|
||||
const windowOpenSpy = vi.spyOn(window, "open").mockImplementation(() => null);
|
||||
sharedVariablesRef.value = {
|
||||
types: {
|
||||
all: [
|
||||
{
|
||||
id: 3,
|
||||
customer_number: 1003,
|
||||
customer_name: "Ready Customer",
|
||||
requires_action: true,
|
||||
queue: {
|
||||
has_active_job: false,
|
||||
statuses: [],
|
||||
invoice_collection_ids: [],
|
||||
is_action_blocked: false,
|
||||
},
|
||||
transactions: [
|
||||
{
|
||||
id: 6001,
|
||||
amount: 75,
|
||||
booked: false,
|
||||
excluded: false,
|
||||
invoice_collection_id: 3001,
|
||||
date: "2026-04-13T10:00:00.000Z",
|
||||
},
|
||||
{
|
||||
id: 6002,
|
||||
amount: 125,
|
||||
booked: false,
|
||||
excluded: false,
|
||||
invoice_collection_id: 3001,
|
||||
date: "2026-04-14T10:00:00.000Z",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = mountView();
|
||||
await nextTick();
|
||||
|
||||
await wrapper.get("[data-testid='invoicing-period-customer-invoice-1003']").trigger("click");
|
||||
await nextTick();
|
||||
|
||||
expect(SessionUser.objects.orders.get.multiple).not.toHaveBeenCalled();
|
||||
expect(invoiceQueue.addInvoiceCollectionsToQueue).toHaveBeenCalledWith([3001]);
|
||||
expect(invoiceQueue.processInvoiceCollectionQueue).toHaveBeenCalledTimes(1);
|
||||
expect(windowOpenSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user