some bug fix in order archive, bank transfer and ...

This commit is contained in:
Hesabix 2025-04-09 21:41:16 +00:00
parent 3908830417
commit 638a386fe6
13 changed files with 954 additions and 921 deletions

View file

@ -4,6 +4,10 @@ namespace App\Controller;
use App\Entity\HesabdariDoc;
use App\Entity\HesabdariRow;
use App\Entity\BankAccount;
use App\Entity\Salary;
use App\Entity\Cashdesk;
use App\Entity\HesabdariTable;
use App\Service\Access;
use App\Service\Log;
use App\Service\Provider;
@ -22,13 +26,15 @@ class TransferController extends AbstractController
$acc = $access->hasRole('bankTransfer');
if (!$acc)
throw $this->createAccessDeniedException();
$items = $entityManager->getRepository(HesabdariDoc::class)->findBy([
$items = $entityManager->getRepository(HesabdariDoc::class)->findBy(
[
'bid' => $acc['bid'],
'type' => 'transfer',
'year' => $acc['year'],
'money' => $acc['money']
],
['dateSubmit'=>'DESC']);
['dateSubmit' => 'DESC']
);
$resp = [];
foreach ($items as $item) {
$temp = [];
@ -50,26 +56,21 @@ class TransferController extends AbstractController
if ($row->getBank()) {
$fromType = 'bank';
$fromObject = $row->getBank()->getName();
}
elseif($row->getSalary()){
} elseif ($row->getSalary()) {
$fromType = 'salary';
$fromObject = $row->getSalary()->getName();
}
elseif($row->getCashdesk()){
} elseif ($row->getCashdesk()) {
$fromType = 'cashDesk';
$fromObject = $row->getCashdesk()->getName();
}
}
else{
} else {
if ($row->getBank()) {
$toType = 'bank';
$toObject = $row->getBank()->getName();
}
elseif($row->getSalary()){
} elseif ($row->getSalary()) {
$toType = 'salary';
$toObject = $row->getSalary()->getName();
}
elseif($row->getCashdesk()){
} elseif ($row->getCashdesk()) {
$toType = 'cashDesk';
$toObject = $row->getCashdesk()->getName();
}
@ -83,4 +84,121 @@ class TransferController extends AbstractController
}
return $this->json($resp);
}
#[Route('/api/transfer/insert', name: 'app_transfer_insert')]
public function app_transfer_insert(Provider $provider, Request $request, Access $access, Log $log, EntityManagerInterface $entityManager): JsonResponse
{
$acc = $access->hasRole('bankTransfer');
if (!$acc)
throw $this->createAccessDeniedException();
$params = [];
if ($content = $request->getContent()) {
$params = json_decode($content, true);
}
if (!array_key_exists('date', $params) || !array_key_exists('des', $params))
throw $this->createNotFoundException('some params mistake');
if (array_key_exists('update', $params) && $params['update'] != '') {
$doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([
'bid' => $acc['bid'],
'year' => $acc['year'],
'code' => $params['update'],
'money' => $acc['money']
]);
if (!$doc)
throw $this->createNotFoundException('document not found.');
$doc->setDes($params['des']);
$doc->setDate($params['date']);
$doc->setMoney($acc['money']);
$entityManager->persist($doc);
$entityManager->flush();
$rows = $entityManager->getRepository(HesabdariRow::class)->findBy([
'doc' => $doc
]);
foreach ($rows as $row)
$entityManager->remove($row);
} else {
$doc = new HesabdariDoc();
$doc->setBid($acc['bid']);
$doc->setYear($acc['year']);
$doc->setDes($params['des']);
$doc->setDateSubmit(time());
$doc->setType('transfer');
$doc->setDate($params['date']);
$doc->setSubmitter($this->getUser());
$doc->setMoney($acc['money']);
$doc->setCode($provider->getAccountingCode($acc['bid'], 'accounting'));
$entityManager->persist($doc);
$entityManager->flush();
}
$amount = 0;
foreach ($params['rows'] as $row) {
$row['bs'] = str_replace(',', '', $row['bs']);
$row['bd'] = str_replace(',', '', $row['bd']);
$hesabdariRow = new HesabdariRow();
$hesabdariRow->setBid($acc['bid']);
$hesabdariRow->setYear($acc['year']);
$hesabdariRow->setDoc($doc);
$hesabdariRow->setBs($row['bs']);
$hesabdariRow->setBd($row['bd']);
$hesabdariRow->setDes($row['des']);
$hesabdariRow->setReferral($row['referral']);
if ($row['type'] == 'bank') {
$bank = $entityManager->getRepository(BankAccount::class)->findOneBy([
'id' => $row['id'],
'bid' => $acc['bid']
]);
if (!$bank)
throw $this->createNotFoundException('bank not found');
$hesabdariRow->setBank($bank);
$hesabdariRow->setRef($entityManager->getRepository(HesabdariTable::class)->findOneBy(['code' => '5']));
} elseif ($row['type'] == 'salary') {
$salary = $entityManager->getRepository(Salary::class)->findOneBy([
'id' => $row['id'],
'bid' => $acc['bid']
]);
if (!$salary)
throw $this->createNotFoundException('salary not found');
$hesabdariRow->setSalary($salary);
$hesabdariRow->setRef($entityManager->getRepository(HesabdariTable::class)->findOneBy(['code' => '122']));
} elseif ($row['type'] == 'cashdesk') {
$cashdesk = $entityManager->getRepository(Cashdesk::class)->findOneBy([
'id' => $row['id'],
'bid' => $acc['bid']
]);
if (!$cashdesk)
throw $this->createNotFoundException('cashdesk not found');
$hesabdariRow->setCashdesk($cashdesk);
$hesabdariRow->setRef($entityManager->getRepository(HesabdariTable::class)->findOneBy(['code' => '121']));
}
$entityManager->persist($hesabdariRow);
$amount += $row['bs'];
}
$doc->setAmount($amount);
$entityManager->persist($doc);
$entityManager->flush();
$log->insert(
'حسابداری',
'سند انتقال وجه شماره ' . $doc->getCode() . ' ثبت / ویرایش شد.',
$this->getUser(),
$request->headers->get('activeBid'),
$doc
);
return $this->json([
'result' => 1,
'doc' => $provider->Entity2Array($doc, 0)
]);
}
}

View file

@ -10,7 +10,7 @@
<h3 class="mx-5">
متاسفانه پرداخت ناموفق بود!
</h3>
<a class="btn btn-lg btn-success mt-4" href="{{ twigFunctions.systemSettings().appSite }}/profile/dashboard">
<a class="btn btn-lg btn-success mt-4" href="{{ twigFunctions.systemSettings().appSite }}/u/profile/dashboard">
<i class="bi bi-buy"></i>
بازگشت به پروفایل کاربری
</a>

View file

@ -10,7 +10,7 @@
<h3 class="mx-5">
با تشکر از پرداخت شما. سفارش شما اعمال شد.
</h3>
<a class="btn btn-lg btn-success mt-4" href="{{ twigFunctions.systemSettings().appSite }}/profile/dashboard">
<a class="btn btn-lg btn-success mt-4" href="{{ twigFunctions.systemSettings().appSite }}/u/profile/dashboard">
<i class="bi bi-buy"></i>
بازگشت به پروفایل کاربری
</a>

View file

