forked from Kispi/Core
feat(webbapp): add account migration
This commit is contained in:
parent
8c1878d4aa
commit
cfb41b2b32
5 changed files with 113 additions and 3 deletions
75
src/components/molecules/MoleculeMigrateAccountModal.vue
Normal file
75
src/components/molecules/MoleculeMigrateAccountModal.vue
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<template>
|
||||||
|
<AtomModal
|
||||||
|
:id="id"
|
||||||
|
title="Kontonummer ändern"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<AtomInput
|
||||||
|
v-model="oldAccountNumber"
|
||||||
|
placeholder="Alte Kontonummer"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
<AtomInput
|
||||||
|
v-model="newAccountNumber"
|
||||||
|
placeholder="Neue Kontonummer"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<template #action>
|
||||||
|
<label
|
||||||
|
ref="abortButton"
|
||||||
|
:for="id"
|
||||||
|
class="btn gap-2"
|
||||||
|
>
|
||||||
|
<XCircleIcon class="w-6 h-6" />
|
||||||
|
Abbrechen
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
class="btn gap-2"
|
||||||
|
@click="handleSubmit"
|
||||||
|
>
|
||||||
|
<CheckCircleIcon class="w-6 h-6" />
|
||||||
|
Speichern
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</AtomModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { DataService } from '../services/data.service';
|
||||||
|
import { CheckCircleIcon, XCircleIcon } from '@heroicons/vue/outline';
|
||||||
|
import AtomInput from '../atoms/AtomInput.vue';
|
||||||
|
import AtomModal from '../atoms/AtomModal.vue';
|
||||||
|
|
||||||
|
const abortButton = ref();
|
||||||
|
const oldAccountNumber = ref('');
|
||||||
|
const newAccountNumber = ref('');
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
try {
|
||||||
|
const isSuccess = await DataService.migrateAccount(oldAccountNumber.value, newAccountNumber.value);
|
||||||
|
emit('submit', isSuccess);
|
||||||
|
abortButton.value.click();
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
} catch (error: any) {
|
||||||
|
alert('Fehler beim Migrieren');
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits(['submit']);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -53,4 +53,14 @@ export const AccountService = {
|
||||||
const accountDocument = await database.createDocument<IAccount & Models.Document>(ACCOUNTS_COLLECTION_ID, 'unique()', account);
|
const accountDocument = await database.createDocument<IAccount & Models.Document>(ACCOUNTS_COLLECTION_ID, 'unique()', account);
|
||||||
return accountDocument;
|
return accountDocument;
|
||||||
},
|
},
|
||||||
|
async migrateAccount(oldAccountNumber: string, newAccountNumber: string): Promise<IAccount> {
|
||||||
|
const account = await this.getAccount(oldAccountNumber);
|
||||||
|
if(!account) {
|
||||||
|
throw new Error('Account not found');
|
||||||
|
}
|
||||||
|
await database.updateDocument<IAccount & Models.Document>(ACCOUNTS_COLLECTION_ID, account.$id, {
|
||||||
|
accountNumber: newAccountNumber,
|
||||||
|
});
|
||||||
|
return account;
|
||||||
|
},
|
||||||
};
|
};
|
|
@ -11,10 +11,10 @@ const SALARY_LABEL = 'Gehalt';
|
||||||
const WITHDRAW_LABEL = 'Bargeldauszahlung';
|
const WITHDRAW_LABEL = 'Bargeldauszahlung';
|
||||||
const OPEN_ACCOUNT_LABEL = 'Kontoeröffnung';
|
const OPEN_ACCOUNT_LABEL = 'Kontoeröffnung';
|
||||||
const sdk = AppwriteService.getSDK();
|
const sdk = AppwriteService.getSDK();
|
||||||
|
const database = new Databases(sdk, DATABASE_ID);
|
||||||
|
|
||||||
export const BankService = {
|
export const BankService = {
|
||||||
async getAccountDetails(accountNumber: string): Promise<IAccount> {
|
async getAccountDetails(accountNumber: string): Promise<IAccount> {
|
||||||
const database = new Databases(sdk, DATABASE_ID);
|
|
||||||
const account = await AccountService.getAccount(accountNumber);
|
const account = await AccountService.getAccount(accountNumber);
|
||||||
if(!account) {
|
if(!account) {
|
||||||
throw new Error('Account not found');
|
throw new Error('Account not found');
|
||||||
|
@ -35,7 +35,6 @@ export const BankService = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async addTransaction(accountNumber: string, amount: number, type: TransactionType): Promise<ITransaction> {
|
async addTransaction(accountNumber: string, amount: number, type: TransactionType): Promise<ITransaction> {
|
||||||
const database = new Databases(sdk, DATABASE_ID);
|
|
||||||
let label = '';
|
let label = '';
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TransactionType.DEPOSIT:
|
case TransactionType.DEPOSIT:
|
||||||
|
@ -59,6 +58,16 @@ export const BankService = {
|
||||||
await AccountService.updateBalance(accountNumber, type === TransactionType.WITHDRAW ? -amount : amount);
|
await AccountService.updateBalance(accountNumber, type === TransactionType.WITHDRAW ? -amount : amount);
|
||||||
return { label: transactionDocument.label, amount: transactionDocument.amount, date: new Date(transactionDocument.$createdAt * 1000) };
|
return { label: transactionDocument.label, amount: transactionDocument.amount, date: new Date(transactionDocument.$createdAt * 1000) };
|
||||||
},
|
},
|
||||||
|
async migrateTransactions(oldAccountNumber: string, newAccountNumber: string): Promise<boolean> {
|
||||||
|
const transactionDocuments = await database.listDocuments<ITransaction & Models.Document>(
|
||||||
|
TRANSACTIONS_COLLECTION_ID, [Query.equal('accountNumber', oldAccountNumber)], 100, 0, undefined, undefined, ['$createdAt'], ['DESC']);
|
||||||
|
transactionDocuments.documents.forEach(async transaction => {
|
||||||
|
await database.updateDocument(TRANSACTIONS_COLLECTION_ID, transaction.$id, {
|
||||||
|
accountNumber: newAccountNumber,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum TransactionType {
|
export enum TransactionType {
|
||||||
|
|
|
@ -65,4 +65,9 @@ export const DataService = {
|
||||||
accountDocument.balance = OPEN_ACCOUNT_BALANCE;
|
accountDocument.balance = OPEN_ACCOUNT_BALANCE;
|
||||||
return accountDocument;
|
return accountDocument;
|
||||||
},
|
},
|
||||||
|
async migrateAccount(oldAccountNumber: string, newAccountNumber: string): Promise<boolean> {
|
||||||
|
await AccountService.migrateAccount(oldAccountNumber, newAccountNumber);
|
||||||
|
await BankService.migrateTransactions(oldAccountNumber, newAccountNumber);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
};
|
};
|
|
@ -27,10 +27,19 @@
|
||||||
:name="contactName"
|
:name="contactName"
|
||||||
:contact="contact"
|
:contact="contact"
|
||||||
/>
|
/>
|
||||||
|
<MoleculeMigrateAccountModal
|
||||||
|
:id="migrateAccountModalId"
|
||||||
|
/>
|
||||||
<MoleculeAddAccountModal
|
<MoleculeAddAccountModal
|
||||||
:id="addAccountModalId"
|
:id="addAccountModalId"
|
||||||
@submit="addAccount"
|
@submit="addAccount"
|
||||||
/>
|
/>
|
||||||
|
<label
|
||||||
|
class="btn btn-primary btn-lg btn-circle shadow-2xl fixed bottom-8 right-28"
|
||||||
|
:for="migrateAccountModalId"
|
||||||
|
>
|
||||||
|
<SupportIcon class="w-7 h-7" />
|
||||||
|
</label>
|
||||||
<label
|
<label
|
||||||
class="btn btn-primary btn-lg btn-circle shadow-2xl fixed bottom-8 right-8"
|
class="btn btn-primary btn-lg btn-circle shadow-2xl fixed bottom-8 right-8"
|
||||||
:for="addAccountModalId"
|
:for="addAccountModalId"
|
||||||
|
@ -44,11 +53,12 @@
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { DataService } from '../services/data.service';
|
import { DataService } from '../services/data.service';
|
||||||
import { IAccountData } from '../../interfaces/account-data.interface';
|
import { IAccountData } from '../../interfaces/account-data.interface';
|
||||||
import { PlusIcon } from '@heroicons/vue/outline';
|
import { PlusIcon, SupportIcon } from '@heroicons/vue/outline';
|
||||||
import MoleculeAddAccountModal from '../molecules/MoleculeAddAccountModal.vue';
|
import MoleculeAddAccountModal from '../molecules/MoleculeAddAccountModal.vue';
|
||||||
import MoleculeContactModal from '../molecules/MoleculeContactModal.vue';
|
import MoleculeContactModal from '../molecules/MoleculeContactModal.vue';
|
||||||
import MoleculeDataTable, { TableHeaderType } from '../molecules/MoleculeDataTable.vue';
|
import MoleculeDataTable, { TableHeaderType } from '../molecules/MoleculeDataTable.vue';
|
||||||
import AtomInput from '../atoms/AtomInput.vue';
|
import AtomInput from '../atoms/AtomInput.vue';
|
||||||
|
import MoleculeMigrateAccountModal from '../molecules/MoleculeMigrateAccountModal.vue';
|
||||||
|
|
||||||
const ACCESS_PIN_KEY = '1337';
|
const ACCESS_PIN_KEY = '1337';
|
||||||
const pinCorrect = ref(false);
|
const pinCorrect = ref(false);
|
||||||
|
@ -57,6 +67,7 @@ const contactName = ref('');
|
||||||
const contact = ref<string[]>([]);
|
const contact = ref<string[]>([]);
|
||||||
const contactModalId = 'contact-modal';
|
const contactModalId = 'contact-modal';
|
||||||
const addAccountModalId = 'add-account-modal';
|
const addAccountModalId = 'add-account-modal';
|
||||||
|
const migrateAccountModalId = 'migrate-account-modal';
|
||||||
const tableHeaders = [
|
const tableHeaders = [
|
||||||
{
|
{
|
||||||
title: 'Kontonummer',
|
title: 'Kontonummer',
|
||||||
|
|
Loading…
Reference in a new issue