277 lines
8.2 KiB
Vue
277 lines
8.2 KiB
Vue
<template>
|
|
<div v-if="transaction">
|
|
<h4 class="subtitle is-4">{{ transaction.date | fulldate }}</h4>
|
|
<nav class="breadcrumb" aria-label="breadcrumbs" v-if="account">
|
|
<ul>
|
|
<li>
|
|
<router-link
|
|
:to="{ name: 'account', params: { id: account._id }, hash: `#${transaction._id}` }"
|
|
>{{ account.name }}</router-link>
|
|
</li>
|
|
<li class="is-active" v-if="transaction.tag && transaction.tag !== noTag">
|
|
<a href="#" @click.prevent>{{ transactionTagLabel[transaction.tag].label }}</a>
|
|
</li>
|
|
<li class="is-active">
|
|
<a href="#" @click.prevent>{{ transaction.name }}</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
<div class="resume">
|
|
Dépense payée par
|
|
<span class="pay-by">{{ transaction.payBy }}</span>
|
|
pour
|
|
<span v-if="payForLabel.length > 1">{{ payForLabel.join(', ') }}</span>
|
|
<span v-else>{{ payForLabel[0] }}</span>
|
|
d'une somme de
|
|
<span
|
|
class="numeric"
|
|
>{{ transaction.amount | money(transaction.mainCurrency) }}</span>.
|
|
</div>
|
|
<div v-if="transaction.exchange" class="exchange">
|
|
<div v-if="currencies.length">
|
|
<hr />
|
|
<h2 class="subtitle is-2">Taux d'échange à date</h2>
|
|
<div class="columns is-centered">
|
|
<div class="column">
|
|
<table class="table is-fullwidth is-striped is-bordered">
|
|
<caption>
|
|
<span class="numeric">{{ transaction.amount | money(transaction.mainCurrency) }}</span>
|
|
</caption>
|
|
<tbody>
|
|
<tr v-for="(currency, k) in currencies" :key="k">
|
|
<td
|
|
class="numeric"
|
|
>{{ (transaction.amount * transaction.exchange.rates[currency.code]) | moneypad(currency) }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="column">
|
|
<table class="table is-fullwidth is-striped is-bordered">
|
|
<caption>
|
|
<span class="numeric">{{ 1 | money(transaction.mainCurrency) }}</span>
|
|
</caption>
|
|
<tbody>
|
|
<tr v-for="(currency, k) in currencies" :key="k">
|
|
<td
|
|
class="numeric"
|
|
>{{ ( transaction.exchange.rates[currency.code]) | moneypad(currency) }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="column">
|
|
<table class="table is-hoverable is-fullwidth is-striped is-bordered">
|
|
<caption>{{ $tc('transaction.money', currencies.length) }}</caption>
|
|
<tbody>
|
|
<tr v-for="(currency, k) in currencies" :key="k">
|
|
<td>{{ 1 | money(currency) }}</td>
|
|
<td
|
|
class="numeric"
|
|
>{{ (1 / transaction.exchange.rates[currency.code]) | moneypad(transaction.mainCurrency) }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else>
|
|
<online-view @online="retrieveExchange" />Le taux d'échange n'a pas pu être récupéré.
|
|
</div>
|
|
<div class="buttons is-centered" v-if="!account.archive">
|
|
<router-link
|
|
v-if="canModify"
|
|
tag="button"
|
|
class="button"
|
|
:to="{ name: 'transaction-update', params: { id } }"
|
|
>modifier</router-link>
|
|
<confirm-button class="is-danger" @confirm="removeTransaction">supprimer</confirm-button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Prop, Vue } from 'vue-property-decorator'
|
|
import { Getter } from 'vuex-class'
|
|
import TransactionType from '@/enums/TransactionType'
|
|
import bus, { SYNC } from '@/utils/bus-event'
|
|
import notif from '@/utils/notif'
|
|
import TransactionTag, { TransactionTagLabel } from '@/enums/TransactionTag'
|
|
import accountService from '@/services/AccountService'
|
|
import exchangeService from '@/services/ExchangeService'
|
|
import transactionService from '@/services/TransactionService'
|
|
import IAccount from '@/models/IAccount'
|
|
import ICurrency from '@/models/ICurrency'
|
|
import ITransaction from '@/models/ITransaction'
|
|
import IUser from '@/models/IUser'
|
|
import ISplit from '@/models/ISplit'
|
|
|
|
@Component({
|
|
components: {
|
|
'online-view': () => import('@/components/OnlineView.vue'),
|
|
'confirm-button': () => import('@/components/ConfirmButton.vue')
|
|
}
|
|
})
|
|
export default class TransactionItem extends Vue {
|
|
@Getter
|
|
public user!: IUser | null
|
|
@Prop({ type: String, required: true })
|
|
public id!: string
|
|
public transaction: ITransaction | null = null
|
|
public account: IAccount | null = null
|
|
public noTag: string = TransactionTag.None
|
|
public transactionTagLabel: typeof TransactionTagLabel = TransactionTagLabel
|
|
public removing: boolean = false
|
|
|
|
public created(): void {
|
|
this.getData()
|
|
bus.$on(SYNC, this.getData)
|
|
}
|
|
|
|
public beforeDestroy(): void {
|
|
bus.$off(SYNC, this.getData)
|
|
}
|
|
|
|
public async getData(docIds?: string[]): Promise<void> {
|
|
if (docIds && !docIds.find((i: string) => i === this.id)) {
|
|
return
|
|
}
|
|
try {
|
|
if (this.removing) {
|
|
return
|
|
}
|
|
this.transaction = await transactionService.get(this.id)
|
|
if (this.transaction) {
|
|
this.account = await accountService.get(this.accountId)
|
|
} else {
|
|
if (this.accountId) {
|
|
this.$router.push({ name: 'account', params: { id: this.accountId } })
|
|
notif.error('Transaction supprimée.')
|
|
} else {
|
|
this.$router.push({ name: 'home' })
|
|
notif.error('Compte inexistant.')
|
|
}
|
|
}
|
|
} catch (error) {
|
|
// tslint:disable-next-line
|
|
console.warn({ error })
|
|
this.$router.push({ name: 'home' })
|
|
}
|
|
}
|
|
|
|
public async removeTransaction(): Promise<void> {
|
|
if (!this.transaction) {
|
|
return
|
|
}
|
|
this.removing = true
|
|
const ok: boolean = await transactionService.remove(this.id)
|
|
if (ok) {
|
|
if (this.accountId) {
|
|
this.$router.push({
|
|
name: 'account',
|
|
params: {
|
|
id: this.accountId
|
|
}
|
|
})
|
|
} else {
|
|
this.$router.push({ name: 'home' })
|
|
}
|
|
}
|
|
this.removing = false
|
|
}
|
|
|
|
public async retrieveExchange(): Promise<void> {
|
|
if (this.transaction && !this.transaction.exchange) {
|
|
this.transaction.exchange = await exchangeService.get(
|
|
this.transaction.mainCurrency.code,
|
|
this.transaction.date
|
|
)
|
|
await transactionService.save(this.transaction)
|
|
}
|
|
}
|
|
|
|
public get accountId(): string {
|
|
return (this.transaction && this.transaction.accountId) || ''
|
|
}
|
|
|
|
public get canModify(): boolean {
|
|
if (!this.transaction) {
|
|
return false
|
|
}
|
|
return (
|
|
(this.transaction.transactionType === TransactionType.normal &&
|
|
this.isAdmin) ||
|
|
this.transaction.payBy === this.userAlias
|
|
)
|
|
}
|
|
|
|
public get userAlias(): string | undefined {
|
|
if (!this.account || !this.user) {
|
|
return ''
|
|
}
|
|
const user = this.user
|
|
return this.account.users
|
|
.map((u: IUser) => u.slugEmail)
|
|
.find((email: string | undefined) => email === user.slugEmail)
|
|
}
|
|
|
|
public get isAdmin(): boolean {
|
|
if (!this.account || !this.user) {
|
|
return true
|
|
}
|
|
return (
|
|
!this.account.admin ||
|
|
this.account.admin.slugEmail === this.user.slugEmail
|
|
)
|
|
}
|
|
|
|
public get payForLabel(): string[] {
|
|
if (!this.transaction) {
|
|
return []
|
|
}
|
|
return this.transaction.payFor.map((p: ISplit) => {
|
|
const part =
|
|
p.weight > 1
|
|
? `(${p.weight} ${this.$tc('transaction.weight', p.weight)})`
|
|
: ''
|
|
return `${p.alias} ${part}`.trim()
|
|
})
|
|
}
|
|
|
|
public get currencies(): ICurrency[] {
|
|
if (!this.transaction || !this.transaction.exchange) {
|
|
return []
|
|
}
|
|
const transaction = this.transaction
|
|
const exchange = transaction.exchange
|
|
return transaction.currencies.filter(
|
|
(currency: ICurrency) => exchange && currency.code !== exchange.base
|
|
)
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
p.resume {
|
|
font-size: 18pt;
|
|
margin: 15px 0;
|
|
}
|
|
table.table {
|
|
margin: 15px auto 0;
|
|
max-width: 350px;
|
|
}
|
|
.main-cell {
|
|
vertical-align: middle;
|
|
}
|
|
.buttons {
|
|
margin-top: 15px;
|
|
}
|
|
.pay-by {
|
|
font-weight: bold;
|
|
}
|
|
.numeric {
|
|
text-align: right;
|
|
}
|
|
</style>
|