@ -41,16 +41,15 @@ export default {
},
data() {
return {
displayDate: this.modelValue, // مقداردهی اولیه از prop
pickerActive: false, // کنترل باز شدن تقویم
minDatePersian: '', // تاریخ شروع سال مالی (شمسی برای پکیج)
maxDatePersian: '', // تاریخ پایان سال مالی (شمسی برای پکیج)
uniqueId: '', // شناسه یکتا برای هر نمونه
isInitialized: false, // فلگ برای کنترل مقداردهی اولیه
displayDate: '', // مقداردهی اولیه خالی
pickerActive: false,
minDatePersian: '',
maxDatePersian: '',
uniqueId: '',
isInitialized: false,
};
},
created() {
// ایجاد شناسه یکتا برای هر نمونه از کامپوننت
this.uniqueId = Math.random().toString(36).substring(2, 15);
},
watch: {
@ -62,7 +61,7 @@ export default {
modelValue: {
immediate: true,
handler(newVal) {
if (newVal && newVal !== this.displayDate) {
if (newVal) {
this.displayDate = newVal;
}
}
@ -78,8 +77,8 @@ export default {
this.minDatePersian = response.data.start;
this.maxDatePersian = response.data.end;
// فقط اگر مقدار اولیه نداریم، از تاریخ جاری استفاده کنیم
if (!this.modelValue && !this.isInitialized) {
// فقط اگر مقدار اولیه نداریم و هنوز مقداردهی نشده، از تاریخ جاری استفاده کنیم
if (!this.modelValue && !this.displayDate && !this.isInitialized) {
this.displayDate = response.data.now;
this.$emit('update:modelValue', response.data.now);
this.isInitialized = true;

View file

@ -268,7 +268,9 @@ const fa_lang = {
count: "تعداد",
},
dialog: {
download: 'دانلود',
delete_group: 'حذف گروهی',
add_new_transfer: 'سند انتقال جدید',
acc_price: 'مبلغ',
des: 'شرح',
warning: 'هشدار',

View file

@ -1,57 +1,88 @@
<template>
<div class="block block-content-full ">
<div id="fixed-header" class="block-header block-header-default bg-gray-light pt-2 pb-1">
<h3 class="block-title text-primary-dark">
<button @click="$router.back()" type="button"
class="float-start d-none d-sm-none d-md-block btn btn-sm btn-link text-warning">
<i class="fa fw-bold fa-arrow-right"></i>
</button>
<i class="fa fa-shopping-bag px-2"></i>
سفارش فضای ذخیره سازی
</h3>
<div class="block-options">
<button :disabled="this.loading" @click="this.submit()" type="button" class="btn btn-sm btn-primary">
<div v-show="this.loading" class="spinner-grow spinner-grow-sm me-2" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<i class="fa fa-bank"></i>
<div class="d-flex flex-column">
<v-toolbar title="سفارش فضای ذخیره سازی" color="toolbar">
<template v-slot:prepend>
<v-btn icon @click="$router.back()">
<v-icon>mdi-arrow-right</v-icon>
</v-btn>
</template>
<v-spacer></v-spacer>
<v-btn
:loading="loading"
:disabled="loading"
@click="submit()"
color="success"
prepend-icon="mdi-credit-card-check"
variant="elevated"
class="px-4"
>
<template v-slot:prepend>
<v-icon size="20" class="ml-2"></v-icon>
</template>
پرداخت آنلاین
</button>
</div>
</div>
<div class="block-content pt-1 pb-3">
<div class="row">
<div class="col-sm-12 col-md-12 p-1">
<div class="alert">
<v-tooltip activator="parent" location="bottom">
پرداخت آنلاین از طریق درگاه بانکی
</v-tooltip>
</v-btn>
</v-toolbar>
<v-container>
<v-alert
type="info"
class="mb-4"
>
برای سفارش فضای ذخیره سازی ابتدا حجم مورد نظر را انتخاب و روی دکمه پرداخت کلیک کنید.
</div>
</div>
<div class="row">
<div class="col-12">
<label for="customRange3" class="form-label">فضای مورد نیاز بر حسب گیگابایت:</label>
<input :disabled="this.loading" v-model="this.space" type="range" class="form-range" min="1" max="5"
step="1" id="customRange3">
</div>
<div class="col">
<label>فضا(گیگابایت)</label>
<input type="text" class="form-control" v-model="this.space" readonly="readonly" />
</div>
<div class="col">
<label>زمان</label>
<select :disabled="this.loading" v-model="this.month" class="form-select" aria-label="ماه">
<option value="1" selected>یک ماه</option>
<option value="3">سه ماه</option>
<option value="6">شش ماه</option>
<option value="12">یک سال</option>
</select>
</div>
<div class="col">
<label>مبلغ نهایی (ریال)</label>
<input type="text" class="form-control text-danger" v-model="this.priceTotal" readonly="readonly" />
</div>
</div>
</div>
</div>
</v-alert>
<v-row>
<v-col cols="12">
<v-label>فضای مورد نیاز بر حسب گیگابایت:</v-label>
<v-slider
v-model="space"
:disabled="loading"
min="1"
max="5"
step="1"
thumb-label
class="mt-2"
></v-slider>
</v-col>
<v-col cols="12" sm="4">
<v-text-field
v-model="space"
label="فضا (گیگابایت)"
readonly
variant="outlined"
></v-text-field>
</v-col>
<v-col cols="12" sm="4">
<v-select
v-model="month"
:disabled="loading"
:items="[
{ title: 'یک ماه', value: 1 },
{ title: 'سه ماه', value: 3 },
{ title: 'شش ماه', value: 6 },
{ title: 'یک سال', value: 12 }
]"
label="زمان"
variant="outlined"
></v-select>
</v-col>
<v-col cols="12" sm="4">
<v-text-field
v-model="priceTotal"
label="مبلغ نهایی (ریال)"
readonly
variant="outlined"
color="error"
></v-text-field>
</v-col>
</v-row>
</v-container>
</div>
</template>

View file

@ -1,61 +1,50 @@
<template>
<div class="block block-content-full ">
<div id="fixed-header" class="block-header block-header-default bg-gray-light pt-2 pb-1">
<h3 class="block-title text-primary-dark">
<button @click="$router.back()" type="button" class="float-start d-none d-sm-none d-md-block btn btn-sm btn-link text-warning">
<i class="fa fw-bold fa-arrow-right"></i>
</button>
<i class="fa fa-list-dots px-2"></i>
لیست سفارشات فضای ابری
</h3>
<div class="block-options">
<v-toolbar color="grey-lighten-3" title="لیست سفارشات فضای ابری" density="compact" class="px-2">
<template v-slot:prepend>
<v-btn icon @click="$router.back()">
<v-icon>mdi-arrow-right</v-icon>
</v-btn>
</template>
</v-toolbar>
<v-row>
<v-col cols="12">
<v-text-field v-model="searchValue" prepend-inner-icon="mdi-magnify" label="جست و جو ..." variant="outlined"
density="compact" hide-details :rounded="false" class=""></v-text-field>
</div>
</div>
<div class="block-content pt-1 pb-3">
<div class="row">
<div class="col-sm-12 col-md-12 p-1">
<div class="my-2">
<div class="input-group input-group-sm">
<span class="input-group-text"><i class="fa fa-search"></i></span>
<input v-model="searchValue" class="form-control" type="text" placeholder="جست و جو ...">
</div>
</div>
<EasyDataTable
:headers="headers"
:items="items"
alternating
:search-value="searchValue"
theme-color="#1d90ff"
table-class-name="customize-table"
header-text-direction="center"
body-text-direction="center"
rowsPerPageMessage="تعداد سطر"
emptyMessage="اطلاعاتی برای نمایش وجود ندارد"
rowsOfPageSeparatorMessage="از"
:loading="loading"
>
<template #item-status="{ status }">
<span v-if="status == 100" class="text-success"><i class="fa fa-check me-2"></i>موفق</span>
<span v-else class="text-danger"><i class="fa fa-info me-2"></i>پرداخت نشده</span>
<v-data-table :headers="headers" :items="items" :search="searchValue" :loading="loading"
loading-text="در حال بارگذاری..." no-data-text="اطلاعاتی برای نمایش وجود ندارد" items-per-page-text="تعداد سطر"
:items-per-page-options="[10, 25, 50, 100]" class="elevation-1" :header-props="{ class: 'custom-header' }">
<template v-slot:item.status="{ item }">
<v-chip :color="item.status === 100 ? 'success' : 'error'" size="small">
<v-icon start>
{{ item.status === 100 ? 'mdi-check' : 'mdi-information' }}
</v-icon>
{{ item.status === 100 ? 'موفق' : 'پرداخت نشده' }}
</v-chip>
</template>
<template #item-price="{ price }">
<span class="">{{ $filters.formatNumber(price)}}</span>
<template v-slot:item.price="{ item }">
{{ $filters.formatNumber(item.price) }}
</template>
<template #item-cardPan="{ cardPan }">
<span style="direction:ltr" class="">{{cardPan}}</span>
<template v-slot:item.cardPan="{ item }">
<span style="direction: ltr">{{ item.cardPan }}</span>
</template>
<template #item-gatePay="{ gatePay }">
<span class="text-warning" v-if="gatePay == 'zarinpal'">
<img src="/img/icons/zarinpal.png" class="img-avatar img-avatar16" />
<template v-slot:item.gatePay="{ item }">
<v-chip v-if="item.gatePay === 'zarinpal'" color="warning" size="small">
<v-avatar start>
<v-img src="/img/icons/zarinpal.png" width="16" height="16"></v-img>
</v-avatar>
زرین پال
</span>
</v-chip>
<v-chip v-else color="error" size="small">
سایر
</v-chip>
</template>
</EasyDataTable>
</div>
</div>
</div>
</div>
</v-data-table>
</v-col>
</v-row>
</template>
<script>
@ -65,20 +54,20 @@ import {ref} from "vue";
export default {
name: "orders_list",
data: ()=>{return {
data: () => ({
searchValue: '',
loading: ref(true),
items: [],
headers: [
{ text: "تاریخ", value: "dateSubmit" },
{ text: "وضعیت", value: "status"},
{ text: "مبلغ (ریال)", value: "price"},
{ text: "توضیحات", value: "des"},
{ text: "شماره کارت", value: "cardPan"},
{ text: "شماره پیگیری", value: "refID"},
{ text: "درگاه پرداخت", value: "gatePay"},
{ title: "تاریخ", key: "dateSubmit", align: "center" },
{ title: "وضعیت", key: "status", align: "center" },
{ title: "مبلغ (ریال)", key: "price", align: "center" },
{ title: "توضیحات", key: "des", align: "center" },
{ title: "شماره کارت", key: "cardPan", align: "center" },
{ title: "شماره پیگیری", key: "refID", align: "center" },
{ title: "درگاه پرداخت", key: "gatePay", align: "center" },
],
}},
}),
methods: {
loadData() {
this.loading = true;
@ -96,5 +85,7 @@ export default {
</script>
<style scoped>
.v-toolbar-title {
font-size: 1.1rem;
}
</style>

View file

@ -1,139 +1,139 @@
<template>
<div class="block block-content-full ">
<div id="fixed-header" class="block-header block-header-default bg-gray-light pt-2 pb-1">
<h3 class="block-title text-primary-dark">
<button @click="$router.back()" type="button" class="float-start d-none d-sm-none d-md-block btn btn-sm btn-link text-warning">
<i class="fa fw-bold fa-arrow-right"></i>
</button>
<i class="fa fa-folder-tree px-2"></i>
آرشیو فایلها</h3>
<div class="block-options">
</div>
</div>
<div class="block-content pt-1 pb-3">
<div class="row">
<div class="col-sm-12 col-md-3 p-1">
<div class="list-group">
<button class="list-group-item list-group-item-action active" aria-current="true">
<i class="fa fa-folder-tree"></i>
<v-toolbar color="toolbar" title="آرشیو فایل‌ها">
<template v-slot:prepend>
<v-btn icon @click="$router.back()">
<v-icon>mdi-arrow-right</v-icon>
</v-btn>
</template>
</v-toolbar>
<v-container fluid>
<v-row>
<v-col cols="12" md="3">
<v-expansion-panels class="mb-1" :model-value="isMobile ? [] : [0]">
<v-expansion-panel>
<v-expansion-panel-title class="bg-primary text-white">
<v-icon start>mdi-folder-tree</v-icon>
دسته بندی فایلها
</button>
<button type="button" @click="this.loadData('all')" class="list-group-item list-group-item-action">همه فایلها</button>
<button type="button" @click="this.loadData('accounting')" class="list-group-item list-group-item-action">اسناد حسابداری</button>
<button type="button" @click="this.loadData('persons')" class="list-group-item list-group-item-action">اشخاص</button>
<button type="button" @click="this.loadData('commodity')" class="list-group-item list-group-item-action">کالا</button>
<button type="button" @click="this.loadData('bank')" class="list-group-item list-group-item-action">بانک</button>
<button type="button" @click="this.loadData('cashdesk')" class="list-group-item list-group-item-action">صندوق</button>
<button type="button" @click="this.loadData('salary')" class="list-group-item list-group-item-action">تنخواه</button>
<button type="button" @click="this.loadData('storeroom')" class="list-group-item list-group-item-action">انبار</button>
<button type="button" @click="this.loadData('transfer')" class="list-group-item list-group-item-action">انتقال</button>
<button type="button" @click="this.loadData('persons_recive')" class="list-group-item list-group-item-action">دریافت</button>
<button type="button" @click="this.loadData('persns_send')" class="list-group-item list-group-item-action">پرداخت</button>
<button type="button" @click="this.loadData('income')" class="list-group-item list-group-item-action">درآمد</button>
<button type="button" @click="this.loadData('cost')" class="list-group-item list-group-item-action">هزینه</button>
<button type="button" @click="this.loadData('buy')" class="list-group-item list-group-item-action">خرید</button>
<button type="button" @click="this.loadData('sell')" class="list-group-item list-group-item-action">فروش</button>
<button type="button" @click="this.loadData('onlinestore')" class="list-group-item list-group-item-action">فروشگاه آنلاین</button>
</div>
</div>
<div class="col-sm-12 col-md-9 p-0">
<div class="mb-1">
<div class="input-group input-group-sm">
<span class="input-group-text"><i class="fa fa-search"></i></span>
<input v-model="searchValue" class="form-control" type="text" placeholder="جست و جو ...">
</div>
</div>
<EasyDataTable table-class-name="customize-table"
show-index
alternating
:search-value="searchValue"
:headers="headers"
:items="items"
theme-color="#1d90ff"
header-text-direction="center"
body-text-direction="center"
rowsPerPageMessage="تعداد سطر"
emptyMessage="اطلاعاتی برای نمایش وجود ندارد"
rowsOfPageSeparatorMessage="از"
:loading = "loading"
>
<template #item-operation="{ id, filename,fileType}">
<a class="btn btn-link" href="/" @click.prevent="downloadFile(id,filename,fileType)">
<i class="fa fa-download"></i>
</a>
<button @click="deleteItem(id)" class="btn ms-2 btn-link text-danger">
<i class="fa fa-trash"></i>
</button>
</v-expansion-panel-title>
<v-expansion-panel-text>
<v-list density="compact" class="py-0">
<v-list-item v-for="(category, index) in categories" :key="index" :title="category.title"
:value="category.value" @click="loadData(category.value)" class="py-1"></v-list-item>
</v-list>
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
</v-col>
<v-col cols="12" md="9">
<v-text-field v-model="searchValue" prepend-inner-icon="mdi-magnify" label="جست و جو ..." variant="outlined"
density="compact" :rounded="false"></v-text-field>
<v-data-table :headers="headers" :items="items" :search="searchValue" :loading="loading"
loading-text="در حال بارگذاری..." no-data-text="اطلاعاتی برای نمایش وجود ندارد"
items-per-page-text="تعداد سطر" :items-per-page-options="[10, 20, 50, 100]" class="elevation-1 text-center"
:header-props="{ class: 'custom-header' }">
<template v-slot:item.operation="{ item }">
<v-menu>
<template v-slot:activator="{ props }">
<v-btn variant="text" size="small" color="error" icon="mdi-menu" v-bind="props" />
</template>
<template #item-cat="{ cat }">
<span v-if="cat == 'accounting'">اسناد حسابداری</span>
<span v-if="cat == 'persons'">اشخاص</span>
<span v-if="cat == 'commodity'">کالا</span>
<span v-if="cat == 'bank'">بانک</span>
<span v-if="cat == 'cashdesk'">صندوق</span>
<span v-if="cat == 'salary'">تنخواه گردان</span>
<span v-if="cat == 'transfer'">انتقال</span>
<span v-if="cat == 'storeroom'">انبار</span>
<span v-if="cat == 'persons_recive'">دریافت</span>
<span v-if="cat == 'persns_send'">پرداخت</span>
<span v-if="cat == 'income'">درآمد</span>
<span v-if="cat == 'cost'">هزینه</span>
<span v-if="cat == 'buy'">خرید</span>
<span v-if="cat == 'sell'">فروش</span>
<span v-if="cat == 'onlinestore'">فروشگاه آنلاین</span>
<v-list>
<v-list-item class="text-dark" :title="$t('dialog.download')"
@click="downloadFile(item.id, item.filename, item.fileType)">
<template v-slot:prepend>
<v-icon color="primary" icon="mdi-download" />
</template>
<template #item-filePublic="{ filePublic }">
<i v-if="filePublic" class="text-success fa fa-check"></i>
<i v-else class="text-danger fa fa-close"></i>
</v-list-item>
<v-list-item class="text-dark" :title="$t('dialog.delete')" @click="deleteItem(item.id)">
<template v-slot:prepend>
<v-icon color="error" icon="mdi-delete" />
</template>
</EasyDataTable>
</div>
</div>
</div>
</div>
</v-list-item>
</v-list>
</v-menu>
</template>
<template v-slot:item.cat="{ item }">
{{ getCategoryTitle(item.cat) }}
</template>
<template v-slot:item.filePublic="{ item }">
<v-icon :color="item.filePublic ? 'success' : 'error'">
{{ item.filePublic ? 'mdi-check' : 'mdi-close' }}
</v-icon>
</template>
</v-data-table>
</v-col>
</v-row>
</v-container>
</template>
<script>
import axios from "axios";
import Swal from "sweetalert2";
import {ref} from "vue";
export default {
name: "list",
data: ()=>{return {
name: "ArchiveFiles",
data: () => ({
searchValue: '',
loading: ref(true),
loading: true,
cat: 'all',
items: [],
categories: [
{ title: 'همه فایل‌ها', value: 'all' },
{ title: 'اسناد حسابداری', value: 'accounting' },
{ title: 'اشخاص', value: 'persons' },
{ title: 'کالا', value: 'commodity' },
{ title: 'بانک', value: 'bank' },
{ title: 'صندوق', value: 'cashdesk' },
{ title: 'تنخواه', value: 'salary' },
{ title: 'انبار', value: 'storeroom' },
{ title: 'انتقال', value: 'transfer' },
{ title: 'دریافت', value: 'persons_recive' },
{ title: 'پرداخت', value: 'persns_send' },
{ title: 'درآمد', value: 'income' },
{ title: 'هزینه', value: 'cost' },
{ title: 'خرید', value: 'buy' },
{ title: 'فروش', value: 'sell' },
{ title: 'فروشگاه آنلاین', value: 'onlinestore' }
],
headers: [
{ text: "عملیات", value: "operation", width: "130"},
{ text: "نام فایل", value: "filename", width: "100" },
{ text: "نوع فایل", value: "fileType", width: "120"},
{ text: "حجم (مگابایت)", value: "filesize", width: "100" },
{ text: "تاریخ ایجاد", value: "dateSubmit", width: "140"},
{ text: "ایجاد کننده", value: "submitter", width: "140"},
{ text: "دسترسی عمومی", value: "filePublic", width: "120"},
{ text: "دسته بندی", value: "cat", width: "120"},
{ title: "عملیات", key: "operation", width: "130", align: "center" },
{ title: "نام فایل", key: "filename", width: "100", align: "center" },
{ title: "نوع فایل", key: "fileType", width: "120", align: "center" },
{ title: "حجم (مگابایت)", key: "filesize", width: "100", align: "center" },
{ title: "تاریخ ایجاد", key: "dateSubmit", width: "140", align: "center" },
{ title: "ایجاد کننده", key: "submitter", width: "140", align: "center" },
{ title: "دسترسی عمومی", key: "filePublic", width: "120", align: "center" },
{ title: "دسته بندی", key: "cat", width: "120", align: "center" }
]
}},
}),
computed: {
isMobile() {
return this.$vuetify.display.mobile;
}
},
methods: {
loadData(cat) {
this.loading = true;
axios.post('/api/archive/list/' + cat)
.then((response) => {
this.items = response.data;
this.cat = cat;
this.loading = false;
})
.catch(() => {
this.loading = false;
});
},
deleteItem(id) {
Swal.fire({
text: 'آیا برای حذف فایل مطمئن هستید؟',
showCancelButton: true,
confirmButtonText: 'بله',
cancelButtonText: `خیر`,
cancelButtonText: 'خیر',
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
axios.post('api/archive/file/remove/' + id).then((response) => {
if (response.data.result == 1) {
@ -144,28 +144,37 @@
confirmButtonText: 'قبول'
});
}
})
});
}
})
},
downloadFile(id,filename,fileType) {
axios.post(this.$filters.getApiUrl() + '/api/archive/file/get/' + id, {responseType: "arraybuffer"})
.then(response => {
const blob = new Blob([response.data], {type: fileType});
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
URL.revokeObjectURL(link.href);
});
},
downloadFile(id, filename, fileType) {
axios.get(this.$filters.getApiUrl() + '/api/archive/file/get/' + id, {
responseType: 'blob'
}).then(response => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
link.remove();
window.URL.revokeObjectURL(url);
});
},
beforeMount() {
getCategoryTitle(cat) {
const category = this.categories.find(c => c.value === cat);
return category ? category.title : cat;
}
},
mounted() {
this.loadData(this.cat);
}
}
</script>
<style scoped>
.v-list-item--active {
background-color: rgba(var(--v-theme-primary), 0.1);
}
</style>

View file

@ -35,6 +35,7 @@
class="mb-0 pt-0 rounded-0"
hide-details="auto"
density="compact"
:rounded="false"
:placeholder="$t('dialog.search_txt')"
clearable
>

View file

@ -44,12 +44,10 @@
</v-menu>
</v-toolbar>
<v-card>
<v-card-text>
<v-window v-model="tab">
<v-window-item value="input">
<v-text-field v-model="searchValueInput" prepend-inner-icon="mdi-magnify" label="جست و جو" variant="outlined"
density="compact" class="mb-4"></v-text-field>
<v-text-field class="pt-1" v-model="searchValueInput" prepend-inner-icon="mdi-magnify" label="جست و جو" variant="outlined"
density="compact" :rounded="false"></v-text-field>
<v-data-table :headers="headersInput" :items="itemsInput" :search="searchValueInput" :loading="loading"
show-index density="comfortable" class="elevation-1" :header-props="{ class: 'custom-header' }">
@ -72,8 +70,8 @@
</v-window-item>
<v-window-item value="output">
<v-text-field v-model="searchValueOutput" prepend-inner-icon="mdi-magnify" label="جست و جو" variant="outlined"
density="compact" class="mb-4"></v-text-field>
<v-text-field class="pt-1" v-model="searchValueOutput" prepend-inner-icon="mdi-magnify" label="جست و جو" variant="outlined"
density="compact" :rounded="false"></v-text-field>
<v-data-table :headers="headersInput" :items="itemsOutput" :search="searchValueOutput" :loading="loading"
show-index density="comfortable" class="elevation-1" :header-props="{ class: 'custom-header' }">
@ -95,8 +93,6 @@
</v-data-table>
</v-window-item>
</v-window>
</v-card-text>
</v-card>
</template>
<script>

View file

@ -3,6 +3,15 @@ import { defineComponent } from 'vue';
import axios from 'axios';
import Swal from 'sweetalert2';
interface FileItem {
id: number;
filename: string;
filesize: number;
dateSubmit: string;
fileType: string;
fileBin?: string;
}
export default defineComponent({
name: 'archiveUpload',
props: {
@ -13,7 +22,7 @@ export default defineComponent({
data() {
return {
dialog: false, // برای باز و بسته کردن دیالوگ
fileStack: [],
fileStack: [] as FileItem[],
des: '',
media: {
saved: [],
@ -26,6 +35,24 @@ export default defineComponent({
this.getFilesList();
},
methods: {
getFileIconColor(fileType: string): string {
if (!fileType) return 'grey';
const type = fileType.toLowerCase();
if (type.includes('pdf')) return 'red';
if (type.includes('word') || type.includes('doc')) return 'blue';
if (type.includes('excel') || type.includes('sheet')) return 'green';
if (type.includes('image')) return 'purple';
return 'grey';
},
getFileIcon(fileType: string): string {
if (!fileType) return 'mdi-file';
const type = fileType.toLowerCase();
if (type.includes('pdf')) return 'mdi-file-pdf-box';
if (type.includes('word') || type.includes('doc')) return 'mdi-file-word-box';
if (type.includes('excel') || type.includes('sheet')) return 'mdi-file-excel-box';
if (type.includes('image')) return 'mdi-file-image-box';
return 'mdi-file';
},
changeMedia(media) {
this.media = media;
},
@ -42,13 +69,15 @@ export default defineComponent({
}).then((resp) => {
this.media.added = [];
this.fileStack = resp.data;
this.fileStack.forEach((item) => {
this.fileStack.forEach((item: FileItem) => {
if (item.fileType && item.fileType.startsWith('image/')) {
axios
.post(`${this.$filters.getApiUrl()}/api/archive/file/get/${item.id}`, { responseType: 'arraybuffer' })
.get(`${this.$filters.getApiUrl()}/api/archive/file/get/${item.id}`, { responseType: 'arraybuffer' })
.then((response) => {
const b64 = btoa(String.fromCharCode(...new Uint8Array(response.data)));
item.fileBin = `data:${response.headers['content-type']};base64,${b64}`;
});
}
});
});
},
@ -74,19 +103,30 @@ export default defineComponent({
});
},
downloadFile(item) {
axios
.post(`${this.$filters.getApiUrl()}/api/archive/file/get/${item.id}`, { responseType: 'arraybuffer' })
.then((response) => {
const blob = new Blob([response.data], { type: item.fileType });
axios.get(`${this.$filters.getApiUrl()}/api/archive/file/get/${item.id}`, {
responseType: 'blob'
}).then(response => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = item.filename;
link.href = url;
link.setAttribute('download', item.filename);
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(link.href);
link.remove();
window.URL.revokeObjectURL(url);
});
},
submitArchive() {
const formData = new FormData(document.getElementById('archive-file-upload'));
if (this.media.added.length === 0) {
Swal.fire({
text: 'لطفا حداقل یک فایل انتخاب کنید',
icon: 'warning',
confirmButtonText: 'قبول',
});
return;
}
const formData = new FormData(document.getElementById('archive-file-upload') as HTMLFormElement);
axios
.post('/api/archive/file/save', formData, {
headers: {
@ -133,7 +173,7 @@ export default defineComponent({
</v-btn>
<!-- دیالوگ آرشیو -->
<v-dialog v-model="dialog" max-width="800" persistent>
<v-dialog v-model="dialog" max-width="800" scrollable>
<v-card>
<v-toolbar color="grey-lighten-4" flat>
<v-toolbar-title>
@ -170,17 +210,27 @@ export default defineComponent({
outlined
name="des"
class="mt-2"
></v-text-field>
<v-btn type="submit" color="success" class="mt-2">
<v-icon left>mdi-content-save</v-icon>
بارگذاری فایلها
hide-details
>
<template v-slot:append>
<v-btn
type="submit"
color="success"
icon
variant="flat"
class="ml-2"
height="100%"
>
<v-icon>mdi-content-save</v-icon>
<v-tooltip activator="parent" location="bottom">
ثبت بارگذاری و ذخیره فایلها
</v-tooltip>
</v-btn>
</template>
</v-text-field>
</form>
</v-col>
</v-row>
<v-divider class="my-4"></v-divider>
<!-- لیست فایلها -->
<v-row>
<v-col cols="12">
@ -190,7 +240,7 @@ export default defineComponent({
<tr>
<th class="text-center">پیشنمایش</th>
<th class="text-center">نام فایل</th>
<th class="text-center">سایز فایل (مگابایت)</th>
<th class="text-center">سایز (MB)</th>
<th class="text-center">تاریخ</th>
<th class="text-center">عملیات</th>
</tr>
@ -198,18 +248,37 @@ export default defineComponent({
<tbody>
<tr v-for="item in fileStack" :key="item.id">
<td class="text-center">
<v-img :src="item.fileBin" max-width="50" max-height="50" class="mx-auto" alt="پیش‌نمایش" />
<template v-if="item.fileType && item.fileType.startsWith('image/')">
<v-img
:src="item.fileBin"
max-width="50"
max-height="50"
class="mx-auto"
alt="پیش‌نمایش"
cover
/>
</template>
<template v-else>
<v-icon
size="50"
:color="getFileIconColor(item.fileType)"
>
{{ getFileIcon(item.fileType) }}
</v-icon>
</template>
</td>
<td class="text-center">{{ item.filename }}</td>
<td class="text-center">{{ item.filesize }}</td>
<td class="text-center">{{ item.dateSubmit }}</td>
<td class="text-center">
<v-btn icon small color="primary" @click="downloadFile(item)">
<div class="d-flex justify-center">
<v-btn variant="text" color="primary" @click="downloadFile(item)" class="px-1">
<v-icon>mdi-download</v-icon>
</v-btn>
<v-btn icon small color="error" class="ml-2" @click="deleteItem(item)">
<v-btn variant="text" color="error" @click="deleteItem(item)" class="px-1">
<v-icon>mdi-trash-can</v-icon>
</v-btn>
</div>
</td>
</tr>
<tr v-if="fileStack.length === 0">
@ -226,4 +295,8 @@ export default defineComponent({
<style scoped>
/* استایل‌های اضافی اگه نیاز باشه */
:deep(.v-table .v-table__wrapper > table > thead > tr > th) {
background-color: #1d90ff !important;
color: white !important;
}
</style>

View file

@ -1,121 +1,99 @@
<template>
<div class="block block-content-full ">
<div id="fixed-header" class="block-header block-header-default bg-gray-light pt-2 pb-1">
<h3 class="block-title text-primary-dark">
<button @click="$router.back()" type="button" class="float-start d-none d-sm-none d-md-block btn btn-sm btn-link text-warning">
<i class="fa fw-bold fa-arrow-right"></i>
</button>
<i class="fa fa-book"></i>
لیست انتقالها
</h3>
<div class="block-options">
<router-link title="افزودن سند انتقال جدید" to="/acc/transfer/mod/" class="block-options-item">
<span class="fa fa-plus fw-bolder"></span>
</router-link>
</div>
</div>
<div class="block-content pt-1 pb-3">
<div class="row">
<div class="col-sm-12 col-md-12 m-0 p-0">
<div class="mb-1">
<div class="input-group input-group-sm">
<span class="input-group-text"><i class="fa fa-search"></i></span>
<input v-model="searchValue" class="form-control" type="text" placeholder="جست و جو ...">
</div>
</div>
<EasyDataTable table-class-name="customize-table" show-index alternating :search-value="searchValue" :headers="headers" :items="items"
theme-color="#1d90ff" header-text-direction="center" body-text-direction="center"
rowsPerPageMessage="تعداد سطر" emptyMessage="اطلاعاتی برای نمایش وجود ندارد" rowsOfPageSeparatorMessage="از"
:loading="loading">
<template #item-operation="{ code, type }">
<div class="dropdown-center">
<button aria-expanded="false" aria-haspopup="true" class="btn btn-sm btn-link"
data-bs-toggle="dropdown" id="dropdown-align-center-alt-primary" type="button">
<i class="fa-solid fa-ellipsis"></i>
</button>
<div aria-labelledby="dropdown-align-center-outline-primary" class="dropdown-menu dropdown-menu-end"
style="">
<router-link class="dropdown-item" :to="'/acc/accounting/view/' + code">
<i class="fa fa-file text-success pe-2"></i>
<v-toolbar color="toolbar" title="انتقالات">
<template v-slot:prepend>
<v-tooltip :text="$t('dialog.back')" location="bottom">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" @click="$router.back()" class="d-none d-sm-flex" variant="text"
icon="mdi-arrow-right" />
</template>
</v-tooltip>
</template>
<v-spacer></v-spacer>
<v-tooltip :text="$t('dialog.add_new_transfer')" location="bottom">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" icon variant="text" color="primary" :to="'/acc/transfer/mod/'">
<v-icon>mdi-plus</v-icon>
</v-btn>
</template>
</v-tooltip>
</v-toolbar>
<v-text-field v-model="searchValue" :rounded="false" prepend-inner-icon="mdi-magnify" variant="outlined" density="compact" hide-details
placeholder="جست و جو ..." class=""></v-text-field>
<v-data-table :headers="headers" :items="items" :search="searchValue" :loading="loading" density="comfortable" hover
:header-props="{ class: 'custom-header' }">
<template v-slot:item.operation="{ item }">
<v-menu>
<template v-slot:activator="{ props }">
<v-btn icon variant="text" v-bind="props">
<v-icon>mdi-dots-vertical</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item :to="'/acc/accounting/view/' + item.code" prepend-icon="mdi-file-document text-success">
سند حسابداری
</router-link>
<!-- Button trigger modal -->
<router-link :to="'/acc/transfer/mod/' + code" class="dropdown-item">
<i class="fa fa-eye text-primary pe-2"></i>
</v-list-item>
<v-list-item :to="'/acc/transfer/mod/' + item.code" prepend-icon="mdi-eye text-primary">
مشاهده
</router-link>
<router-link :to="'/acc/transfer/mod/' + code" class="dropdown-item">
<i class="fa fa-edit pe-2"></i>
</v-list-item>
<v-list-item :to="'/acc/transfer/mod/' + item.code" prepend-icon="mdi-pencil">
ویرایش
</router-link>
<button type="button" @click="deleteItem(code)" class="dropdown-item text-danger">
<i class="fa fa-trash pe-2"></i>
</v-list-item>
<v-list-item @click="deleteItem(item.code)" prepend-icon="mdi-delete text-error">
حذف
</button>
</div>
</div>
</v-list-item>
</v-list>
</v-menu>
</template>
<template #item-fromType="{ fromType, fromObject }">
<label v-if="fromType == 'bank'">حساب بانکی: {{ fromObject }}</label>
<label v-if="fromType == 'salary'">تنخواه گردان: {{ fromObject }}</label>
<label v-if="fromType == 'cashDesk'">صندوق: {{ fromObject }}</label>
<template v-slot:item.fromType="{ item }">
<span v-if="item.fromType === 'bank'">حساب بانکی: {{ item.fromObject }}</span>
<span v-if="item.fromType === 'salary'">تنخواه گردان: {{ item.fromObject }}</span>
<span v-if="item.fromType === 'cashDesk'">صندوق: {{ item.fromObject }}</span>
</template>
<template #item-toType="{ toType, toObject }">
<label v-if="toType == 'bank'">حساب بانکی: {{ toObject }}</label>
<label v-if="toType == 'salary'">تنخواه گردان: {{ toObject }}</label>
<label v-if="toType == 'cashDesk'">صندوق: {{ toObject }}</label>
<template v-slot:item.toType="{ item }">
<span v-if="item.toType === 'bank'">حساب بانکی: {{ item.toObject }}</span>
<span v-if="item.toType === 'salary'">تنخواه گردان: {{ item.toObject }}</span>
<span v-if="item.toType === 'cashDesk'">صندوق: {{ item.toObject }}</span>
</template>
<template #item-code="{ code }">
<router-link class="btn-link" :to="'/acc/accounting/view/' + code">
{{ code }}
</router-link>
<template v-slot:item.code="{ item }">
<v-btn variant="text" :to="'/acc/accounting/view/' + item.code" class="text-none">
{{ item.code }}
</v-btn>
</template>
</EasyDataTable>
</div>
</div>
</div>
</div>
</v-data-table>
</template>
<script>
import axios from "axios";
import Swal from "sweetalert2";
import { ref } from "vue";
export default {
name: "list",
components: {
},
data: () => {
return {
showTransferModal: {},
transferQuickDoc:{},
data: () => ({
searchValue: '',
loading: ref(true),
items: [],
headers: [
{ text: "عملیات", value: "operation" },
{ text: "شماره سند", value: "code", sortable: true },
{ text: "تاریخ", value: "date", sortable: true },
{ text: "از", value: "fromType", sortable: true },
{ text: "به", value: "toType", sortable: true },
{ text: "مبلغ", value: "amount", sortable: true },
{ text: "شرح", value: "des", sortable: true },
{ text: "ثبت کننده", value: "submitter", sortable: true },
{ title: "عملیات", key: "operation", sortable: false },
{ title: "شماره سند", key: "code", sortable: true },
{ title: "تاریخ", key: "date", sortable: true },
{ title: "از", key: "fromType", sortable: true },
{ title: "به", key: "toType", sortable: true },
{ title: "مبلغ", key: "amount", sortable: true },
{ title: "شرح", key: "des", sortable: true },
{ title: "ثبت کننده", key: "submitter", sortable: true },
]
}
},
}),
methods: {
showModal(code) {
var myModal = bootstrap.Modal.getOrCreateInstance(document.getElementById('quickTransferView'));
myModal.show();
},
hideModal() {
var myModal = bootstrap.Modal.getOrCreateInstance(document.getElementById('quickTransferView'));
myModal.hide();
},
loadData() {
axios.post('/api/transfer/search',)
axios.post('/api/transfer/search')
.then((response) => {
this.items = response.data;
this.items.forEach((item) => {
@ -131,20 +109,12 @@ export default {
confirmButtonText: 'بله',
cancelButtonText: `خیر`,
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
axios.post('/api/accounting/remove', {
'code': code
}
).then((response) => {
}).then((response) => {
if (response.data.result == 1) {
let index = 0;
for (let z = 0; z < this.items.length; z++) {
index++;
if (this.items[z]['code'] == code) {
this.items.splice(index - 1, 1);
}
}
this.items = this.items.filter(item => item.code !== code);
Swal.fire({
text: 'سند انتقال با موفقیت حذف شد.',
icon: 'success',

View file

@ -1,270 +1,122 @@
<template>
<div class="block block-content-full ">
<div id="fixed-header" class="block-header block-header-default bg-gray-light pt-2 pb-1">
<h3 class="block-title text-primary-dark">
<button @click="$router.back()" type="button"
class="float-start d-none d-sm-none d-md-block btn btn-sm btn-link text-warning">
<i class="fa fw-bold fa-arrow-right"></i>
</button>
انتقال
</h3>
<div class="block-options">
<v-toolbar color="toolbar" :title="$t('drawer.transfer')">
<template v-slot:prepend>
<v-tooltip :text="$t('dialog.back')" location="bottom">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" @click="$router.back()" class="d-none d-sm-flex" variant="text"
icon="mdi-arrow-right" />
</template>
</v-tooltip>
</template>
<v-spacer></v-spacer>
<archive-upload v-if="this.$route.params.id != ''" :docid="this.$route.params.id" doctype="transfer"
cat="transfer"></archive-upload>
<button @click="save()" type="button" class="btn btn-sm btn-alt-primary"><i class="fa fa-save"></i> ثبت</button>
</div>
</div>
<div class="block-content py-3 vl-parent">
<loading color="blue" loader="dots" v-model:active="isLoading" :is-full-page="false" />
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-6">
<div class="form-control">
<label class="form-label">تاریخ:</label>
<date-picker class="" v-model="this.date" format="jYYYY/jMM/jDD" display-format="jYYYY/jMM/jDD"
:min="this.year.start" :max="this.year.end" />
</div>
</div>
<div class="col-sm-12 col-md-6">
<div class="form-floating mb-4">
<input v-model="this.des" class="form-control" type="text">
<label class="form-label">توضیحات</label>
</div>
</div>
</div>
<hr>
<div class="row">
<div class="col-sm-12 col-md-6">
<h3>از:</h3>
<div class="btn-group d-flex" role="group" aria-label="Basic radio toggle button group">
<input :checked="this.sideOne.content == 'bank'" @change="this.changeFrom('bank')" type="radio"
class="btn-check" name="btnradio" id="btnradio1" autocomplete="off" checked>
<label class="btn btn-outline-primary" for="btnradio1">بانک</label>
<v-tooltip :text="$t('dialog.save')" location="bottom">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" color="primary" @click="save()" variant="text" icon="mdi-content-save" />
</template>
</v-tooltip>
<input :checked="this.sideOne.content == 'cashdesk'" @change="this.changeFrom('cashdesk')" type="radio"
v-model="this.sideOne.content" class="btn-check" name="btnradio" id="btnradio2" autocomplete="off">
<label class="btn btn-outline-primary" for="btnradio2">صندوق</label>
</v-toolbar>
<v-container>
<v-row>
<v-col cols="12" md="6">
<Hdatepicker v-model="date" label="تاریخ" />
</v-col>
<v-col cols="12" md="6">
<v-text-field v-model="this.des" label="توضیحات" variant="outlined"></v-text-field>
</v-col>
</v-row>
<input :checked="this.sideOne.content == 'salary'" @change="this.changeFrom('salary')" type="radio"
class="btn-check" name="btnradio" id="btnradio3" autocomplete="off">
<label class="btn btn-outline-primary" for="btnradio3">تنخواه</label>
</div>
<div class="row mt-2">
<div class="col-12">
<div v-if="this.sideOne.content == 'bank'" class="">
<label class="form-label">بانک</label>
<div class="form-floating mb-2">
<v-cob dir="rtl" :options="banks" label="name" v-model="this.sideOne.bank">
<template #no-options="{ search, searching, loading }">
نتیجهای یافت نشد!
</template>
<template #option="option">
<div class="row">
<div class="col-12">
<i class="fa fa-bank"></i>
{{ option.name }}
</div>
<div class="col-12">
موجودی:
{{ $filters.formatNumber(option.balance) }}
<span class="text-danger" v-if="option.balance < 0">بدهکار</span>
<span class="text-success" v-if="option.balance > 0">بستانکار</span>
</div>
</div>
</template>
</v-cob>
<v-row>
<v-col cols="12" md="6">
<h3 class="text-primary text-h6 mb-4">از:</h3>
<v-btn-group class="divided mb-4" :border="true">
<v-btn :color="sideOne.type === 'bank' ? 'primary' : 'outlined'" @click="changeFrom('bank')">بانک</v-btn>
<v-btn :color="sideOne.type === 'cashdesk' ? 'primary' : 'outlined'"
@click="changeFrom('cashdesk')">صندوق</v-btn>
<v-btn :color="sideOne.type === 'salary' ? 'primary' : 'outlined'"
@click="changeFrom('salary')">تنخواه</v-btn>
</v-btn-group>
</div>
</div>
<div v-if="this.sideOne.content == 'cashdesk'" class="">
<label class="form-label">صندوق</label>
<div class="form-floating mb-2">
<v-cob dir="rtl" :options="cashdesks" label="name" v-model="this.sideOne.cashdesk">
<template #no-options="{ search, searching, loading }">
نتیجهای یافت نشد!
</template>
<template #option="option">
<div class="row">
<div class="col-12">
<i class="fa fa-bank"></i>
{{ option.name }}
</div>
<div class="col-12">
موجودی:
{{ $filters.formatNumber(option.balance) }}
<span class="text-danger" v-if="option.balance < 0">بدهکار</span>
<span class="text-success" v-if="option.balance > 0">بستانکار</span>
</div>
</div>
</template>
</v-cob>
</div>
</div>
<div v-if="this.sideOne.content == 'salary'" class="">
<label class="form-label">تنخواه گردان</label>
<div class="form-floating mb-2">
<v-cob dir="rtl" :options="salarys" label="name" v-model="this.sideOne.salary">
<template #no-options="{ search, searching, loading }">
نتیجهای یافت نشد!
</template>
<template #option="option">
<div class="row">
<div class="col-12">
<i class="fa fa-bank"></i>
{{ option.name }}
</div>
<div class="col-12">
موجودی:
{{ $filters.formatNumber(option.balance) }}
<span class="text-danger" v-if="option.balance < 0">بدهکار</span>
<span class="text-success" v-if="option.balance > 0">بستانکار</span>
</div>
</div>
</template>
</v-cob>
</div>
</div>
<div class="form-floating mb-2">
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="this.sideOne.bs" />
<label class="form-label">مبلغ</label>
</div>
<div class="form-floating mb-2">
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="this.sideOne.tax" />
<label class="form-label">کارمزد خدمات بانکی</label>
</div>
<div class="form-floating mb-2">
<input v-model="this.sideOne.reference" class="form-control" type="text">
<label class="form-label">ارجاع</label>
</div>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<h3>به:</h3>
<div class="btn-group d-flex" role="group" aria-label="Basic radio toggle button group">
<input v-model="this.sideTwo.content" :checked="this.sideTwo.content == 'bank'"
@change="this.changeDes('bank')" type="radio" class="btn-check" name="btnradio1" id="btnradio4"
autocomplete="off" checked>
<label class="btn btn-outline-warning" for="btnradio4">بانک</label>
<v-row>
<v-col cols="12">
<v-select :hide-details="false" v-if="sideOne.type === 'bank'" v-model="sideOne.id" :items="banks"
item-title="name" item-value="id" label="بانک" variant="outlined" :item-props="bankItemProps"></v-select>
<input v-model="this.sideTwo.content" :checked="this.sideTwo.content == 'cashdesk'"
@change="this.changeDes('cashdesk')" type="radio" class="btn-check" name="btnradio1" id="btnradio5"
autocomplete="off">
<label class="btn btn-outline-warning" for="btnradio5">صندوق</label>
<v-select :hide-details="false" v-if="sideOne.type === 'cashdesk'" v-model="sideOne.id"
:items="cashdesks" item-title="name" item-value="id" label="صندوق" variant="outlined"
:item-props="cashdeskItemProps"></v-select>
<input v-model="this.sideTwo.content" :checked="this.sideTwo.content == 'salary'"
@change="this.changeDes('salary')" type="radio" class="btn-check" name="btnradio1" id="btnradio6"
autocomplete="off">
<label class="btn btn-outline-warning" for="btnradio6">تنخواه</label>
</div>
<div class="row mt-2">
<div class="col-12">
<div v-if="this.sideTwo.content == 'bank'" class="">
<label class="form-label">بانک</label>
<div class="form-floating mb-2">
<v-cob dir="rtl" :options="banks" label="name" v-model="this.sideTwo.bank">
<template #no-options="{ search, searching, loading }">
نتیجهای یافت نشد!
</template>
<template #option="option">
<div class="row">
<div class="col-12">
<i class="fa fa-bank"></i>
{{ option.name }}
</div>
<div class="col-12">
موجودی:
{{ $filters.formatNumber(option.balance) }}
<span class="text-danger" v-if="option.balance < 0">بدهکار</span>
<span class="text-success" v-if="option.balance > 0">بستانکار</span>
</div>
</div>
</template>
</v-cob>
</div>
</div>
<div v-if="this.sideTwo.content == 'cashdesk'" class="">
<label class="form-label">صندوق</label>
<div class="form-floating mb-2">
<v-cob dir="rtl" :options="cashdesks" label="name" v-model="this.sideTwo.cashdesk">
<template #no-options="{ search, searching, loading }">
نتیجهای یافت نشد!
</template>
<template #option="option">
<div class="row">
<div class="col-12">
<i class="fa fa-bank"></i>
{{ option.name }}
</div>
<div class="col-12">
موجودی:
{{ $filters.formatNumber(option.balance) }}
<span class="text-danger" v-if="option.balance < 0">بدهکار</span>
<span class="text-success" v-if="option.balance > 0">بستانکار</span>
</div>
</div>
</template>
</v-cob>
</div>
</div>
<div v-if="this.sideTwo.content == 'salary'" class="">
<label class="form-label">تنخواه گردان</label>
<div class="form-floating mb-2">
<v-cob dir="rtl" :options="salarys" label="name" v-model="this.sideTwo.salary">
<template #no-options="{ search, searching, loading }">
نتیجهای یافت نشد!
</template>
<template #option="option">
<div class="row">
<div class="col-12">
<i class="fa fa-bank"></i>
{{ option.name }}
</div>
<div class="col-12">
موجودی:
{{ $filters.formatNumber(option.balance) }}
<span class="text-danger" v-if="option.balance < 0">بدهکار</span>
<span class="text-success" v-if="option.balance > 0">بستانکار</span>
</div>
</div>
</template>
</v-cob>
</div>
</div>
<div class="form-floating mb-2">
<money3 readonly="readonly" v-bind="currencyConfig" min=0 class="form-control"
v-model="this.sideTwo.bd" />
<label class="form-label">مبلغ</label>
</div>
<div class="form-floating mb-2">
<money3 readonly="readonly" v-bind="currencyConfig" min=0 class="form-control"
v-model="this.sideTwo.tax" />
<label class="form-label">کارمزد خدمات بانکی</label>
</div>
<div class="form-floating mb-2">
<input v-model="this.sideTwo.reference" class="form-control" type="text">
<label class="form-label">ارجاع</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<v-select :hide-details="false" v-if="sideOne.type === 'salary'" v-model="sideOne.id"
:items="salarys" item-title="name" item-value="id" label="تنخواه گردان" variant="outlined"
:item-props="salaryItemProps"></v-select>
<Hnumberinput :hide-details="false" v-model="sideOne.bs" label="مبلغ" variant="outlined" />
<Hnumberinput :hide-details="false" v-model="sideOne.tax" label="کارمزد خدمات بانکی" variant="outlined" />
<v-text-field :hide-details="false" v-model="sideOne.reference" label="ارجاع"
variant="outlined"></v-text-field>
<v-text-field v-model="sideOne.des" label="شرح" variant="outlined"></v-text-field>
</v-col>
</v-row>
</v-col>
<v-col cols="12" md="6">
<h3 class="text-primary text-h6 mb-4">به:</h3>
<v-btn-group class="divided mb-4" :border="true">
<v-btn :color="sideTwo.type === 'bank' ? 'primary' : 'outlined'" @click="changeDes('bank')">بانک</v-btn>
<v-btn :color="sideTwo.type === 'cashdesk' ? 'primary' : 'outlined'"
@click="changeDes('cashdesk')">صندوق</v-btn>
<v-btn :color="sideTwo.type === 'salary' ? 'primary' : 'outlined'"
@click="changeDes('salary')">تنخواه</v-btn>
</v-btn-group>
<v-row>
<v-col cols="12">
<v-select :hide-details="false" v-if="sideTwo.type === 'bank'" v-model="sideTwo.id" :items="banks"
item-title="name" item-value="id" label="بانک" variant="outlined" :item-props="bankItemProps"></v-select>
<v-select :hide-details="false" v-if="sideTwo.type === 'cashdesk'" v-model="sideTwo.id"
:items="cashdesks" item-title="name" item-value="id" label="صندوق" variant="outlined"
:item-props="cashdeskItemProps"></v-select>
<v-select :hide-details="false" v-if="sideTwo.type === 'salary'" v-model="sideTwo.id"
:items="salarys" item-title="name" item-value="id" label="تنخواه گردان" variant="outlined"
:item-props="salaryItemProps"></v-select>
<Hnumberinput :hide-details="false" v-model="sideTwo.bd" label="مبلغ" variant="outlined" readonly />
<Hnumberinput :hide-details="false" v-model="sideTwo.tax" label="کارمزد خدمات بانکی" variant="outlined"
readonly />
<v-text-field :hide-details="false" v-model="sideTwo.reference" label="ارجاع"
variant="outlined"></v-text-field>
<v-text-field v-model="sideTwo.des" label="شرح" variant="outlined"></v-text-field>
</v-col>
</v-row>
</v-col>
</v-row>
</v-container>
</template>
<script>
import axios from "axios";
import Loading from "vue-loading-overlay";
import Swal from "sweetalert2";
import archiveUpload from "../component/archive/archiveUpload.vue";
import Hdatepicker from "../../../components/forms/Hdatepicker.vue";
import Hnumberinput from "../../../components/forms/Hnumberinput.vue";
export default {
name: "mod",
components: {
Loading,
archiveUpload
archiveUpload,
Hdatepicker,
Hnumberinput
},
watch: {
'sideOne.bs': function () {
@ -274,48 +126,30 @@ export default {
this.sideTwo.tax = this.sideOne.tax;
},
'sideOne.bank': function () {
this.sideOne.id = this.sideOne.bank.id;
this.sideOne.id = this.sideOne.bank?.id;
},
'sideOne.salary': function () {
this.sideOne.id = this.sideOne.salary.id;
this.sideOne.id = this.sideOne.salary?.id;
},
'sideOne.cashdesk': function () {
this.sideOne.id = this.sideOne.cashdesk.id;
this.sideOne.id = this.sideOne.cashdesk?.id;
},
'sideTwo.bank': function () {
this.sideTwo.id = this.sideTwo.bank.id;
this.sideTwo.id = this.sideTwo.bank?.id;
},
'sideTwo.salary': function () {
this.sideTwo.id = this.sideTwo.salary.id;
this.sideTwo.id = this.sideTwo.salary?.id;
},
'sideTwo.cashdesk': function () {
this.sideTwo.id = this.sideTwo.cashdesk.id;
this.sideTwo.id = this.sideTwo.cashdesk?.id;
},
},
data: () => {
return {
isLoading: false,
currencyConfig: {
masked: false,
prefix: '',
suffix: 'ریال',
thousands: ',',
decimal: '.',
precision: 0,
disableNegative: false,
disabled: false,
min: 0,
max: null,
allowBlank: false,
minimumNumberOfCharacters: 0,
shouldRound: true,
focusOnRight: false,
},
data: () => ({
year: {},
date: '',
des: '',
sideOne: {
content: 'bank',
type: 'bank',
bank: undefined,
cashdesk: undefined,
salary: undefined,
@ -323,12 +157,11 @@ export default {
bd: 0,
tax: 0,
reference: '',
table: 5,
id: '',
des: 'انتقال بین حساب‌های بانکی،صندوق،تنخواه گردان'
},
sideTwo: {
content: 'bank',
type: 'bank',
bank: undefined,
cashdesk: undefined,
salary: undefined,
@ -336,16 +169,32 @@ export default {
bd: 0,
tax: 0,
reference: '',
table: 5,
id: '',
des: 'انتقال بین حساب‌های بانکی،صندوق،تنخواه گردان'
des: ''
},
banks: [],
cashdesks: [],
salarys: []
}),
methods: {
bankItemProps(item) {
return {
title: item.name,
subtitle: `موجودی: ${this.$filters.formatNumber(item.balance)} ${item.balance < 0 ? 'بدهکار' : 'بستانکار'}`
}
},
cashdeskItemProps(item) {
return {
title: item.name,
subtitle: `موجودی: ${this.$filters.formatNumber(item.balance)} ${item.balance < 0 ? 'بدهکار' : 'بستانکار'}`
}
},
salaryItemProps(item) {
return {
title: item.name,
subtitle: `موجودی: ${this.$filters.formatNumber(item.balance)} ${item.balance < 0 ? 'بدهکار' : 'بستانکار'}`
}
},
methods: {
loadData() {
axios.post('/api/bank/list').then((response) => {
this.banks = response.data;
@ -356,7 +205,6 @@ export default {
axios.post('/api/salary/list').then((response) => {
this.salarys = response.data;
});
//load year
axios.post('/api/year/get').then((response) => {
this.year = response.data;
this.date = response.data.now;
@ -365,10 +213,12 @@ export default {
axios.post('/api/accounting/doc/get', {
code: this.$route.params.id
}).then((response) => {
this.des = response.data.doc.des;
this.date = response.data.doc.date;
let taxAmount = 0;
response.data.rows.forEach((item, key) => {
if (item.refCode == '108') {
//item is tax
taxAmount = item.bd;
response.data.rows[key].id = 'ignore';
}
@ -379,61 +229,65 @@ export default {
response.data.rows[key].id = 'ignore';
}
});
response.data.rows.forEach((item, key) => {
if (item.bs != 0 && item.tableCode == 5 && item.id != 'ignore') {
response.data.rows.forEach((item) => {
if (item.bs != 0 && item.id != 'ignore') {
let opt = {
content: '',
type: '',
bank: undefined,
cashdesk: undefined,
salary: undefined,
bs: item.bs,
bd: item.bd,
tax: taxAmount,
reference: '',
table: 5,
reference: item.referral,
id: '',
des: item.des
};
if (item.bank != undefined) {
if (item.bank) {
opt.bank = item.bank;
opt.content = 'bank';
opt.type = 'bank';
opt.id = item.bank.id;
}
else if (item.cashdesk != undefined) {
else if (item.cashdesk) {
opt.cashdesk = item.cashdesk;
opt.content = 'cashdesk';
opt.type = 'cashdesk';
opt.id = item.cashdesk.id;
}
else if (item.salary != undefined) {
else if (item.salary) {
opt.salary = item.salary;
opt.content = 'salary';
opt.type = 'salary';
opt.id = item.salary.id;
}
this.sideOne = opt
this.sideOne = opt;
}
if (parseInt(item.bd) != 0 && parseInt(item.tableCode) == 5 && item.id != 'ignore') {
else if (parseInt(item.bd) != 0 && item.id != 'ignore') {
let opt = {
content: '',
type: '',
bank: undefined,
cashdesk: undefined,
salary: undefined,
bs: item.bs,
bd: item.bd,
tax: taxAmount,
reference: '',
table: 5,
reference: item.referral,
id: '',
des: item.des
};
if (item.bank != undefined) {
if (item.bank) {
opt.bank = item.bank;
opt.content = 'bank';
opt.type = 'bank';
opt.id = item.bank.id;
}
else if (item.cashdesk != undefined) {
else if (item.cashdesk) {
opt.cashdesk = item.cashdesk;
opt.content = 'cashdesk';
opt.type = 'cashdesk';
opt.id = item.cashdesk.id;
}
else if (item.salary != undefined) {
else if (item.salary) {
opt.salary = item.salary;
opt.content = 'salary';
opt.type = 'salary';
opt.id = item.salary.id;
}
this.sideTwo = opt;
}
@ -448,89 +302,82 @@ export default {
icon: 'error',
confirmButtonText: 'قبول'
});
return;
}
else if (
(this.sideOne.content == 'bank' && this.sideOne.bank == undefined) ||
(this.sideOne.content == 'salary' && this.sideOne.salary == undefined) ||
(this.sideOne.content == 'cashdesk' && this.sideOne.cashdesk == undefined)
if (
(this.sideOne.type == 'bank' && !this.sideOne.id) ||
(this.sideOne.type == 'salary' && !this.sideOne.id) ||
(this.sideOne.type == 'cashdesk' && !this.sideOne.id)
) {
Swal.fire({
text: 'انتقال دهنده انتخاب نشده است.',
icon: 'error',
confirmButtonText: 'قبول'
});
return;
}
else if (
(this.sideTwo.content == 'bank' && this.sideTwo.bank == undefined) ||
(this.sideTwo.content == 'salary' && this.sideTwo.salary == undefined) ||
(this.sideTwo.content == 'cashdesk' && this.sideTwo.cashdesk == undefined)
if (
(this.sideTwo.type == 'bank' && !this.sideTwo.id) ||
(this.sideTwo.type == 'salary' && !this.sideTwo.id) ||
(this.sideTwo.type == 'cashdesk' && !this.sideTwo.id)
) {
Swal.fire({
text: 'انتقال گیرنده انتخاب نشده است.',
icon: 'error',
confirmButtonText: 'قبول'
});
return;
}
else {
let PushData = {
date: this.date,
des: this.des,
type: 'transfer',
update: this.$route.params.id,
rows: [
{
bs: this.sideOne.bs,
bd: 0,
type: this.sideOne.content,
bank: this.sideOne.bank,
salary: this.sideOne.salary,
cashdesk: this.sideOne.cashdesk,
table: this.sideOne.table,
type: this.sideOne.type,
id: this.sideOne.id,
referral: this.sideOne.reference,
des: this.sideOne.des,
referral: this.sideOne.reference
},
{
bd: this.sideTwo.bd,
bs: 0,
type: this.sideTwo.content,
bank: this.sideTwo.bank,
salary: this.sideTwo.salary,
cashdesk: this.sideTwo.cashdesk,
table: this.sideTwo.table,
type: this.sideTwo.type,
id: this.sideTwo.id,
referral: this.sideTwo.reference,
des: this.sideTwo.des,
referral: this.sideTwo.reference
}
]
};
if (this.sideOne.tax != 0) {
PushData.rows.push({
bd: this.sideOne.tax,
bs: 0,
type: 'calc',
table: 108,
des: 'کارمزد هزینه‌های بانکی'
});
PushData.rows.push({
bs: this.sideOne.tax,
bd: 0,
type: this.sideOne.content,
bank: this.sideOne.bank,
salary: this.sideOne.salary,
cashdesk: this.sideOne.cashdesk,
table: this.sideOne.table,
type: this.sideOne.type,
id: this.sideOne.id,
des: 'کارمزد هزینه‌های بانکی'
})
});
}
axios.post('/api/accounting/insert', PushData).then((response) => {
axios.post('/api/transfer/insert', PushData).then((response) => {
if (response.data.result == '1') {
Swal.fire({
text: 'سند انتقال با موفقیت ثبت شد.',
icon: 'success',
confirmButtonText: 'قبول'
}).then((res) => {
}).then(() => {
this.$router.push('/acc/transfer/list');
});
}
@ -542,20 +389,12 @@ export default {
});
}
});
}
},
changeDes(content) {
this.sideTwo.content = content;
if (content == ' bank') { this.sideTwo.table = 5; }
else if (content == ' salary') { this.sideTwo.table = 122; }
else if (content == ' cashdesk') { this.sideTwo.table = 121; }
changeDes(type) {
this.sideTwo.type = type;
},
changeFrom(content) {
this.sideOne.content = content;
if (content == ' bank') { this.sideOne.table = 5; }
else if (content == ' salary') { this.sideOne.table = 122; }
else if (content == ' cashdesk') { this.sideOne.table = 121; }
changeFrom(type) {
this.sideOne.type = type;
},
},
mounted() {
@ -564,4 +403,8 @@ export default {
}
</script>
<style scoped></style>
<style scoped>
.v-navigation-bar {
direction: rtl;
}
</style>