hesabixCore/webUI/src/views/acc/accounting/mod.vue

252 lines
7.5 KiB
Vue
Raw Normal View History

2025-03-21 14:20:43 +03:30
<template>
2025-03-26 21:40:38 +03:30
<v-container>
<v-form @submit.prevent="submitForm">
<v-row>
<v-col cols="12" md="6">
<Hdatepicker
v-model="form.date"
:rules="[v => !!v || 'تاریخ الزامی است']"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="form.des"
label="توضیحات سند"
placeholder="توضیحات مربوط به سند"
></v-text-field>
</v-col>
</v-row>
<v-data-table
:headers="headers"
:items="form.rows"
class="elevation-1"
hide-default-footer
:header-props="{ class: 'custom-header' }"
2025-03-26 21:40:38 +03:30
>
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>ردیفهای سند</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn color="primary" @click="addRow">افزودن ردیف</v-btn>
</v-toolbar>
</template>
<template v-slot:item.ref="{ item }">
<v-menu offset-y>
<template v-slot:activator="{ props }">
<v-text-field
v-model="item.refName"
label="حساب"
dense
readonly
v-bind="props"
:rules="[v => !!item.ref || 'حساب الزامی است']"
></v-text-field>
</template>
<v-treeview
:items="hesabdariTables"
item-key="id"
item-text="name"
item-children="children"
selectable
return-object
v-model="item.selectedAccounts"
@update:active="selectAccount(item, $event)"
>
<template v-slot:label="{ item: treeItem }">
{{ treeItem.name }}
2025-03-21 14:20:43 +03:30
</template>
2025-03-26 21:40:38 +03:30
</v-treeview>
</v-menu>
</template>
<template v-slot:item.bd="{ item }">
<v-text-field
v-model="item.bd"
label="بدهکار"
type="number"
dense
@input="calculateTotals"
></v-text-field>
</template>
<template v-slot:item.bs="{ item }">
<v-text-field
v-model="item.bs"
label="بستانکار"
type="number"
dense
@input="calculateTotals"
></v-text-field>
</template>
<template v-slot:item.des="{ item }">
<v-text-field v-model="item.des" label="توضیحات" dense></v-text-field>
</template>
<template v-slot:item.actions="{ item }">
<v-btn color="error" small @click="removeRow(item)">حذف</v-btn>
</template>
</v-data-table>
<v-row class="mt-4">
<v-col cols="6">
<v-text-field
:value="totalBd"
label="جمع بدهکار"
readonly
dense
></v-text-field>
</v-col>
<v-col cols="6">
<v-text-field
:value="totalBs"
label="جمع بستانکار"
readonly
dense
></v-text-field>
</v-col>
</v-row>
<v-alert v-if="error" type="error" class="mt-4">{{ error }}</v-alert>
<v-btn type="submit" color="success" class="mt-4" :disabled="totalBd !== totalBs || !form.date">
ثبت سند
</v-btn>
</v-form>
</v-container>
</template>
<script>
import axios from 'axios';
import moment from 'jalali-moment';
import Hdatepicker from '@/components/forms/Hdatepicker.vue';
export default {
components: {
Hdatepicker,
},
props: {
docId: {
type: Number,
default: null,
2025-03-21 14:20:43 +03:30
},
2025-03-26 21:40:38 +03:30
},
data() {
return {
form: {
date: '', // تاریخ به فرمت ISO (مثلاً 2025-03-24)
des: '',
rows: [
{ ref: null, refName: '', bd: '0', bs: '0', des: '', selectedAccounts: [] },
2025-03-21 14:20:43 +03:30
],
2025-03-26 21:40:38 +03:30
},
hesabdariTables: [],
totalBd: 0,
totalBs: 0,
error: null,
headers: [
{ text: 'حساب', value: 'ref' },
{ text: 'بدهکار', value: 'bd' },
{ text: 'بستانکار', value: 'bs' },
{ text: 'توضیحات', value: 'des' },
{ text: 'عملیات', value: 'actions', sortable: false },
],
};
},
mounted() {
this.fetchHesabdariTables();
if (this.docId) {
this.fetchDoc();
}
},
methods: {
async fetchHesabdariTables() {
try {
const response = await axios.get('/api/hesabdari/tables');
this.hesabdariTables = response.data.data;
} catch (error) {
console.error('خطا در دریافت حساب‌ها:', error.response?.data || error.message);
this.error = 'خطا در بارگذاری حساب‌ها: ' + (error.response?.data?.message || 'مشکل ناشناخته');
}
2025-03-21 14:20:43 +03:30
},
2025-03-26 21:40:38 +03:30
async fetchDoc() {
try {
const response = await axios.get(`/api/hesabdari/doc/${this.docId}`);
const serverDate = response.data.data.date; // فرض: تاریخ شمسی از سرور
this.form.date = moment(serverDate, 'YYYY/MM/DD').format('YYYY-MM-DD');
this.form.des = response.data.data.des || '';
this.form.rows = response.data.data.rows.map(row => ({
ref: row.ref.id,
refName: row.ref.name,
bd: row.bd,
bs: row.bs,
des: row.des,
selectedAccounts: [{ id: row.ref.id, name: row.ref.name }],
}));
this.calculateTotals();
} catch (error) {
this.error = 'خطا در بارگذاری سند: ' + (error.response?.data?.message || 'مشکل ناشناخته');
2025-03-21 14:20:43 +03:30
}
},
2025-03-26 21:40:38 +03:30
addRow() {
this.form.rows.push({ ref: null, refName: '', bd: '0', bs: '0', des: '', selectedAccounts: [] });
},
removeRow(item) {
const index = this.form.rows.indexOf(item);
if (index >= 0) {
this.form.rows.splice(index, 1);
this.calculateTotals();
}
},
calculateTotals() {
this.totalBd = this.form.rows.reduce((sum, row) => sum + parseInt(row.bd || 0), 0);
this.totalBs = this.form.rows.reduce((sum, row) => sum + parseInt(row.bs || 0), 0);
},
selectAccount(row, selected) {
if (selected.length > 0) {
const account = selected[0];
row.ref = account.id;
row.refName = account.name;
row.selectedAccounts = [account];
}
},
async submitForm() {
this.error = null;
if (this.totalBd !== this.totalBs) {
this.error = 'جمع بدهکار و بستانکار باید برابر باشد';
return;
}
const payload = {
date: moment(this.form.date, 'YYYY-MM-DD').locale('fa').format('YYYY/MM/DD'), // ارسال به فرمت شمسی
des: this.form.des,
rows: this.form.rows.map(row => ({
ref: row.ref,
bd: row.bd,
bs: row.bs,
des: row.des,
})),
};
try {
if (this.docId) {
await axios.put(`/api/hesabdari/doc/${this.docId}`, payload);
this.$emit('saved', 'سند با موفقیت ویرایش شد');
} else {
const response = await axios.post('/api/hesabdari/doc', payload);
this.$emit('saved', 'سند با موفقیت ثبت شد', response.data.data.id);
2025-03-21 14:20:43 +03:30
}
2025-03-26 21:40:38 +03:30
} catch (error) {
this.error = error.response?.data?.message || 'خطا در ثبت سند';
}
2025-03-21 14:20:43 +03:30
},
2025-03-26 21:40:38 +03:30
},
};
</script>
<style scoped>
.v-data-table {
margin-top: 20px;
}
</style>