Add collected order invoice management and improve edit logic
Introduce collected order invoice views, tables, and detailed navigation for superuser dashboards. Enhance `showEditOrderItemForm` to support an optional callback, streamlining post-submission actions. These changes improve invoice handling and editing workflows for better usability.
This commit is contained in:
@@ -236,7 +236,7 @@ loadOrder();
|
||||
icon="fas fa-edit"
|
||||
template="warning"
|
||||
:disabled="!SessionUser.hasPermission('edit_order_items')"
|
||||
@click="showEditOrderItemForm(orderItem.id, orderItem.product.name, orderItem.price, orderItem.notes, orderItem.reference, orderItem.quantity, editPossible).then(() => loadOrderItems())"
|
||||
@click="showEditOrderItemForm(orderItem.id, orderItem.product.name, orderItem.price, orderItem.notes, orderItem.reference, orderItem.quantity, editPossible, () => loadOrderItems())"
|
||||
/>
|
||||
</template>
|
||||
</ActionSettingsWheelButton>
|
||||
@@ -329,7 +329,7 @@ loadOrder();
|
||||
icon="fas fa-edit"
|
||||
template="warning"
|
||||
:disabled="!SessionUser.hasPermission('edit_order_items')"
|
||||
@click="showEditOrderItemForm(relatedItem.id, relatedItem.product.name, relatedItem.price, relatedItem.notes, relatedItem.reference, relatedItem.quantity, editPossible).then(() => loadOrderItems())"
|
||||
@click="showEditOrderItemForm(relatedItem.id, relatedItem.product.name, relatedItem.price, relatedItem.notes, relatedItem.reference, relatedItem.quantity, editPossible, () => loadOrderItems())"
|
||||
/>
|
||||
</template>
|
||||
</ActionSettingsWheelButton>
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<script setup>
|
||||
import EditableTableColumn from "@/components/displays/buttons/EditableTableColumn.vue";
|
||||
import {getCustomerName} from "@/components/shop/POSDepartmentProcess.vue";
|
||||
|
||||
defineProps(['objects']);
|
||||
import { ref } from 'vue';
|
||||
import { loadList } from "@/components/pagination/paginatedList.vue";
|
||||
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
||||
import ActionSettingsWheelButton from "@/components/displays/buttons/ActionSettingsWheelButton.vue";
|
||||
import ActionSettingsWheelItem from "@/components/displays/buttons/ActionSettingsWheelItem.vue";
|
||||
|
||||
const redirect = (path) => {
|
||||
window.location = path;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table class="table is-fullwidth is-hoverable is-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ SessionUser.objects.collectedOrderInvoices.columns.id.label }}</th>
|
||||
<th>{{ SessionUser.objects.collectedOrderInvoices.columns.customer_number.label }}</th>
|
||||
<th>{{ SessionUser.objects.collectedOrderInvoices.columns.name.label }}</th>
|
||||
<th>{{ SessionUser.objects.collectedOrderInvoices.columns.notes.label }}</th>
|
||||
<th>{{ SessionUser.objects.collectedOrderInvoices.columns.processor.label }}</th>
|
||||
<th>Transaktioner</th>
|
||||
<th>{{ SessionUser.objects.collectedOrderInvoices.columns.closed_at.label }}</th>
|
||||
<th>{{ SessionUser.objects.collectedOrderInvoices.columns.created_at.label }}</th>
|
||||
<th><!-- Actions --></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="object in objects" :key="object.id">
|
||||
<td>{{ object.id }}</td>
|
||||
<!-- Customer number -->
|
||||
<EditableTableColumn
|
||||
:object="object"
|
||||
:loadList="loadList"
|
||||
column="customer_id"
|
||||
/>
|
||||
<!-- Name -->
|
||||
<EditableTableColumn
|
||||
:object="object"
|
||||
:loadList="loadList"
|
||||
:editFunction="SessionUser.objects.collectedOrderInvoices.showEditObjectFieldForm"
|
||||
column="name"
|
||||
/>
|
||||
<!-- Notes -->
|
||||
<EditableTableColumn
|
||||
:object="object"
|
||||
:loadList="loadList"
|
||||
:editFunction="SessionUser.objects.collectedOrderInvoices.showEditObjectFieldForm"
|
||||
column="notes"
|
||||
/>
|
||||
<!-- Processor -->
|
||||
<EditableTableColumn
|
||||
:object="object"
|
||||
:loadList="loadList"
|
||||
:editFunction="SessionUser.objects.collectedOrderInvoices.showEditObjectFieldForm"
|
||||
column="processor"
|
||||
/>
|
||||
<!-- Transactions -->
|
||||
<EditableTableColumn
|
||||
:object="object"
|
||||
:loadList="loadList"
|
||||
column="orders"
|
||||
/>
|
||||
<!-- Closed at -->
|
||||
<EditableTableColumn
|
||||
:object="object"
|
||||
:loadList="loadList"
|
||||
column="closed_at"
|
||||
/>
|
||||
<!-- Created at -->
|
||||
<EditableTableColumn
|
||||
:object="object"
|
||||
:loadList="loadList"
|
||||
column="created_at"
|
||||
/>
|
||||
<!-- Actions -->
|
||||
<td>
|
||||
<ActionSettingsWheelButton>
|
||||
<template #actions>
|
||||
<ActionSettingsWheelItem
|
||||
icon="fas fa-eye"
|
||||
@click="redirect('/superuser/invoices/' + object.id)"
|
||||
label="Vis"
|
||||
/>
|
||||
</template>
|
||||
</ActionSettingsWheelButton>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- If the list is empty -->
|
||||
<tr v-if="objects.length === 0">
|
||||
<td colspan="9">
|
||||
Ingen transaktioner fundet
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Show a count of the total number of objects -->
|
||||
<tr>
|
||||
<td colspan="9">Viser {{ objects.length }} transaktioner i faktura kollektion</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -6,6 +6,8 @@ defineProps(['objects']);
|
||||
import { ref } from 'vue';
|
||||
import { loadList } from "@/components/pagination/paginatedList.vue";
|
||||
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
||||
import ActionSettingsWheelButton from "@/components/displays/buttons/ActionSettingsWheelButton.vue";
|
||||
import ActionSettingsWheelItem from "@/components/displays/buttons/ActionSettingsWheelItem.vue";
|
||||
|
||||
const redirect = (path) => {
|
||||
window.location = path;
|
||||
@@ -76,6 +78,18 @@ const redirect = (path) => {
|
||||
:loadList="loadList"
|
||||
column="created_at"
|
||||
/>
|
||||
<!-- Actions -->
|
||||
<td>
|
||||
<ActionSettingsWheelButton>
|
||||
<template #actions>
|
||||
<ActionSettingsWheelItem
|
||||
icon="fas fa-eye"
|
||||
@click="redirect('/superuser/invoices/' + object.id)"
|
||||
label="Vis"
|
||||
/>
|
||||
</template>
|
||||
</ActionSettingsWheelButton>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- If the list is empty -->
|
||||
<tr v-if="objects.length === 0">
|
||||
|
||||
@@ -5,7 +5,7 @@ import Swal from "sweetalert2";
|
||||
|
||||
//
|
||||
|
||||
export const showEditOrderItemForm = async (orderItemId, name, price, notes, reference, quantity, allowEdit) => {
|
||||
export const showEditOrderItemForm = async (orderItemId, name, price, notes, reference, quantity, allowEdit, afterSubmit = null) => {
|
||||
await Swal.fire({
|
||||
title: 'Edit Item',
|
||||
html: `
|
||||
@@ -53,6 +53,10 @@ export const showEditOrderItemForm = async (orderItemId, name, price, notes, ref
|
||||
.then(() => {
|
||||
// Close the modal
|
||||
Swal.close();
|
||||
// If afterSubmit is set, run it
|
||||
if (afterSubmit) {
|
||||
afterSubmit();
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
Swal.fire('Error', e.response.data.error ?? e.response, 'error');
|
||||
|
||||
@@ -144,7 +144,22 @@ export const CollectedOrderInvoices = {
|
||||
return ObjectsGlobal.get.object(CollectedOrderInvoices.meta.endpoint, id);
|
||||
}
|
||||
},
|
||||
functions: {},
|
||||
functions: {
|
||||
economic: {
|
||||
invoice: async (invoiceId) => {
|
||||
return authenticatedRequest('/collected-invoices/economic', 'POST', {
|
||||
id: parseInt(invoiceId)
|
||||
}).then((response) => {
|
||||
console.log(response);
|
||||
Swal.fire({
|
||||
title: 'Fakturer med E-conomic',
|
||||
text: 'Fakturaen er nu sendt til E-conomic',
|
||||
icon: 'success'
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Show the create object form
|
||||
* @param onAfterSubmit
|
||||
|
||||
@@ -69,6 +69,8 @@ import SuperUserRolesPermissions from "@/views/dashboards/superUserDashboard/rol
|
||||
import DepartmentStripeTerminalsReaders from "@/views/dashboards/superUserDashboard/department/stripe/DepartmentStripeTerminalsReaders.vue";
|
||||
import DepartmentStripeSetup from "@/views/dashboards/superUserDashboard/department/stripe/DepartmentStripeSetup.vue";
|
||||
import CollectedOrderInvoices from "@/views/dashboards/superUserDashboard/CollectedOrderInvoices.vue";
|
||||
import CollectedOrderInvoice
|
||||
from "@/views/dashboards/superUserDashboard/collectedOrderInvoice/collectedOrderInvoice.vue";
|
||||
|
||||
// Export the router as router
|
||||
export const router = createRouter({
|
||||
@@ -248,6 +250,12 @@ export const router = createRouter({
|
||||
component: CollectedOrderInvoices,
|
||||
meta: { middleware: superUserMiddleware }
|
||||
},
|
||||
{
|
||||
name: 'collectedorderinvoice',
|
||||
path: '/superuser/invoices/:collectedOrderInvoiceId',
|
||||
component: CollectedOrderInvoice,
|
||||
meta: { middleware: superUserMiddleware }
|
||||
},
|
||||
{
|
||||
name: 'orders',
|
||||
path: '/superuser/orders',
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
<script setup>
|
||||
import SuperUserDashboardNavigation from "@/views/dashboards/superUserDashboard/SuperUserDashboardNavigation.vue";
|
||||
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
|
||||
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
||||
import PageTitle from "@/components/global/PageTitle.vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { ref } from 'vue';
|
||||
import CollectedOrderInvoiceOrdersTable
|
||||
from "@/components/displays/superuser/tables/collectedOrderInvoiceOrdersTable.vue";
|
||||
import CollectedOrderInvoiceOverview
|
||||
from "@/views/dashboards/superUserDashboard/collectedOrderInvoice/displays/collectedOrderInvoiceOverview.vue";
|
||||
import CollectedOrderInvoiceManage
|
||||
from "@/views/dashboards/superUserDashboard/collectedOrderInvoice/displays/collectedOrderInvoiceManage.vue";
|
||||
|
||||
// Get the id from the URL
|
||||
const router = useRouter();
|
||||
const collectedOrderInvoiceId = router.currentRoute.value.params.collectedOrderInvoiceId;
|
||||
|
||||
// Define the reactive objects
|
||||
const orders = ref([]);
|
||||
const data = ref([]);
|
||||
|
||||
// Make the first letter uppercase
|
||||
const title = SessionUser.objects.collectedOrderInvoices.meta.labels.single;
|
||||
const firstLetter = title.charAt(0).toUpperCase();
|
||||
const restOfTitle = title.slice(1);
|
||||
const formattedTitle = firstLetter + restOfTitle;
|
||||
|
||||
// Get the collected order invoice
|
||||
const collectedOrderInvoice = ref(null);
|
||||
const getCollectedOrderInvoice = async () => {
|
||||
SessionUser.objects.collectedOrderInvoices.get.single(collectedOrderInvoiceId).then((response) => {
|
||||
const raw_data = response;
|
||||
console.log(raw_data);
|
||||
orders.value = raw_data.orders || [];
|
||||
collectedOrderInvoice.value = raw_data;
|
||||
});
|
||||
};
|
||||
|
||||
// Get the collected order invoice
|
||||
getCollectedOrderInvoice();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RestrictedPageWrapper :hasPermission="SessionUser.canAccessSuperUser()">
|
||||
<SuperUserDashboardNavigation />
|
||||
<PageTitle
|
||||
:title="formattedTitle + ' #' + collectedOrderInvoiceId"
|
||||
subtitle="Her kan du se en faktura i systemet"
|
||||
/>
|
||||
<!-- At A Glance -->
|
||||
<collected-order-invoice-overview
|
||||
v-bind:invoices="orders"
|
||||
v-bind:closed_at="collectedOrderInvoice.closed_at"
|
||||
:total="0"
|
||||
/>
|
||||
<CollectedOrderInvoiceManage
|
||||
:invoiceId="parseInt(collectedOrderInvoiceId)"
|
||||
v-bind:closed_at="collectedOrderInvoice.closed_at"
|
||||
/>
|
||||
<CollectedOrderInvoiceOrdersTable :objects="orders" />
|
||||
</RestrictedPageWrapper>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<script setup>
|
||||
import {ref, defineProps} from 'vue';
|
||||
import {SessionUser} from "@/components/session/token/SessionUser.vue";
|
||||
|
||||
const props = defineProps({
|
||||
invoiceId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
closed_at: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
v-if="!closed_at"
|
||||
class="button is-small is-primary"
|
||||
@click="SessionUser.objects.collectedOrderInvoices.functions.economic.invoice(invoiceId)"
|
||||
>
|
||||
<span class="icon">
|
||||
<i class="fas fa-file-invoice-dollar"></i>
|
||||
</span>
|
||||
<span>Send til E-conomic (Som faktura klar til bogføring)</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
<script setup>
|
||||
import {defineProps, ref} from 'vue';
|
||||
const props = defineProps({
|
||||
invoices: {
|
||||
type: Array,
|
||||
required: true,
|
||||
description: 'The transactions contained in the invoice collection'
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
required: true,
|
||||
description: 'The total amount of the invoices in the collection'
|
||||
},
|
||||
closed_at: {
|
||||
type: String,
|
||||
required: false,
|
||||
description: 'The date the invoice collection was closed'
|
||||
},
|
||||
});
|
||||
const column_width = 'is-3';
|
||||
const displays = [
|
||||
{
|
||||
title: 'Transaktioner',
|
||||
value: props.invoices.length,
|
||||
icon: 'fas fa-file-invoice-dollar',
|
||||
},
|
||||
{
|
||||
title: 'Total beløb',
|
||||
value: (props.total ? props.total.toFixed(2) : 0) + ' kr.',
|
||||
icon: 'fas fa-money-bill-wave',
|
||||
},
|
||||
{
|
||||
title: 'Arkiveret',
|
||||
value: props.closed_at ? props.closed_at : 'Nej',
|
||||
icon: 'fas fa-lock',
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<template v-for="display in displays">
|
||||
<div class="column" :class="column_width">
|
||||
<div class="card">
|
||||
<!-- Header -->
|
||||
<header class="card-header">
|
||||
<!-- Icon -->
|
||||
<a class="card-header-icon">
|
||||
<span class="icon">
|
||||
<i :class="display.icon"></i>
|
||||
</span>
|
||||
</a>
|
||||
<!-- Title -->
|
||||
<p class="card-header-title">{{ display.title }}</p>
|
||||
<!-- Dropdown icon -->
|
||||
<a class="card-header-icon">
|
||||
<span class="icon">
|
||||
<i class="fas fa-angle-down"></i>
|
||||
</span>
|
||||
</a>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<p class="title is-4">{{ display.value }}</p>
|
||||
<p class="subtitle is-6">{{ display.title }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user