Add bulk action preview and apply functionality for invoice collections

This commit is contained in:
Jeppe Bundgaard
2026-07-08 13:51:54 +02:00
parent 59af8453f3
commit e399c9f974
14 changed files with 775 additions and 11 deletions
@@ -1,7 +1,7 @@
<script setup>
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { t, locale } = useI18n();
import ActionSettingsWheelButton from "@/components/displays/buttons/ActionSettingsWheelButton.vue";
import OrderAttachmentsActionButton from "@/components/displays/department/pos/orders/OrderAttachmentsActionButton.vue";
@@ -266,6 +266,23 @@ const normalizeInvoiceCollectionId = (invoiceCollectionId) => {
: null;
};
const INVOICE_COLLECTION_BULK_ACTIONS = Object.freeze({
CLEAN_CUSTOMER_RULES: "remove_customer_rule_violations",
MERGE: "merge_collections",
SPLIT_BY_MONTH: "split_by_month",
RESET_HIDDEN_PRICES: "reset_hidden_item_prices",
QUEUE_ECONOMIC: "queue_economic",
});
const getApiPayload = (response) => response?.data?.data ?? response?.data ?? response ?? {};
const escapeHtml = (value) => String(value ?? "")
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
const getInvoiceCollectionResponseOrders = (response) => {
if (Array.isArray(response?.orders)) {
return response.orders;
@@ -445,19 +462,27 @@ const isDropdownActive = (object) => {
*/
const selectedInvoiceCollections = ref([]);
const toggleInvoiceCollectionSelection = (invoiceCollectionId) => {
const normalizedInvoiceCollectionId = normalizeInvoiceCollectionId(invoiceCollectionId);
if (normalizedInvoiceCollectionId === null) {
return;
}
// Check if the invoice collection is already selected
if (selectedInvoiceCollections.value.includes(invoiceCollectionId)) {
if (selectedInvoiceCollections.value.includes(normalizedInvoiceCollectionId)) {
// If it is, remove it from the list
selectedInvoiceCollections.value = selectedInvoiceCollections.value.filter((id) => id !== invoiceCollectionId);
selectedInvoiceCollections.value = selectedInvoiceCollections.value.filter((id) => id !== normalizedInvoiceCollectionId);
} else {
// If it is not, add it to the list
selectedInvoiceCollections.value.push(invoiceCollectionId);
selectedInvoiceCollections.value.push(normalizedInvoiceCollectionId);
}
};
const isInvoiceCollectionSelected = (invoiceCollectionId) => {
const normalizedInvoiceCollectionId = normalizeInvoiceCollectionId(invoiceCollectionId);
if (normalizedInvoiceCollectionId === null) {
return false;
}
// Check if the invoice collection is in the selected list
return selectedInvoiceCollections.value.includes(invoiceCollectionId);
return selectedInvoiceCollections.value.includes(normalizedInvoiceCollectionId);
};
const isInvoiceCollectionSelectedAll = () => {
// Check if all invoice collections are selected
@@ -512,14 +537,202 @@ const isInvoiceQueueBusy = computed(() => {
return invoiceCollectionQueue.value.length > 0 || invoiceCollectionQueueInProgress.value.length > 0;
});
const invoiceSelectedCollections = () => {
// Check if any invoice collections are selected
if (selectedInvoiceCollections.value.length === 0) {
const getSelectedInvoiceCollectionIds = () => selectedInvoiceCollections.value
.map((invoiceCollectionId) => normalizeInvoiceCollectionId(invoiceCollectionId))
.filter((invoiceCollectionId) => invoiceCollectionId !== null);
const getBulkActionLabel = (action) => t(`invoicing_period.invoice_collection_actions.actions.${action}`);
const renderBulkActionPreviewHtml = (preview) => {
const summary = preview?.summary || {};
const collections = Number(summary.collections ?? preview?.invoice_collection_ids?.length ?? 0);
const changedCount = Number(summary.changed_count ?? summary.order_items ?? summary.orders_to_move ?? 0);
const skippedCount = Number(summary.skipped_count ?? 0);
const blockers = Array.isArray(preview?.blockers) ? preview.blockers : [];
const orderItems = Array.isArray(preview?.order_items) ? preview.order_items : [];
const orders = Array.isArray(preview?.orders) ? preview.orders : [];
const splitItems = Array.isArray(preview?.items) ? preview.items : [];
const detailItems = [
...orderItems.map((item) => t("invoicing_period.invoice_collection_actions.preview.order_item_line", {
collection: item.invoice_collection_id,
order: item.order_id,
product: item.product_name || item.product_id,
})),
...orders.map((item) => t("invoicing_period.invoice_collection_actions.preview.order_move_line", {
order: item.order_id,
source: item.source_invoice_collection_id,
target: item.target_invoice_collection_id,
})),
...splitItems.map((item) => t("invoicing_period.invoice_collection_actions.preview.collection_status_line", {
collection: item.invoice_collection_id,
status: item.status,
})),
].slice(0, 10);
const summaryLines = [
t("invoicing_period.invoice_collection_actions.preview.collections", { count: collections }),
t("invoicing_period.invoice_collection_actions.preview.changed", { count: changedCount }),
...(skippedCount > 0 ? [t("invoicing_period.invoice_collection_actions.preview.skipped", { count: skippedCount })] : []),
...(preview?.target_invoice_collection_id
? [t("invoicing_period.invoice_collection_actions.preview.merge_target", { id: preview.target_invoice_collection_id })]
: []),
];
const html = [
`<p>${escapeHtml(t("invoicing_period.invoice_collection_actions.preview.requires_confirmation", {
phrase: preview?.confirmation_phrase || "",
}))}</p>`,
`<ul class="has-text-left">${summaryLines.map((line) => `<li>${escapeHtml(line)}</li>`).join("")}</ul>`,
];
if (detailItems.length > 0) {
html.push(`<hr><p class="has-text-left has-text-weight-bold">${escapeHtml(t("invoicing_period.invoice_collection_actions.preview.affected_examples"))}</p>`);
html.push(`<ul class="has-text-left">${detailItems.map((line) => `<li>${escapeHtml(line)}</li>`).join("")}</ul>`);
}
if (blockers.length > 0) {
html.push(`<hr><p class="has-text-left has-text-weight-bold has-text-danger">${escapeHtml(t("invoicing_period.invoice_collection_actions.preview.blockers"))}</p>`);
html.push(`<ul class="has-text-left">${blockers.map((blocker) => `<li>${escapeHtml(blocker.message || blocker.code)}</li>`).join("")}</ul>`);
}
return html.join("");
};
const chooseMergeTargetInvoiceCollection = async (invoiceCollectionIds) => {
const result = await Swal.fire({
title: t("invoicing_period.invoice_collection_actions.merge_target_title"),
input: "select",
inputOptions: invoiceCollectionIds.reduce((options, invoiceCollectionId) => ({
...options,
[invoiceCollectionId]: `#${invoiceCollectionId}`,
}), {}),
inputValue: String(invoiceCollectionIds[0] ?? ""),
showCancelButton: true,
confirmButtonText: t("common.continue"),
cancelButtonText: t("common.cancel"),
});
if (!result.isConfirmed) {
return null;
}
return normalizeInvoiceCollectionId(result.value);
};
const runInvoiceCollectionBulkAction = async (action) => {
const invoiceCollectionIds = getSelectedInvoiceCollectionIds();
if (invoiceCollectionIds.length === 0) {
return;
}
isInvoiceMultipleCollectionsModalOpen.value = true;
invoiceQueue.addInvoiceCollectionsToQueue(selectedInvoiceCollections.value);
invoiceQueue.processInvoiceCollectionQueue();
const options = {};
if (action === INVOICE_COLLECTION_BULK_ACTIONS.MERGE) {
if (invoiceCollectionIds.length < 2) {
await Swal.fire({
icon: "warning",
title: t("invoicing_period.invoice_collection_actions.merge_requires_multiple_title"),
text: t("invoicing_period.invoice_collection_actions.merge_requires_multiple_text"),
});
return;
}
const targetInvoiceCollectionId = await chooseMergeTargetInvoiceCollection(invoiceCollectionIds);
if (targetInvoiceCollectionId === null) {
return;
}
options.target_invoice_collection_id = targetInvoiceCollectionId;
}
try {
const previewResponse = await SessionUser.objects.collectedOrderInvoices.functions.bulk_action_preview(
action,
invoiceCollectionIds,
options,
locale.value
);
const preview = getApiPayload(previewResponse);
const blockers = Array.isArray(preview.blockers) ? preview.blockers : [];
const changedCount = Number(preview?.summary?.changed_count ?? 0);
if (blockers.length > 0 || changedCount === 0) {
await Swal.fire({
icon: blockers.length > 0 ? "error" : "info",
title: blockers.length > 0
? t("invoicing_period.invoice_collection_actions.preview.blocked_title")
: t("invoicing_period.invoice_collection_actions.preview.no_changes_title"),
html: renderBulkActionPreviewHtml(preview),
});
return;
}
const confirmation = await Swal.fire({
icon: "warning",
title: t("invoicing_period.invoice_collection_actions.preview.title", {
action: getBulkActionLabel(action),
}),
html: renderBulkActionPreviewHtml(preview),
input: "text",
inputLabel: t("invoicing_period.invoice_collection_actions.preview.confirmation_label", {
phrase: preview.confirmation_phrase,
}),
inputPlaceholder: preview.confirmation_phrase,
showCancelButton: true,
confirmButtonText: t("invoicing_period.invoice_collection_actions.preview.confirm_button"),
cancelButtonText: t("common.cancel"),
inputValidator: (value) => {
if (String(value ?? "").trim() !== String(preview.confirmation_phrase ?? "")) {
return t("invoicing_period.invoice_collection_actions.preview.confirmation_mismatch", {
phrase: preview.confirmation_phrase,
});
}
return undefined;
},
});
if (!confirmation.isConfirmed) {
return;
}
const applyResponse = await SessionUser.objects.collectedOrderInvoices.functions.bulk_action_apply({
preview_id: preview.preview_id,
action,
invoice_collection_ids: invoiceCollectionIds,
options,
confirmation_text: confirmation.value,
locale: locale.value,
});
const applied = getApiPayload(applyResponse);
if (action === INVOICE_COLLECTION_BULK_ACTIONS.QUEUE_ECONOMIC) {
const queuedInvoiceCollectionIds = applied?.result?.queued_invoice_collection_ids || invoiceCollectionIds;
isInvoiceMultipleCollectionsModalOpen.value = true;
invoiceQueue.addInvoiceCollectionsToQueue(queuedInvoiceCollectionIds);
invoiceQueue.processInvoiceCollectionQueue();
} else {
selectedInvoiceCollections.value = [];
await loadList();
}
await Swal.fire({
icon: "success",
title: t("invoicing_period.invoice_collection_actions.success_title"),
text: t("invoicing_period.invoice_collection_actions.success_text", {
count: applied?.result?.changed_count ?? applied?.summary?.changed_count ?? changedCount,
}),
timer: 2000,
showConfirmButton: false,
});
} catch (error) {
await Swal.fire({
icon: "error",
title: t("invoicing_period.invoice_collection_actions.error_title"),
text: SessionUser.functions.parseErrorMessage(error),
});
}
};
const invoiceSelectedCollections = () => {
runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.QUEUE_ECONOMIC);
};
const retryInvoiceCollection = (invoiceCollectionId) => {
@@ -904,6 +1117,34 @@ const formatCashierName = (order) => {
selectedInvoiceCollections.length
}})
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.CLEAN_CUSTOMER_RULES)"
:disabled="selectedInvoiceCollections.length === 0"
>
{{ t("invoicing_period.invoice_collection_actions.actions.remove_customer_rule_violations") }}
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.MERGE)"
:disabled="selectedInvoiceCollections.length < 2"
>
{{ t("invoicing_period.invoice_collection_actions.actions.merge_collections") }}
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.SPLIT_BY_MONTH)"
:disabled="selectedInvoiceCollections.length === 0"
>
{{ t("invoicing_period.invoice_collection_actions.actions.split_by_month") }}
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.RESET_HIDDEN_PRICES)"
:disabled="selectedInvoiceCollections.length === 0"
>
{{ t("invoicing_period.invoice_collection_actions.actions.reset_hidden_item_prices") }}
</button>
<!-- Select / Unselect all invoice collections -->
<button
class="button is-small"
@@ -1395,6 +1636,34 @@ const formatCashierName = (order) => {
{{ SessionUser.objects.global.language.invoice }}
{{ SessionUser.objects.global.language.selected_multiple }} ({{ selectedInvoiceCollections.length }})
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.CLEAN_CUSTOMER_RULES)"
:disabled="selectedInvoiceCollections.length === 0"
>
{{ t("invoicing_period.invoice_collection_actions.actions.remove_customer_rule_violations") }}
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.MERGE)"
:disabled="selectedInvoiceCollections.length < 2"
>
{{ t("invoicing_period.invoice_collection_actions.actions.merge_collections") }}
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.SPLIT_BY_MONTH)"
:disabled="selectedInvoiceCollections.length === 0"
>
{{ t("invoicing_period.invoice_collection_actions.actions.split_by_month") }}
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.RESET_HIDDEN_PRICES)"
:disabled="selectedInvoiceCollections.length === 0"
>
{{ t("invoicing_period.invoice_collection_actions.actions.reset_hidden_item_prices") }}
</button>
<button
class="button is-small"
@click="selectAllInvoiceCollections()"
@@ -1612,6 +1881,34 @@ const formatCashierName = (order) => {
{{ SessionUser.objects.global.language.invoice }}
{{ SessionUser.objects.global.language.selected_multiple }} ({{ selectedInvoiceCollections.length }})
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.CLEAN_CUSTOMER_RULES)"
:disabled="selectedInvoiceCollections.length === 0"
>
{{ t("invoicing_period.invoice_collection_actions.actions.remove_customer_rule_violations") }}
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.MERGE)"
:disabled="selectedInvoiceCollections.length < 2"
>
{{ t("invoicing_period.invoice_collection_actions.actions.merge_collections") }}
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.SPLIT_BY_MONTH)"
:disabled="selectedInvoiceCollections.length === 0"
>
{{ t("invoicing_period.invoice_collection_actions.actions.split_by_month") }}
</button>
<button
class="button is-small"
@click="runInvoiceCollectionBulkAction(INVOICE_COLLECTION_BULK_ACTIONS.RESET_HIDDEN_PRICES)"
:disabled="selectedInvoiceCollections.length === 0"
>
{{ t("invoicing_period.invoice_collection_actions.actions.reset_hidden_item_prices") }}
</button>
<button
class="button is-small"
@click="selectAllInvoiceCollections()"
@@ -516,6 +516,43 @@ export const CollectedOrderInvoices = {
throw error;
});
},
bulk_action_preview: async (action, invoiceCollectionIds = [], options = {}, locale = null) => {
return authenticatedRequest('/collected-invoices/bulk-actions/preview', 'POST', {
action,
invoice_collection_ids: invoiceCollectionIds.map((id) => parseInt(id)).filter((id) => Number.isInteger(id) && id > 0),
options,
...(locale ? { locale } : {}),
}).then((response) => {
console.log(response);
return response;
}).catch((error) => {
console.log(error);
throw error;
});
},
bulk_action_apply: async ({
preview_id,
action,
invoice_collection_ids = [],
options = {},
confirmation_text,
locale = null,
}) => {
return authenticatedRequest('/collected-invoices/bulk-actions/apply', 'POST', {
preview_id,
action,
invoice_collection_ids: invoice_collection_ids.map((id) => parseInt(id)).filter((id) => Number.isInteger(id) && id > 0),
options,
confirmation_text,
...(locale ? { locale } : {}),
}).then((response) => {
console.log(response);
return response;
}).catch((error) => {
console.log(error);
throw error;
});
},
move_to_customer: async (id, customerNumber) => {
const invoiceCollectionId = parseInt(id);
const targetCustomerNumber = parseInt(customerNumber);
+33
View File
@@ -4165,6 +4165,39 @@
"split_success_title": "Månedsopdeling fuldført",
"text": "Du er ved at fakturere ordrer fra flere måneder sammen ({months}). Skal de i stedet opdeles efter måned?",
"title": "Ordrer fra flere måneder"
},
"invoice_collection_actions": {
"actions": {
"merge_collections": "Sammenlæg",
"queue_economic": "Fakturer valgte",
"remove_customer_rule_violations": "Fjern regelbrud",
"reset_hidden_item_prices": "Nulstil skjulte priser",
"split_by_month": "Opdel efter måned"
},
"error_title": "Handlingen mislykkedes",
"merge_requires_multiple_text": "Vælg mindst to fakturasamlinger for at sammenlægge dem.",
"merge_requires_multiple_title": "Vælg flere fakturasamlinger",
"merge_target_title": "Vælg målfakturasamling",
"preview": {
"affected_examples": "Eksempler på ændringer",
"blocked_title": "Handlingen er blokeret",
"blockers": "Blokeringer",
"changed": "Ændringer: {count}",
"collection_status_line": "Fakturasamling #{collection}: {status}",
"collections": "Fakturasamlinger: {count}",
"confirm_button": "Udfør handling",
"confirmation_label": "Skriv {phrase} for at bekræfte",
"confirmation_mismatch": "Skriv præcis {phrase} for at fortsætte.",
"merge_target": "Mål: fakturasamling #{id}",
"no_changes_title": "Ingen ændringer",
"order_item_line": "Fakturasamling #{collection}, ordre #{order}: {product}",
"order_move_line": "Ordre #{order}: #{source} til #{target}",
"requires_confirmation": "Gennemgå forhåndsvisningen. Ingen ændringer udføres før du skriver {phrase}.",
"skipped": "Sprunget over: {count}",
"title": "Forhåndsvis {action}"
},
"success_text": "Udførte {count} ændringer.",
"success_title": "Handling fuldført"
}
},
"invoicing": {
+33
View File
@@ -4276,6 +4276,39 @@
"split_success_title": "Monatsaufteilung abgeschlossen",
"text": "Sie sind dabei, Aufträge aus mehreren Monaten gemeinsam abzurechnen ({months}). Sollen sie stattdessen nach Monat aufgeteilt werden?",
"title": "Aufträge aus mehreren Monaten"
},
"invoice_collection_actions": {
"actions": {
"merge_collections": "Zusammenführen",
"queue_economic": "Ausgewählte fakturieren",
"remove_customer_rule_violations": "Regelverstöße entfernen",
"reset_hidden_item_prices": "Ausgeblendete Preise zurücksetzen",
"split_by_month": "Nach Monat teilen"
},
"error_title": "Aktion fehlgeschlagen",
"merge_requires_multiple_text": "Wählen Sie mindestens zwei Rechnungssammlungen aus, um sie zusammenzuführen.",
"merge_requires_multiple_title": "Mehrere Rechnungssammlungen auswählen",
"merge_target_title": "Ziel-Rechnungssammlung auswählen",
"preview": {
"affected_examples": "Beispieländerungen",
"blocked_title": "Aktion ist blockiert",
"blockers": "Blockierungen",
"changed": "Änderungen: {count}",
"collection_status_line": "Rechnungssammlung #{collection}: {status}",
"collections": "Rechnungssammlungen: {count}",
"confirm_button": "Aktion ausführen",
"confirmation_label": "{phrase} eingeben, um zu bestätigen",
"confirmation_mismatch": "Geben Sie genau {phrase} ein, um fortzufahren.",
"merge_target": "Ziel: Rechnungssammlung #{id}",
"no_changes_title": "Keine Änderungen",
"order_item_line": "Rechnungssammlung #{collection}, Auftrag #{order}: {product}",
"order_move_line": "Auftrag #{order}: #{source} nach #{target}",
"requires_confirmation": "Prüfen Sie die Vorschau. Es werden keine Änderungen ausgeführt, bevor Sie {phrase} eingeben.",
"skipped": "Übersprungen: {count}",
"title": "{action} Vorschau"
},
"success_text": "{count} Änderungen ausgeführt.",
"success_title": "Aktion abgeschlossen"
}
},
"invoicing": {
+33
View File
@@ -3997,6 +3997,39 @@
"split_success_title": "Monthly split completed",
"text": "You are about to invoice orders from multiple months together ({months}). Should they be split by month instead?",
"title": "Orders from multiple months"
},
"invoice_collection_actions": {
"actions": {
"merge_collections": "Merge",
"queue_economic": "Invoice selected",
"remove_customer_rule_violations": "Remove rule violations",
"reset_hidden_item_prices": "Reset hidden prices",
"split_by_month": "Split by month"
},
"error_title": "Action failed",
"merge_requires_multiple_text": "Select at least two invoice collections to merge them.",
"merge_requires_multiple_title": "Select multiple invoice collections",
"merge_target_title": "Select target invoice collection",
"preview": {
"affected_examples": "Example changes",
"blocked_title": "Action is blocked",
"blockers": "Blockers",
"changed": "Changes: {count}",
"collection_status_line": "Invoice collection #{collection}: {status}",
"collections": "Invoice collections: {count}",
"confirm_button": "Apply action",
"confirmation_label": "Type {phrase} to confirm",
"confirmation_mismatch": "Type exactly {phrase} to continue.",
"merge_target": "Target: invoice collection #{id}",
"no_changes_title": "No changes",
"order_item_line": "Invoice collection #{collection}, order #{order}: {product}",
"order_move_line": "Order #{order}: #{source} to #{target}",
"requires_confirmation": "Review the preview. No changes are applied until you type {phrase}.",
"skipped": "Skipped: {count}",
"title": "Preview {action}"
},
"success_text": "Applied {count} changes.",
"success_title": "Action completed"
}
},
"invoicing": {
+33
View File
@@ -3251,6 +3251,39 @@
"split_success_title": "@:{'templates.generated.compat.invoicing_period.multi_month_invoice_warning.split_success_title'}",
"text": "@:{'templates.generated.compat.invoicing_period.multi_month_invoice_warning.text'}",
"title": "@:{'templates.generated.compat.invoicing_period.multi_month_invoice_warning.title'}"
},
"invoice_collection_actions": {
"actions": {
"merge_collections": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.actions.merge_collections'}",
"queue_economic": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.actions.queue_economic'}",
"remove_customer_rule_violations": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.actions.remove_customer_rule_violations'}",
"reset_hidden_item_prices": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.actions.reset_hidden_item_prices'}",
"split_by_month": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.actions.split_by_month'}"
},
"error_title": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.error_title'}",
"merge_requires_multiple_text": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.merge_requires_multiple_text'}",
"merge_requires_multiple_title": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.merge_requires_multiple_title'}",
"merge_target_title": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.merge_target_title'}",
"preview": {
"affected_examples": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.affected_examples'}",
"blocked_title": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.blocked_title'}",
"blockers": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.blockers'}",
"changed": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.changed'}",
"collection_status_line": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.collection_status_line'}",
"collections": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.collections'}",
"confirm_button": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.confirm_button'}",
"confirmation_label": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.confirmation_label'}",
"confirmation_mismatch": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.confirmation_mismatch'}",
"merge_target": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.merge_target'}",
"no_changes_title": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.no_changes_title'}",
"order_item_line": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.order_item_line'}",
"order_move_line": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.order_move_line'}",
"requires_confirmation": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.requires_confirmation'}",
"skipped": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.skipped'}",
"title": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.preview.title'}"
},
"success_text": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.success_text'}",
"success_title": "@:{'templates.generated.compat.invoicing_period.invoice_collection_actions.success_title'}"
}
},
"invoicing": {
+33
View File
@@ -4279,6 +4279,39 @@
"split_success_title": "Månedsdeling fullført",
"text": "Du er i ferd med å fakturere ordrer fra flere måneder samlet ({months}). Skal de i stedet deles opp etter måned?",
"title": "Ordrer fra flere måneder"
},
"invoice_collection_actions": {
"actions": {
"merge_collections": "Slå sammen",
"queue_economic": "Fakturer valgte",
"remove_customer_rule_violations": "Fjern regelbrudd",
"reset_hidden_item_prices": "Tilbakestill skjulte priser",
"split_by_month": "Del etter måned"
},
"error_title": "Handlingen mislyktes",
"merge_requires_multiple_text": "Velg minst to fakturasamlinger for å slå dem sammen.",
"merge_requires_multiple_title": "Velg flere fakturasamlinger",
"merge_target_title": "Velg målfakturasamling",
"preview": {
"affected_examples": "Eksempler på endringer",
"blocked_title": "Handlingen er blokkert",
"blockers": "Blokkeringer",
"changed": "Endringer: {count}",
"collection_status_line": "Fakturasamling #{collection}: {status}",
"collections": "Fakturasamlinger: {count}",
"confirm_button": "Utfør handling",
"confirmation_label": "Skriv {phrase} for å bekrefte",
"confirmation_mismatch": "Skriv nøyaktig {phrase} for å fortsette.",
"merge_target": "Mål: fakturasamling #{id}",
"no_changes_title": "Ingen endringer",
"order_item_line": "Fakturasamling #{collection}, ordre #{order}: {product}",
"order_move_line": "Ordre #{order}: #{source} til #{target}",
"requires_confirmation": "Gå gjennom forhåndsvisningen. Ingen endringer utføres før du skriver {phrase}.",
"skipped": "Hoppet over: {count}",
"title": "Forhåndsvis {action}"
},
"success_text": "Utførte {count} endringer.",
"success_title": "Handling fullført"
}
},
"invoicing": {
+33
View File
@@ -4329,6 +4329,39 @@
"split_success_title": "Månadsuppdelning klar",
"text": "Du håller på att fakturera ordrar från flera månader tillsammans ({months}). Ska de delas upp per månad i stället?",
"title": "Ordrar från flera månader"
},
"invoice_collection_actions": {
"actions": {
"merge_collections": "Slå ihop",
"queue_economic": "Fakturera valda",
"remove_customer_rule_violations": "Ta bort regelbrott",
"reset_hidden_item_prices": "Återställ dolda priser",
"split_by_month": "Dela efter månad"
},
"error_title": "Åtgärden misslyckades",
"merge_requires_multiple_text": "Välj minst två fakturasamlingar för att slå ihop dem.",
"merge_requires_multiple_title": "Välj flera fakturasamlingar",
"merge_target_title": "Välj målfakturasamling",
"preview": {
"affected_examples": "Exempel på ändringar",
"blocked_title": "Åtgärden är blockerad",
"blockers": "Blockeringar",
"changed": "Ändringar: {count}",
"collection_status_line": "Fakturasamling #{collection}: {status}",
"collections": "Fakturasamlingar: {count}",
"confirm_button": "Utför åtgärd",
"confirmation_label": "Skriv {phrase} för att bekräfta",
"confirmation_mismatch": "Skriv exakt {phrase} för att fortsätta.",
"merge_target": "Mål: fakturasamling #{id}",
"no_changes_title": "Inga ändringar",
"order_item_line": "Fakturasamling #{collection}, order #{order}: {product}",
"order_move_line": "Order #{order}: #{source} till #{target}",
"requires_confirmation": "Granska förhandsvisningen. Inga ändringar görs innan du skriver {phrase}.",
"skipped": "Hoppade över: {count}",
"title": "Förhandsvisa {action}"
},
"success_text": "Utförde {count} ändringar.",
"success_title": "Åtgärd slutförd"
}
},
"invoicing": {
@@ -0,0 +1,39 @@
{
"compat": {
"invoicing_period": {
"invoice_collection_actions": {
"actions": {
"merge_collections": "Sammenlæg",
"queue_economic": "Fakturer valgte",
"remove_customer_rule_violations": "Fjern regelbrud",
"reset_hidden_item_prices": "Nulstil skjulte priser",
"split_by_month": "Opdel efter måned"
},
"error_title": "Handlingen mislykkedes",
"merge_requires_multiple_text": "Vælg mindst to fakturasamlinger for at sammenlægge dem.",
"merge_requires_multiple_title": "Vælg flere fakturasamlinger",
"merge_target_title": "Vælg målfakturasamling",
"preview": {
"affected_examples": "Eksempler på ændringer",
"blocked_title": "Handlingen er blokeret",
"blockers": "Blokeringer",
"changed": "Ændringer: {count}",
"collection_status_line": "Fakturasamling #{collection}: {status}",
"collections": "Fakturasamlinger: {count}",
"confirm_button": "Udfør handling",
"confirmation_label": "Skriv {phrase} for at bekræfte",
"confirmation_mismatch": "Skriv præcis {phrase} for at fortsætte.",
"merge_target": "Mål: fakturasamling #{id}",
"no_changes_title": "Ingen ændringer",
"order_item_line": "Fakturasamling #{collection}, ordre #{order}: {product}",
"order_move_line": "Ordre #{order}: #{source} til #{target}",
"requires_confirmation": "Gennemgå forhåndsvisningen. Ingen ændringer udføres før du skriver {phrase}.",
"skipped": "Sprunget over: {count}",
"title": "Forhåndsvis {action}"
},
"success_text": "Udførte {count} ændringer.",
"success_title": "Handling fuldført"
}
}
}
}
@@ -0,0 +1,39 @@
{
"compat": {
"invoicing_period": {
"invoice_collection_actions": {
"actions": {
"merge_collections": "Zusammenführen",
"queue_economic": "Ausgewählte fakturieren",
"remove_customer_rule_violations": "Regelverstöße entfernen",
"reset_hidden_item_prices": "Ausgeblendete Preise zurücksetzen",
"split_by_month": "Nach Monat teilen"
},
"error_title": "Aktion fehlgeschlagen",
"merge_requires_multiple_text": "Wählen Sie mindestens zwei Rechnungssammlungen aus, um sie zusammenzuführen.",
"merge_requires_multiple_title": "Mehrere Rechnungssammlungen auswählen",
"merge_target_title": "Ziel-Rechnungssammlung auswählen",
"preview": {
"affected_examples": "Beispieländerungen",
"blocked_title": "Aktion ist blockiert",
"blockers": "Blockierungen",
"changed": "Änderungen: {count}",
"collection_status_line": "Rechnungssammlung #{collection}: {status}",
"collections": "Rechnungssammlungen: {count}",
"confirm_button": "Aktion ausführen",
"confirmation_label": "{phrase} eingeben, um zu bestätigen",
"confirmation_mismatch": "Geben Sie genau {phrase} ein, um fortzufahren.",
"merge_target": "Ziel: Rechnungssammlung #{id}",
"no_changes_title": "Keine Änderungen",
"order_item_line": "Rechnungssammlung #{collection}, Auftrag #{order}: {product}",
"order_move_line": "Auftrag #{order}: #{source} nach #{target}",
"requires_confirmation": "Prüfen Sie die Vorschau. Es werden keine Änderungen ausgeführt, bevor Sie {phrase} eingeben.",
"skipped": "Übersprungen: {count}",
"title": "{action} Vorschau"
},
"success_text": "{count} Änderungen ausgeführt.",
"success_title": "Aktion abgeschlossen"
}
}
}
}
@@ -0,0 +1,39 @@
{
"compat": {
"invoicing_period": {
"invoice_collection_actions": {
"actions": {
"merge_collections": "Merge",
"queue_economic": "Invoice selected",
"remove_customer_rule_violations": "Remove rule violations",
"reset_hidden_item_prices": "Reset hidden prices",
"split_by_month": "Split by month"
},
"error_title": "Action failed",
"merge_requires_multiple_text": "Select at least two invoice collections to merge them.",
"merge_requires_multiple_title": "Select multiple invoice collections",
"merge_target_title": "Select target invoice collection",
"preview": {
"affected_examples": "Example changes",
"blocked_title": "Action is blocked",
"blockers": "Blockers",
"changed": "Changes: {count}",
"collection_status_line": "Invoice collection #{collection}: {status}",
"collections": "Invoice collections: {count}",
"confirm_button": "Apply action",
"confirmation_label": "Type {phrase} to confirm",
"confirmation_mismatch": "Type exactly {phrase} to continue.",
"merge_target": "Target: invoice collection #{id}",
"no_changes_title": "No changes",
"order_item_line": "Invoice collection #{collection}, order #{order}: {product}",
"order_move_line": "Order #{order}: #{source} to #{target}",
"requires_confirmation": "Review the preview. No changes are applied until you type {phrase}.",
"skipped": "Skipped: {count}",
"title": "Preview {action}"
},
"success_text": "Applied {count} changes.",
"success_title": "Action completed"
}
}
}
}
@@ -0,0 +1,37 @@
{
"invoicing_period": {
"invoice_collection_actions": {
"actions": {
"merge_collections": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.actions.merge_collections'}",
"queue_economic": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.actions.queue_economic'}",
"remove_customer_rule_violations": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.actions.remove_customer_rule_violations'}",
"reset_hidden_item_prices": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.actions.reset_hidden_item_prices'}",
"split_by_month": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.actions.split_by_month'}"
},
"error_title": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.error_title'}",
"merge_requires_multiple_text": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.merge_requires_multiple_text'}",
"merge_requires_multiple_title": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.merge_requires_multiple_title'}",
"merge_target_title": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.merge_target_title'}",
"preview": {
"affected_examples": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.affected_examples'}",
"blocked_title": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.blocked_title'}",
"blockers": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.blockers'}",
"changed": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.changed'}",
"collection_status_line": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.collection_status_line'}",
"collections": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.collections'}",
"confirm_button": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.confirm_button'}",
"confirmation_label": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.confirmation_label'}",
"confirmation_mismatch": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.confirmation_mismatch'}",
"merge_target": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.merge_target'}",
"no_changes_title": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.no_changes_title'}",
"order_item_line": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.order_item_line'}",
"order_move_line": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.order_move_line'}",
"requires_confirmation": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.requires_confirmation'}",
"skipped": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.skipped'}",
"title": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.preview.title'}"
},
"success_text": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.success_text'}",
"success_title": "@:{'phrases.compat.invoicing_period.invoice_collection_actions.success_title'}"
}
}
}
@@ -0,0 +1,39 @@
{
"compat": {
"invoicing_period": {
"invoice_collection_actions": {
"actions": {
"merge_collections": "Slå sammen",
"queue_economic": "Fakturer valgte",
"remove_customer_rule_violations": "Fjern regelbrudd",
"reset_hidden_item_prices": "Tilbakestill skjulte priser",
"split_by_month": "Del etter måned"
},
"error_title": "Handlingen mislyktes",
"merge_requires_multiple_text": "Velg minst to fakturasamlinger for å slå dem sammen.",
"merge_requires_multiple_title": "Velg flere fakturasamlinger",
"merge_target_title": "Velg målfakturasamling",
"preview": {
"affected_examples": "Eksempler på endringer",
"blocked_title": "Handlingen er blokkert",
"blockers": "Blokkeringer",
"changed": "Endringer: {count}",
"collection_status_line": "Fakturasamling #{collection}: {status}",
"collections": "Fakturasamlinger: {count}",
"confirm_button": "Utfør handling",
"confirmation_label": "Skriv {phrase} for å bekrefte",
"confirmation_mismatch": "Skriv nøyaktig {phrase} for å fortsette.",
"merge_target": "Mål: fakturasamling #{id}",
"no_changes_title": "Ingen endringer",
"order_item_line": "Fakturasamling #{collection}, ordre #{order}: {product}",
"order_move_line": "Ordre #{order}: #{source} til #{target}",
"requires_confirmation": "Gå gjennom forhåndsvisningen. Ingen endringer utføres før du skriver {phrase}.",
"skipped": "Hoppet over: {count}",
"title": "Forhåndsvis {action}"
},
"success_text": "Utførte {count} endringer.",
"success_title": "Handling fullført"
}
}
}
}
@@ -0,0 +1,39 @@
{
"compat": {
"invoicing_period": {
"invoice_collection_actions": {
"actions": {
"merge_collections": "Slå ihop",
"queue_economic": "Fakturera valda",
"remove_customer_rule_violations": "Ta bort regelbrott",
"reset_hidden_item_prices": "Återställ dolda priser",
"split_by_month": "Dela efter månad"
},
"error_title": "Åtgärden misslyckades",
"merge_requires_multiple_text": "Välj minst två fakturasamlingar för att slå ihop dem.",
"merge_requires_multiple_title": "Välj flera fakturasamlingar",
"merge_target_title": "Välj målfakturasamling",
"preview": {
"affected_examples": "Exempel på ändringar",
"blocked_title": "Åtgärden är blockerad",
"blockers": "Blockeringar",
"changed": "Ändringar: {count}",
"collection_status_line": "Fakturasamling #{collection}: {status}",
"collections": "Fakturasamlingar: {count}",
"confirm_button": "Utför åtgärd",
"confirmation_label": "Skriv {phrase} för att bekräfta",
"confirmation_mismatch": "Skriv exakt {phrase} för att fortsätta.",
"merge_target": "Mål: fakturasamling #{id}",
"no_changes_title": "Inga ändringar",
"order_item_line": "Fakturasamling #{collection}, order #{order}: {product}",
"order_move_line": "Order #{order}: #{source} till #{target}",
"requires_confirmation": "Granska förhandsvisningen. Inga ändringar görs innan du skriver {phrase}.",
"skipped": "Hoppade över: {count}",
"title": "Förhandsvisa {action}"
},
"success_text": "Utförde {count} ändringar.",
"success_title": "Åtgärd slutförd"
}
}
}
}