[pinia] Implemented and migrated balance
* Fixed revert of transaction if Conflic occures
This commit is contained in:
parent
4a7ed50281
commit
fd45a46c01
|
@ -1,10 +1,6 @@
|
|||
<template>
|
||||
<q-card>
|
||||
<BalanceHeader
|
||||
:show-selector="showSelector"
|
||||
@update:user="userUpdated"
|
||||
@open-history="openHistory"
|
||||
/>
|
||||
<BalanceHeader v-model="user" :show-selector="showSelector" @open-history="openHistory" />
|
||||
<q-separator />
|
||||
|
||||
<q-card-section v-if="shortCuts" class="row q-col-gutter-md">
|
||||
|
@ -63,53 +59,39 @@
|
|||
<script lang="ts">
|
||||
import { computed, ref, defineComponent, onBeforeMount } from 'vue';
|
||||
import { hasPermission } from 'src/utils/permission';
|
||||
import { Store, useStore, mapGetters } from 'vuex';
|
||||
import BalanceHeader from '../components/BalanceHeader.vue';
|
||||
import PERMISSIONS from '../permissions';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { useBalanceStore } from '../store';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BalanceAdd',
|
||||
components: { BalanceHeader },
|
||||
emits: { 'open-history': () => true },
|
||||
setup(_, { emit }) {
|
||||
const store = useBalanceStore();
|
||||
const mainStore = useMainStore();
|
||||
|
||||
onBeforeMount(() => {
|
||||
void store.dispatch('balance/getShortcuts');
|
||||
if ((<FG.Transaction[]>balanceGatters.transactions())?.length == 0)
|
||||
// No transaction, load at most six since yesterday
|
||||
void store.dispatch('balance/getTransactions', {
|
||||
filter: { limit: 6, from: new Date(new Date().setDate(new Date().getDate() - 1)) },
|
||||
});
|
||||
void store.getShortcuts();
|
||||
});
|
||||
//const store = <Store<StateInterfaceBalance>>root.$store;
|
||||
const store = useStore<Store<StateInterface>>();
|
||||
const userGetters = mapGetters('users', ['currentUser', 'roles', 'users']);
|
||||
const balanceGatters = mapGetters('balance', ['balances', 'transactions', 'shortcuts']);
|
||||
|
||||
const amount = ref<number>(0);
|
||||
const showAddShortcut = ref(false);
|
||||
const user = ref(<FG.User>userGetters.currentUser());
|
||||
//const shortCuts = ref(balanceState.shortcuts);
|
||||
const shortCuts = computed(() => <number[]>balanceGatters.shortcuts());
|
||||
const user = ref(mainStore.currentUser);
|
||||
const shortCuts = computed(() => store.shortcuts);
|
||||
|
||||
const canAddCredit = computed(() => hasPermission(PERMISSIONS.CREDIT));
|
||||
const showSelector = computed(
|
||||
() => hasPermission(PERMISSIONS.DEBIT) || hasPermission(PERMISSIONS.CREDIT)
|
||||
);
|
||||
const canAddCredit = hasPermission(PERMISSIONS.CREDIT);
|
||||
const showSelector = hasPermission(PERMISSIONS.DEBIT) || hasPermission(PERMISSIONS.CREDIT);
|
||||
|
||||
function addShortcut() {
|
||||
if (amount.value != 0) void store.dispatch('balance/addShortcut', amount.value * -1);
|
||||
if (amount.value != 0) void store.createShortcut(amount.value * -1);
|
||||
}
|
||||
function removeShortcut(shortcut: number) {
|
||||
void store.dispatch('balance/removeShortcut', shortcut);
|
||||
void store.removeShortcut(shortcut);
|
||||
}
|
||||
function userUpdated(selectedUser: FG.User) {
|
||||
user.value = selectedUser;
|
||||
}
|
||||
function changeBalance(amount: number) {
|
||||
store
|
||||
.dispatch('balance/changeBalance', { amount: amount, user: user.value?.userid })
|
||||
.catch((err) => console.log(err));
|
||||
async function changeBalance(amount: number) {
|
||||
await store.changeBalance(amount, user.value);
|
||||
}
|
||||
|
||||
function openHistory() {
|
||||
|
@ -126,7 +108,6 @@ export default defineComponent({
|
|||
amount,
|
||||
showSelector,
|
||||
shortCuts,
|
||||
userUpdated,
|
||||
openHistory,
|
||||
};
|
||||
},
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
<template>
|
||||
<q-card-section class="fit row justify-left content-center items-center q-col-gutter-sm">
|
||||
<div class="text-h6 col-5">
|
||||
Aktueller Stand: {{ balance.balance.toFixed(2) }} €
|
||||
<q-badge v-if="isLocked" color="negative" align="top"> gesperrt </q-badge>
|
||||
<div class="col-5">
|
||||
<div v-if="balance" class="text-h6">
|
||||
Aktueller Stand: {{ balance.balance.toFixed(2) }} €
|
||||
<q-badge v-if="isLocked" color="negative" align="top"> gesperrt </q-badge>
|
||||
</div>
|
||||
<q-spinner v-else color="primary" size="3em" />
|
||||
</div>
|
||||
<div v-if="showSelector" class="col-6">
|
||||
<UserSelector :user="user" @update:user="userUpdated" />
|
||||
<UserSelector v-model="user" />
|
||||
</div>
|
||||
<div class="col-1 justify-end">
|
||||
<q-btn round flat icon="mdi-format-list-checks" @click="openHistory" />
|
||||
|
@ -14,46 +17,50 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref, computed, defineComponent, onBeforeMount } from 'vue';
|
||||
import { computed, defineComponent, onBeforeMount, PropType } from 'vue';
|
||||
import UserSelector from 'src/plugins/user/components/UserSelector.vue';
|
||||
import { StateInterfaceBalance, UserBalance } from '../store/balance';
|
||||
import { useStore, mapGetters } from 'vuex';
|
||||
import { useBalanceStore } from '../store';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BalanceHeader',
|
||||
components: { UserSelector },
|
||||
props: { showSelector: Boolean },
|
||||
emits: { 'update:user': (u: FG.User) => !!u, 'open-history': () => true },
|
||||
setup(_, { emit }) {
|
||||
onBeforeMount(() => void store.dispatch('balance/getBalance'));
|
||||
const store = useStore<StateInterfaceBalance>();
|
||||
const userGetters = mapGetters('users', ['currentUser']);
|
||||
const balanceGetters = mapGetters('balance', ['balances']);
|
||||
const user = ref(<FG.User>userGetters.currentUser());
|
||||
const balance = computed(() => {
|
||||
return (
|
||||
(<Map<string, UserBalance>>balanceGetters.balances()).get(user.value.userid) || {
|
||||
balance: 0,
|
||||
limit: null,
|
||||
}
|
||||
);
|
||||
});
|
||||
props: {
|
||||
showSelector: Boolean,
|
||||
modelValue: {
|
||||
required: true,
|
||||
type: Object as PropType<FG.User>,
|
||||
},
|
||||
},
|
||||
emits: { 'update:modelValue': (u: FG.User) => !!u, 'open-history': () => true },
|
||||
setup(props, { emit }) {
|
||||
const store = useBalanceStore();
|
||||
const mainStore = useMainStore();
|
||||
|
||||
const isLocked = computed(
|
||||
() => balance.value.limit !== null && balance.value.balance >= balance.value.limit
|
||||
onBeforeMount(() => void store.getBalance(mainStore.currentUser));
|
||||
|
||||
const balance = computed(() =>
|
||||
store.balances.find((x) => x.userid === props.modelValue.userid)
|
||||
);
|
||||
|
||||
function userUpdated(selectedUser: FG.User) {
|
||||
void store.dispatch('balance/getBalance', selectedUser);
|
||||
user.value = selectedUser;
|
||||
emit('update:user', selectedUser);
|
||||
}
|
||||
const isLocked = computed(
|
||||
() =>
|
||||
balance.value === undefined ||
|
||||
(balance.value.limit !== undefined && balance.value.balance <= balance.value.limit)
|
||||
);
|
||||
const user = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (x: FG.User) => {
|
||||
void store.getBalance(x);
|
||||
emit('update:modelValue', x);
|
||||
},
|
||||
});
|
||||
|
||||
function openHistory() {
|
||||
emit('open-history');
|
||||
}
|
||||
|
||||
return { user, balance, isLocked, userUpdated, openHistory };
|
||||
return { user, balance, isLocked, openHistory };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
<template>
|
||||
<q-card>
|
||||
<BalanceHeader
|
||||
:show-selector="showSelector"
|
||||
@update:user="senderUpdated"
|
||||
@open-history="openHistory"
|
||||
/>
|
||||
<BalanceHeader v-model="sender" :show-selector="showSelector" @open-history="openHistory" />
|
||||
<q-separator />
|
||||
<q-card-section class="row q-col-gutter-md items-center">
|
||||
<div class="col-sm-4 col-xs-12">
|
||||
<q-input v-model.number="amount" type="number" filled label="Betrag" step="0.1" min="0" />
|
||||
</div>
|
||||
<div class="col-sm-4 col-xs-6">
|
||||
<UserSelector :user="receiver" label="Empfänger" @update:user="receiverUpdated" />
|
||||
<UserSelector v-model="receiver" label="Empfänger" />
|
||||
</div>
|
||||
<div class="col-sm-4 col-xs-6">
|
||||
<q-btn
|
||||
|
@ -29,22 +25,22 @@
|
|||
<script lang="ts">
|
||||
import { computed, ref, defineComponent } from 'vue';
|
||||
import { hasPermission } from 'src/utils/permission';
|
||||
import { mapGetters, Store, useStore } from 'vuex';
|
||||
import UserSelector from 'src/plugins/user/components/UserSelector.vue';
|
||||
import BalanceHeader from '../components/BalanceHeader.vue';
|
||||
import PERMISSIONS from '../permissions';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { useBalanceStore } from '../store';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BalanceTransfer',
|
||||
components: { BalanceHeader, UserSelector },
|
||||
emits: { 'open-history': () => true },
|
||||
setup(_, { emit }) {
|
||||
const store = useStore<Store<StateInterface>>();
|
||||
const userGetters = mapGetters('users', ['currentUser']);
|
||||
const store = useBalanceStore();
|
||||
const mainStore = useMainStore();
|
||||
|
||||
const showSelector = computed(() => hasPermission(PERMISSIONS.SEND_OTHER));
|
||||
const sender = ref(<FG.User>userGetters.currentUser());
|
||||
const sender = ref<FG.User | undefined>(mainStore.currentUser);
|
||||
const receiver = ref<FG.User | undefined>(undefined);
|
||||
const amount = ref<number>(0);
|
||||
|
||||
|
@ -57,22 +53,8 @@ export default defineComponent({
|
|||
);
|
||||
});
|
||||
|
||||
function senderUpdated(selectedUser: FG.User) {
|
||||
console.log(selectedUser);
|
||||
sender.value = selectedUser;
|
||||
}
|
||||
function receiverUpdated(selectedUser: FG.User) {
|
||||
receiver.value = selectedUser;
|
||||
}
|
||||
|
||||
function sendAmount() {
|
||||
store
|
||||
.dispatch('balance/changeBalance', {
|
||||
amount: amount.value,
|
||||
sender: sender.value?.userid,
|
||||
user: receiver.value?.userid,
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
async function sendAmount() {
|
||||
if (receiver.value) await store.changeBalance(amount.value, receiver.value, sender.value);
|
||||
}
|
||||
|
||||
function openHistory() {
|
||||
|
@ -85,8 +67,6 @@ export default defineComponent({
|
|||
amount,
|
||||
sendAmount,
|
||||
showSelector,
|
||||
senderUpdated,
|
||||
receiverUpdated,
|
||||
sendDisabled,
|
||||
openHistory,
|
||||
};
|
||||
|
|
|
@ -33,8 +33,9 @@
|
|||
import { ref, computed, defineComponent, onUnmounted, onMounted, PropType } from 'vue';
|
||||
import { hasPermission } from 'src/utils/permission';
|
||||
import { formatDateTime } from 'src/utils/datetime';
|
||||
import { mapGetters, Store, useStore } from 'vuex';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { useUserStore } from 'src/plugins/user/store';
|
||||
import { useBalanceStore } from '../store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Transaction',
|
||||
|
@ -46,33 +47,29 @@ export default defineComponent({
|
|||
},
|
||||
emits: { 'update:transaction': (t: FG.Transaction) => !!t },
|
||||
setup(props, { emit }) {
|
||||
const mainStore = useMainStore();
|
||||
const userStore = useUserStore();
|
||||
const balanceStore = useBalanceStore();
|
||||
const now = ref(Date.now());
|
||||
const ival = setInterval(() => (now.value = Date.now()), 1000);
|
||||
const store = useStore<Store<StateInterface>>();
|
||||
const userGetters = mapGetters('users', ['currentUser']);
|
||||
const text = ref('');
|
||||
|
||||
onUnmounted(() => clearInterval(ival));
|
||||
onMounted(() => refreshText());
|
||||
|
||||
const isNegative = () =>
|
||||
props.transaction.sender_id === (<FG.User>userGetters.currentUser())?.userid;
|
||||
const isNegative = () => props.transaction.sender_id === mainStore.currentUser.userid;
|
||||
|
||||
const refreshText = async () => {
|
||||
if (isNegative()) {
|
||||
text.value = 'Anschreiben';
|
||||
if (props.transaction.receiver_id !== null) {
|
||||
const user = <FG.User>await store.dispatch('user/getUser', {
|
||||
userid: props.transaction.receiver_id,
|
||||
});
|
||||
if (props.transaction.receiver_id) {
|
||||
const user = <FG.User>await userStore.getUser(props.transaction.receiver_id);
|
||||
text.value = `Gesendet an ${user.display_name}`;
|
||||
}
|
||||
} else {
|
||||
text.value = 'Gutschrift';
|
||||
if (props.transaction.sender_id !== null) {
|
||||
const user = <FG.User>await store.dispatch('user/getUser', {
|
||||
userid: props.transaction.sender_id,
|
||||
});
|
||||
if (props.transaction.sender_id) {
|
||||
const user = <FG.User>await userStore.getUser(props.transaction.sender_id);
|
||||
text.value = `Bekommen von ${user.display_name}`;
|
||||
}
|
||||
}
|
||||
|
@ -86,18 +83,15 @@ export default defineComponent({
|
|||
() =>
|
||||
!isReversed.value &&
|
||||
(hasPermission('balance_reversal') ||
|
||||
(props.transaction.sender_id === (<FG.User>userGetters.currentUser())?.userid &&
|
||||
(props.transaction.sender_id === mainStore.currentUser.userid &&
|
||||
now.value - props.transaction.time.getTime() < 10000))
|
||||
);
|
||||
|
||||
function reverse() {
|
||||
if (canReverse.value)
|
||||
store
|
||||
.dispatch('balance/revert', props.transaction)
|
||||
.then(() => {
|
||||
emit('update:transaction', props.transaction);
|
||||
})
|
||||
.catch((error) => console.log(error));
|
||||
void balanceStore.revert(props.transaction).then(() => {
|
||||
emit('update:transaction', props.transaction);
|
||||
});
|
||||
}
|
||||
|
||||
const timeStr = computed(() => {
|
||||
|
|
|
@ -7,30 +7,21 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useMainStore } from 'src/store';
|
||||
import { useBalanceStore } from '../store';
|
||||
import { computed, defineComponent, onBeforeMount } from 'vue';
|
||||
import { UserBalance } from 'src/plugins/balance/store/balance';
|
||||
import { mapGetters, useStore } from 'vuex';
|
||||
import { StateInterface } from 'src/store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BalanceWidget',
|
||||
setup() {
|
||||
const store = useStore<StateInterface>();
|
||||
const balanceGetters = mapGetters('balance', ['balances']);
|
||||
const userGetters = mapGetters('users', ['currentUser']);
|
||||
const store = useBalanceStore();
|
||||
|
||||
onBeforeMount(() => {
|
||||
store.dispatch('balance/getBalance').catch((err) => {
|
||||
console.warn(err);
|
||||
});
|
||||
const mainStore = useMainStore();
|
||||
void store.getBalance(mainStore.currentUser);
|
||||
});
|
||||
|
||||
const balance = computed(
|
||||
() =>
|
||||
(<Map<string, UserBalance>>balanceGetters.balances()).get(
|
||||
(<FG.User>userGetters.currentUser()).userid
|
||||
)?.balance || NaN
|
||||
);
|
||||
const balance = computed(() => store.balance?.balance || NaN);
|
||||
|
||||
return { balance };
|
||||
},
|
||||
|
|
|
@ -14,21 +14,16 @@
|
|||
// TODO: Fill usefull data
|
||||
|
||||
import { ref, defineComponent, onMounted } from 'vue';
|
||||
import { BalancesResponse } from '../store/balance';
|
||||
import { useStore } from 'vuex';
|
||||
import { useBalanceStore } from '../store';
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'PageName'
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const store = useBalanceStore();
|
||||
|
||||
onMounted(
|
||||
() =>
|
||||
void store
|
||||
.dispatch('balance/getBalances')
|
||||
.then((balances: Array<BalancesResponse>) => rows.value.push(...balances))
|
||||
);
|
||||
onMounted(() => void store.getBalances().then((balances) => rows.value.push(...balances)));
|
||||
|
||||
const rows = ref(new Array<BalancesResponse>());
|
||||
const rows = ref(store.balances);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
|
|
|
@ -67,29 +67,30 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, onMounted } from 'vue';
|
||||
import { mapGetters, Store, useStore } from 'vuex';
|
||||
import { hasSomePermissions } from 'src/utils/permission';
|
||||
import PERMISSIONS from '../permissions';
|
||||
import BalanceAdd from '../components/BalanceAdd.vue';
|
||||
import BalanceTransfer from '../components/BalanceTransfer.vue';
|
||||
import Transaction from '../components/Transaction.vue';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { useBalanceStore } from '../store';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BalanceManage',
|
||||
components: { BalanceAdd, BalanceTransfer, Transaction },
|
||||
setup() {
|
||||
//const store = <Store<StateInterfaceBalance>>root.$store;
|
||||
const store = useStore<Store<StateInterface>>();
|
||||
const balanceGetters = mapGetters('balance', ['balances', 'transactions']);
|
||||
const balanceStore = useBalanceStore();
|
||||
const mainStore = useMainStore();
|
||||
|
||||
const now = new Date();
|
||||
onMounted(() => {
|
||||
void store.dispatch('balance/getTransactions', {
|
||||
filter: { from: new Date(now.getFullYear(), now.getMonth(), now.getDate()) },
|
||||
void balanceStore.getTransactions(mainStore.currentUser, {
|
||||
from: new Date(now.getFullYear(), now.getMonth(), now.getDate()),
|
||||
});
|
||||
});
|
||||
|
||||
const transactions = computed(() => {
|
||||
return (<FG.Transaction[]>balanceGetters.transactions())
|
||||
return balanceStore.transactions
|
||||
.filter((t) => t.original_id == undefined)
|
||||
.filter((t) => t.time > new Date(now.getFullYear(), now.getMonth(), now.getDate()))
|
||||
.sort((a, b) => (a.time >= b.time ? -1 : 1));
|
||||
|
|
|
@ -33,22 +33,21 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, ref } from 'vue';
|
||||
import { TransactionsResponse, UserBalance } from '../store/balance';
|
||||
import { mapGetters, Store, useStore } from 'vuex';
|
||||
import { formatDateTime } from 'src/utils/datetime';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { useBalanceStore } from '../store';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { useUserStore } from 'src/plugins/user/store';
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'PageName'
|
||||
setup() {
|
||||
//const store = <Store<StateInterfaceBalance>>root.$store;
|
||||
const store = useStore<Store<StateInterface>>();
|
||||
const userGetters = mapGetters('users', ['currentUser', 'users']);
|
||||
const balanceGetters = mapGetters('balace', ['balances', 'transactions']);
|
||||
const store = useBalanceStore();
|
||||
const mainStore = useMainStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
onMounted(() => {
|
||||
void store.dispatch('balance/getBalance');
|
||||
void store.dispatch('user/getUsers').then(() =>
|
||||
void store.getBalance(mainStore.currentUser);
|
||||
void userStore.getUsers().then(() =>
|
||||
onRequest({
|
||||
pagination: pagination.value,
|
||||
filter: undefined,
|
||||
|
@ -75,7 +74,7 @@ export default defineComponent({
|
|||
rowsNumber: number;
|
||||
}
|
||||
|
||||
function onRequest(props: { pagination: PaginationInterface; filter?: string }) {
|
||||
async function onRequest(props: { pagination: PaginationInterface; filter?: string }) {
|
||||
const { page, rowsPerPage, sortBy, descending } = props.pagination;
|
||||
|
||||
loading.value = true;
|
||||
|
@ -83,34 +82,28 @@ export default defineComponent({
|
|||
const fetchCount = rowsPerPage === 0 ? pagination.value.rowsNumber : rowsPerPage;
|
||||
// calculate starting row of data
|
||||
const startRow = (page - 1) * rowsPerPage;
|
||||
store
|
||||
.dispatch('balance/getTransactions', {
|
||||
filter: {
|
||||
offset: startRow,
|
||||
limit: fetchCount,
|
||||
showCancelled: showCancelled.value,
|
||||
showReversals: false,
|
||||
},
|
||||
})
|
||||
.then((result: TransactionsResponse) => {
|
||||
// clear out existing data and add new
|
||||
data.value.splice(0, data.value.length, ...result.transactions);
|
||||
// don't forget to update local pagination object
|
||||
pagination.value.page = page;
|
||||
pagination.value.rowsPerPage = rowsPerPage;
|
||||
pagination.value.sortBy = sortBy;
|
||||
pagination.value.descending = descending;
|
||||
if (result.count) pagination.value.rowsNumber = result.count;
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
try {
|
||||
const result = await store.getTransactions(mainStore.currentUser, {
|
||||
offset: startRow,
|
||||
limit: fetchCount,
|
||||
showCancelled: showCancelled.value,
|
||||
showReversals: false,
|
||||
});
|
||||
// clear out existing data and add new
|
||||
data.value.splice(0, data.value.length, ...result.transactions);
|
||||
// don't forget to update local pagination object
|
||||
pagination.value.page = page;
|
||||
pagination.value.rowsPerPage = rowsPerPage;
|
||||
pagination.value.sortBy = sortBy;
|
||||
pagination.value.descending = descending;
|
||||
if (result.count) pagination.value.rowsNumber = result.count;
|
||||
} catch (error) {
|
||||
// ...
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
const balance = computed(
|
||||
() =>
|
||||
(<Map<string, UserBalance>>balanceGetters.balances()).get(
|
||||
(<FG.User>userGetters.currentUser()).userid
|
||||
)?.balance || NaN
|
||||
);
|
||||
const balance = computed(() => store.balance?.balance || NaN);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
|
@ -144,8 +137,7 @@ export default defineComponent({
|
|||
else {
|
||||
if (row.receiver_id == null) return 'Angeschrieben';
|
||||
else {
|
||||
if (row.receiver_id === (<FG.User>userGetters.currentUser())?.userid)
|
||||
return 'Bekommen von X';
|
||||
if (row.receiver_id === mainStore.currentUser.userid) return 'Bekommen von X';
|
||||
else return 'Gesendet an X';
|
||||
}
|
||||
}
|
||||
|
@ -162,7 +154,7 @@ export default defineComponent({
|
|||
label: 'Benutzer',
|
||||
field: 'author_id',
|
||||
format: (val: string) => {
|
||||
const user = (<FG.User[]>userGetters.users()).filter((x) => x.userid == val);
|
||||
const user = userStore.users.filter((x) => x.userid == val);
|
||||
if (user.length > 0) return user[0].display_name;
|
||||
else return val;
|
||||
},
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
import { api } from 'src/boot/axios';
|
||||
|
||||
interface BalanceResponse {
|
||||
balance: number;
|
||||
credit: number;
|
||||
debit: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface BalancesResponse extends BalanceResponse {
|
||||
userid: string;
|
||||
}
|
||||
|
||||
export interface TransactionsResponse {
|
||||
transactions: Array<FG.Transaction>;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
import { defineStore } from 'pinia';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { Notify } from 'quasar';
|
||||
|
||||
function fixTransaction(t: FG.Transaction) {
|
||||
t.time = new Date(t.time);
|
||||
}
|
||||
|
||||
export const useBalanceStore = defineStore({
|
||||
id: 'balance',
|
||||
|
||||
state: () => ({
|
||||
balances: [] as BalancesResponse[],
|
||||
shortcuts: [] as number[],
|
||||
transactions: [] as FG.Transaction[],
|
||||
_balances_dirty: 0,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
balance() {
|
||||
const mainStore = useMainStore();
|
||||
return this.balances.find((v) => v.userid === mainStore.user?.userid);
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
async createShortcut(shortcut: number) {
|
||||
const mainStore = useMainStore();
|
||||
this.shortcuts.push(shortcut);
|
||||
this.shortcuts.sort((a, b) => a - b);
|
||||
await api.put(`/users/${mainStore.currentUser.userid}/balance/shortcuts`, this.shortcuts);
|
||||
},
|
||||
|
||||
async removeShortcut(shortcut: number) {
|
||||
const mainStore = useMainStore();
|
||||
this.shortcuts = this.shortcuts.filter((value: number) => value !== shortcut);
|
||||
this.shortcuts.sort((a, b) => a - b);
|
||||
await api.put(`/users/${mainStore.currentUser.userid}/balance/shortcuts`, this.shortcuts);
|
||||
},
|
||||
|
||||
async getShortcuts(force = false) {
|
||||
if (force || this.shortcuts.length == 0) {
|
||||
const mainStore = useMainStore();
|
||||
const { data } = await api.get<number[]>(
|
||||
`/users/${mainStore.currentUser.userid}/balance/shortcuts`
|
||||
);
|
||||
this.shortcuts = data;
|
||||
}
|
||||
},
|
||||
|
||||
async getBalance(user: FG.User) {
|
||||
const { data } = await api.get<BalanceResponse>(`/users/${user.userid}/balance`);
|
||||
const idx = this.balances.findIndex((x) => x.userid === user.userid);
|
||||
if (idx == -1) this.balances.push(Object.assign(data, { userid: user.userid }));
|
||||
else this.balances[idx] = Object.assign(data, { userid: user.userid });
|
||||
return data;
|
||||
},
|
||||
|
||||
async getBalances(force = false) {
|
||||
if (
|
||||
force ||
|
||||
this.balances.length == 0 ||
|
||||
new Date().getTime() - this._balances_dirty > 60000
|
||||
) {
|
||||
const { data } = await api.get<BalancesResponse[]>('/balance');
|
||||
this.balances = data;
|
||||
}
|
||||
return this.balances;
|
||||
},
|
||||
|
||||
async changeBalance(amount: number, user: FG.User, sender: FG.User | undefined = undefined) {
|
||||
const mainStore = useMainStore();
|
||||
try {
|
||||
const { data } = await api.put<FG.Transaction>(`/users/${user.userid}/balance`, {
|
||||
amount,
|
||||
user: user.userid,
|
||||
sender: sender?.userid,
|
||||
});
|
||||
fixTransaction(data);
|
||||
if (
|
||||
user.userid === mainStore.currentUser.userid ||
|
||||
sender?.userid === mainStore.currentUser.userid
|
||||
)
|
||||
this.transactions.push(data);
|
||||
const f = this.balances.find((x) => x.userid === user.userid);
|
||||
if (f) f.balance += amount;
|
||||
if (sender) {
|
||||
const f = this.balances.find((x) => x.userid === sender.userid);
|
||||
if (f) f.balance += -1 * amount;
|
||||
}
|
||||
this._balances_dirty = 0;
|
||||
return data;
|
||||
} catch ({ response }) {
|
||||
// Maybe Balance changed
|
||||
if (response && (<AxiosResponse>response).status == 409) {
|
||||
Notify.create({
|
||||
type: 'negative',
|
||||
group: false,
|
||||
message: 'Das Limit wurde überschritten!',
|
||||
timeout: 10000,
|
||||
progress: true,
|
||||
actions: [{ icon: 'mdi-close', color: 'white' }],
|
||||
});
|
||||
//void this.getTransactions(true);
|
||||
void this.getBalance(sender ? sender : user);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async getTransactions(
|
||||
user: FG.User,
|
||||
filter:
|
||||
| {
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
from?: Date;
|
||||
to?: Date;
|
||||
showReversals?: boolean;
|
||||
showCancelled?: boolean;
|
||||
}
|
||||
| undefined = undefined
|
||||
) {
|
||||
if (!filter) filter = { limit: 10 };
|
||||
const { data } = await api.get<TransactionsResponse>(
|
||||
`/users/${user.userid}/balance/transactions`,
|
||||
{ params: filter }
|
||||
);
|
||||
data.transactions.forEach((t) => fixTransaction(t));
|
||||
if (data.transactions) this.transactions.push(...data.transactions);
|
||||
return data;
|
||||
},
|
||||
|
||||
async revert(transaction: FG.Transaction) {
|
||||
try {
|
||||
const { data } = await api.delete<FG.Transaction>(`/balance/${transaction.id}`);
|
||||
fixTransaction(data);
|
||||
const f = this.transactions.find((x) => x.id === transaction.id);
|
||||
if (f) f.reversal_id = data.id;
|
||||
this.transactions.push(data);
|
||||
console.log(data);
|
||||
} catch (error) {
|
||||
// ...
|
||||
}
|
||||
this._balances_dirty = 0;
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,66 +0,0 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { api } from 'src/boot/axios';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
interface BalanceResponse {
|
||||
balance: number;
|
||||
credit: number;
|
||||
debit: number;
|
||||
}
|
||||
|
||||
export interface BalancesResponse extends BalanceResponse {
|
||||
userid: string;
|
||||
}
|
||||
|
||||
export interface TransactionsResponse {
|
||||
transactions: Array<FG.Transaction>;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
function fixTransaction(t: FG.Transaction) {
|
||||
t.time = new Date(t.time);
|
||||
}
|
||||
|
||||
export const balanceStore = defineStore({
|
||||
id: 'balance',
|
||||
|
||||
state: () => ({
|
||||
balances: [] as BalancesResponse[],
|
||||
shortcuts: [] as number[],
|
||||
}),
|
||||
|
||||
getters: {
|
||||
balance() {
|
||||
const mainStore = useMainStore();
|
||||
return this.balances.find((v) => v.userid === mainStore.user?.userid);
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
async createShortcut(shortcut: number) {
|
||||
const mainStore = useMainStore();
|
||||
const sc = [...this.shortcuts, shortcut];
|
||||
sc.sort();
|
||||
await api.put(`/users/${mainStore.currentUser.userid}/balance/shortcuts`, sc);
|
||||
this.shortcuts = sc;
|
||||
},
|
||||
|
||||
async removeShortcut(shortcut: number) {
|
||||
const mainStore = useMainStore();
|
||||
const sc = this.shortcuts.filter((value: number) => value !== shortcut);
|
||||
await api.put(`/users/${mainStore.currentUser.userid}/balance/shortcuts`, sc);
|
||||
this.shortcuts = sc;
|
||||
},
|
||||
|
||||
async getShortcuts(force = false) {
|
||||
if (force || this.shortcuts.length == 0) {
|
||||
const mainStore = useMainStore();
|
||||
const { data } = await api.get<number[]>(
|
||||
`/users/${mainStore.currentUser.userid}/balance/shortcuts`
|
||||
);
|
||||
this.shortcuts = data;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
|
@ -33,7 +33,6 @@ export const useUserStore = defineStore({
|
|||
} catch (error) {
|
||||
if (!error || !('response' in error) || (<AxiosError>error).response?.status !== 404)
|
||||
throw error;
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return this.users[idx];
|
||||
|
|
Loading…
Reference in New Issue