bug fix and add plugin transactions in admin panel

This commit is contained in:
Hesabix 2025-06-02 16:37:51 +00:00
parent 11239f06f1
commit 10bd782904
13 changed files with 582 additions and 292 deletions

View file

@ -377,4 +377,56 @@ class PluginController extends AbstractController
return $this->json($extractor->operationSuccess());
}
/**
* دریافت لیست تراکنش‌های افزونه‌ها (برای ادمین)
*
* @OA\Post(
* path="/api/admin/plugins/transactions",
* summary="دریافت لیست تراکنش‌های افزونه‌ها (ادمین)",
* tags={"Admin Plugins"},
* @OA\Response(
* response=200,
* description="لیست تراکنش‌ها",
* @OA\JsonContent(type="array", @OA\Items(ref="#/components/schemas/Plugin"))
* )
* )
*/
#[Route('/api/admin/plugins/transactions', name: 'api_admin_plugins_transactions', methods: ["POST"])]
public function api_admin_plugins_transactions(Access $access, Jdate $jdate, EntityManagerInterface $entityManager): JsonResponse
{
$this->checkAccess($access, 'ROLE_ADMIN');
$plugins = $entityManager->getRepository(Plugin::class)->findBy([], ['dateSubmit' => 'DESC']);
$result = [];
foreach ($plugins as $plugin) {
$pluginData = [
'id' => $plugin->getId(),
'des' => $plugin->getDes(),
'price' => $plugin->getPrice(),
'dateSubmit' => $jdate->jdate('Y/n/d', $plugin->getDateSubmit()),
'dateExpire' => $jdate->jdate('Y/n/d', $plugin->getDateExpire()),
'status' => $plugin->getStatus(),
'cardPan' => $plugin->getCardPan(),
'refID' => $plugin->getRefID()
];
// اضافه کردن نام کسب و کار
$business = $entityManager->getRepository('App\Entity\Business')->find($plugin->getBid());
if ($business) {
$pluginData['businessName'] = $business->getName();
}
// اضافه کردن نام خریدار
$submitter = $plugin->getSubmitter();
if ($submitter) {
$pluginData['submitterName'] = $submitter->getFullName();
}
$result[] = $pluginData;
}
return $this->json($result);
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Controller\Plugins\Hrm;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\PlugGhestaDoc;
use App\Entity\PlugGhestaItem;
use App\Entity\HesabdariDoc;
use App\Entity\Person;
use App\Service\Access;
use App\Service\Provider;
use App\Service\Printers;
use App\Entity\PrintOptions;
use App\Service\Log;
use App\Entity\Business;
class DocsController extends AbstractController
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
}

View file

@ -391,7 +391,7 @@ class PlugGhestaController extends AbstractController
'id' => $item->getId(),
'code' => $item->getMainDoc() ? $item->getMainDoc()->getCode() : null,
'firstGhestaDate' => $firstGhestaDate,
'amount' => $item->getProfitAmount(), // مبلغ کل شامل سود
'amount' => $item->getMainDoc() ? $item->getMainDoc()->getAmount() : 0, // مبلغ کل فاکتور
'profitAmount' => $item->getProfitAmount(),
'profitPercent' => $item->getProfitPercent(),
'profitType' => $item->getProfitType(),

View file

@ -116,6 +116,12 @@
<table style="width:100%;">
<tbody>
<tr style="text-align:center;">
<td class="">
<p>
<b>مبلغ کل فاکتور:</b>
{{ doc.mainDoc.amount|number_format }} ریال
</p>
</td>
<td class="">
<p>
<b>تعداد اقساط:</b>

View file

@ -546,6 +546,14 @@ const fa_lang = {
return_sell: "برگشت از فروش",
all_types: "همه موارد"
},
field: {
id: "شناسه",
date: "تاریخ",
employee: "کارمند",
amount: "مبلغ",
status: "وضعیت",
actions: "عملیات"
},
},
app: {
loading: "در حال بارگذاری...",

View file

@ -146,6 +146,14 @@ const router = createRouter({
'login': true
}
},
{
path: 'manager/plugins/transactions',
component: () => import('../views/user/manager/settings/pluginTransactions.vue'),
meta: {
'title': 'تراکنش‌های افزونه‌ها',
'login': true
}
},
{
path: 'manager/update-core',
component: () => import('../views/user/manager/settings/update-core.vue'),

View file

@ -109,11 +109,6 @@
<v-icon icon="mdi-file-edit"></v-icon>
</template>
</v-list-item>
<v-list-item class="text-dark" :title="$t('dialog.payment')" @click="onPayment(item)">
<template v-slot:prepend>
<v-icon icon="mdi-cash"></v-icon>
</template>
</v-list-item>
<v-list-item class="text-dark" :title="$t('dialog.delete')" @click="onDelete(item)">
<template v-slot:prepend>
<v-icon color="deep-orange-accent-4" icon="mdi-trash-can"></v-icon>
@ -343,10 +338,6 @@ export default defineComponent({
router.push(`/acc/plugins/ghesta/view/${item.id}`)
}
const onPayment = (item) => {
router.push(`/acc/plugins/ghesta/payment/${item.id}`)
}
onMounted(() => {
loadData()
})
@ -370,8 +361,7 @@ export default defineComponent({
onSearch,
onEdit,
onDelete,
onView,
onPayment
onView
}
}
})

View file

@ -632,112 +632,140 @@ export default {
return Math.round(monthlyInterest);
},
calculatedInstallments() {
if (!this.selectedInvoice || !this.installmentData.firstDate) {
return [];
if (!this.canCalculate) {
this.showMessage('لطفا تمام اطلاعات مورد نیاز را وارد کنید', 'error');
return;
}
const totalAmount = this.remainingAmount;
const prepayment = Number(this.installmentData.prepayment) || 0;
const remainingAmount = totalAmount - prepayment;
const interestRate = Number(this.installmentData.interestRate) || 0;
const interestType = this.installmentData.interestType;
if (this.isCalculating) {
return;
}
let count, monthlyPayment;
if (this.installmentData.calculationType === 'amount') {
monthlyPayment = Number(this.installmentData.installmentAmount);
if (monthlyPayment <= 0) {
this.installments = [];
return;
}
try {
this.isCalculating = true;
this.loading = true;
// محاسبه تعداد اقساط بر اساس مبلغ هر قسط
switch (interestType) {
case 'monthly': {
// برای سود ساده ماهانه
const monthlyInterest = interestRate / 100;
const principalPerMonth = remainingAmount / monthlyPayment;
const interestPerMonth = monthlyInterest;
count = Math.ceil(principalPerMonth / (1 - interestPerMonth));
break;
}
case 'yearly': {
// برای سود ساده سالانه
const yearlyInterest = interestRate / 100;
const monthlyInterest = yearlyInterest / 12;
const principalPerMonth = remainingAmount / monthlyPayment;
const interestPerMonth = monthlyInterest;
count = Math.ceil(principalPerMonth / (1 - interestPerMonth));
break;
}
default:
count = 0;
}
// حفظ وضعیت پرداخت اقساط موجود
const existingInstallments = this.installments.reduce((acc, item) => {
acc[item.number] = {
status: item.status,
hesabdariDoc: item.hesabdariDoc
};
return acc;
}, {});
// محدود کردن تعداد اقساط به یک عدد منطقی
count = Math.min(Math.max(count, 1), 360); // حداکثر 30 سال
} else {
count = Number(this.installmentData.count) || 0;
if (count <= 0) {
this.installments = [];
return;
}
const totalAmount = this.remainingAmount;
const prepayment = Number(this.installmentData.prepayment) || 0;
const remainingAmount = totalAmount - prepayment;
const interestRate = Number(this.installmentData.interestRate) || 0;
const interestType = this.installmentData.interestType;
switch (interestType) {
case 'monthly': {
const monthlyInterest = interestRate / 100;
const totalInterest = monthlyInterest * count;
monthlyPayment = (remainingAmount * (1 + totalInterest)) / count;
break;
let count, monthlyPayment;
if (this.installmentData.calculationType === 'amount') {
monthlyPayment = Number(this.installmentData.installmentAmount);
if (monthlyPayment <= 0) {
this.installments = [];
this.showMessage('مبلغ هر قسط باید بزرگتر از صفر باشد', 'error');
return;
}
case 'yearly': {
const yearlyInterest = interestRate / 100;
const monthlyInterest = yearlyInterest / 12;
const totalInterest = monthlyInterest * count;
monthlyPayment = (remainingAmount * (1 + totalInterest)) / count;
break;
// محاسبه تعداد اقساط بر اساس مبلغ هر قسط
switch (interestType) {
case 'monthly': {
const monthlyInterest = interestRate / 100;
const principalPerMonth = remainingAmount / monthlyPayment;
const interestPerMonth = monthlyInterest;
count = Math.ceil(principalPerMonth / (1 - interestPerMonth));
break;
}
case 'yearly': {
const yearlyInterest = interestRate / 100;
const monthlyInterest = yearlyInterest / 12;
const principalPerMonth = remainingAmount / monthlyPayment;
const interestPerMonth = monthlyInterest;
count = Math.ceil(principalPerMonth / (1 - interestPerMonth));
break;
}
default:
count = 0;
}
default:
monthlyPayment = 0;
}
}
// ایجاد اقساط
const newInstallments = [];
let currentDate = moment(this.installmentData.firstDate, 'jYYYY/jMM/jDD').toDate();
let remainingTotal = remainingAmount;
for (let i = 1; i <= count; i++) {
let installmentAmount;
if (i === count) {
installmentAmount = remainingTotal;
count = Math.min(Math.max(count, 1), 360);
} else {
installmentAmount = Math.round(monthlyPayment);
remainingTotal -= installmentAmount;
count = Number(this.installmentData.count) || 0;
if (count <= 0) {
this.installments = [];
this.showMessage('تعداد اقساط باید بزرگتر از صفر باشد', 'error');
return;
}
switch (interestType) {
case 'monthly': {
const monthlyInterest = interestRate / 100;
const totalInterest = monthlyInterest * count;
monthlyPayment = (remainingAmount * (1 + totalInterest)) / count;
break;
}
case 'yearly': {
const yearlyInterest = interestRate / 100;
const monthlyInterest = yearlyInterest / 12;
const totalInterest = monthlyInterest * count;
monthlyPayment = (remainingAmount * (1 + totalInterest)) / count;
break;
}
default:
monthlyPayment = 0;
}
}
newInstallments.push({
number: i,
amount: installmentAmount,
dueDate: moment(currentDate).format('jYYYY/jMM/jDD'),
status: 'پرداخت نشده',
latePaymentPenalty: this.installmentData.latePaymentPenalty
});
const newInstallments = [];
let currentDate = moment(this.installmentData.firstDate, 'jYYYY/jMM/jDD').toDate();
let remainingTotal = remainingAmount;
currentDate = moment(currentDate).add(1, 'month').toDate();
for (let i = 1; i <= count; i++) {
let installmentAmount;
if (i === count) {
installmentAmount = remainingTotal;
} else {
installmentAmount = Math.round(monthlyPayment);
remainingTotal -= installmentAmount;
}
const existingInstallment = existingInstallments[i];
newInstallments.push({
number: i,
amount: installmentAmount,
dueDate: moment(currentDate).format('jYYYY/jMM/jDD'),
status: existingInstallment ? existingInstallment.status : 'پرداخت نشده',
latePaymentPenalty: this.installmentData.latePaymentPenalty,
hesabdariDoc: existingInstallment ? existingInstallment.hesabdariDoc : null
});
currentDate = moment(currentDate).add(1, 'month').toDate();
}
if (prepayment > 0) {
const existingPrepayment = existingInstallments[0];
newInstallments.unshift({
number: 0,
amount: prepayment,
dueDate: moment().format('jYYYY/jMM/jDD'),
status: existingPrepayment ? existingPrepayment.status : 'پرداخت شده',
latePaymentPenalty: 0,
hesabdariDoc: existingPrepayment ? existingPrepayment.hesabdariDoc : null
});
}
this.installments = newInstallments;
this.showMessage('اقساط با موفقیت محاسبه شد', 'success');
} catch (error) {
console.error('خطا در محاسبه اقساط:', error);
this.showMessage('خطا در محاسبه اقساط', 'error');
} finally {
this.isCalculating = false;
this.loading = false;
}
if (prepayment > 0) {
newInstallments.unshift({
number: 0,
amount: prepayment,
dueDate: moment().format('jYYYY/jMM/jDD'),
status: 'پرداخت شده',
latePaymentPenalty: 0
});
}
this.installments = newInstallments;
},
dailyPenaltyAmount() {
if (!this.installmentData.installmentAmount) {
@ -762,6 +790,142 @@ export default {
this.snackbar.color = color;
this.snackbar.show = true;
},
calculateInstallments() {
if (!this.canCalculate) {
this.showMessage('لطفا تمام اطلاعات مورد نیاز را وارد کنید', 'error');
return;
}
if (this.isCalculating) {
return;
}
try {
this.isCalculating = true;
this.loading = true;
// حفظ وضعیت پرداخت اقساط موجود
const existingInstallments = this.installments.reduce((acc, item) => {
acc[item.number] = {
status: item.status,
hesabdariDoc: item.hesabdariDoc
};
return acc;
}, {});
const totalAmount = this.remainingAmount;
const prepayment = Number(this.installmentData.prepayment) || 0;
const remainingAmount = totalAmount - prepayment;
const interestRate = Number(this.installmentData.interestRate) || 0;
const interestType = this.installmentData.interestType;
let count, monthlyPayment;
if (this.installmentData.calculationType === 'amount') {
monthlyPayment = Number(this.installmentData.installmentAmount);
if (monthlyPayment <= 0) {
this.installments = [];
this.showMessage('مبلغ هر قسط باید بزرگتر از صفر باشد', 'error');
return;
}
// محاسبه تعداد اقساط بر اساس مبلغ هر قسط
switch (interestType) {
case 'monthly': {
const monthlyInterest = interestRate / 100;
const principalPerMonth = remainingAmount / monthlyPayment;
const interestPerMonth = monthlyInterest;
count = Math.ceil(principalPerMonth / (1 - interestPerMonth));
break;
}
case 'yearly': {
const yearlyInterest = interestRate / 100;
const monthlyInterest = yearlyInterest / 12;
const principalPerMonth = remainingAmount / monthlyPayment;
const interestPerMonth = monthlyInterest;
count = Math.ceil(principalPerMonth / (1 - interestPerMonth));
break;
}
default:
count = 0;
}
count = Math.min(Math.max(count, 1), 360);
} else {
count = Number(this.installmentData.count) || 0;
if (count <= 0) {
this.installments = [];
this.showMessage('تعداد اقساط باید بزرگتر از صفر باشد', 'error');
return;
}
switch (interestType) {
case 'monthly': {
const monthlyInterest = interestRate / 100;
const totalInterest = monthlyInterest * count;
monthlyPayment = (remainingAmount * (1 + totalInterest)) / count;
break;
}
case 'yearly': {
const yearlyInterest = interestRate / 100;
const monthlyInterest = yearlyInterest / 12;
const totalInterest = monthlyInterest * count;
monthlyPayment = (remainingAmount * (1 + totalInterest)) / count;
break;
}
default:
monthlyPayment = 0;
}
}
const newInstallments = [];
let currentDate = moment(this.installmentData.firstDate, 'jYYYY/jMM/jDD').toDate();
let remainingTotal = remainingAmount;
for (let i = 1; i <= count; i++) {
let installmentAmount;
if (i === count) {
installmentAmount = remainingTotal;
} else {
installmentAmount = Math.round(monthlyPayment);
remainingTotal -= installmentAmount;
}
const existingInstallment = existingInstallments[i];
newInstallments.push({
number: i,
amount: installmentAmount,
dueDate: moment(currentDate).format('jYYYY/jMM/jDD'),
status: existingInstallment ? existingInstallment.status : 'پرداخت نشده',
latePaymentPenalty: this.installmentData.latePaymentPenalty,
hesabdariDoc: existingInstallment ? existingInstallment.hesabdariDoc : null
});
currentDate = moment(currentDate).add(1, 'month').toDate();
}
if (prepayment > 0) {
const existingPrepayment = existingInstallments[0];
newInstallments.unshift({
number: 0,
amount: prepayment,
dueDate: moment().format('jYYYY/jMM/jDD'),
status: existingPrepayment ? existingPrepayment.status : 'پرداخت شده',
latePaymentPenalty: 0,
hesabdariDoc: existingPrepayment ? existingPrepayment.hesabdariDoc : null
});
}
this.installments = newInstallments;
this.showMessage('اقساط با موفقیت محاسبه شد', 'success');
} catch (error) {
console.error('خطا در محاسبه اقساط:', error);
this.showMessage('خطا در محاسبه اقساط', 'error');
} finally {
this.isCalculating = false;
this.loading = false;
}
},
async saveInvoice() {
if (!this.selectedInvoice) {
this.showMessage('لطفا یک فاکتور انتخاب کنید', 'error');
@ -833,6 +997,12 @@ export default {
},
editInstallment(item) {
// اگر قسط پرداخت شده باشد، اجازه ویرایش ندهیم
if (item.isPaid) {
this.showMessage('قسط پرداخت شده قابل ویرایش نیست', 'error');
return;
}
this.dialog = {
show: true,
title: 'ویرایش قسط',
@ -872,6 +1042,12 @@ export default {
},
deleteInstallment(item) {
// اگر قسط پرداخت شده باشد، اجازه حذف ندهیم
if (item.isPaid) {
this.showMessage('قسط پرداخت شده قابل حذف نیست', 'error');
return;
}
this.dialog = {
show: true,
title: 'حذف قسط',
@ -882,14 +1058,6 @@ export default {
onConfirm: () => {
const index = this.installments.findIndex(i => i.number === item.number);
if (index !== -1) {
// اگر قسط پرداخت شده است، اجازه حذف ندهیم
if (item.status === 'پرداخت شده') {
this.showMessage('قسط پرداخت شده قابل حذف نیست', 'error');
this.dialog.show = false;
return;
}
// حذف قسط
this.installments.splice(index, 1);
// بهروزرسانی شماره اقساط
@ -919,133 +1087,6 @@ export default {
// در غیر این صورت، تاریخ میلادی را به شمسی تبدیل کن
return moment(date).format('jYYYY/jMM/jDD');
},
calculateInstallments() {
if (!this.canCalculate) {
this.showMessage('لطفا تمام اطلاعات مورد نیاز را وارد کنید', 'error');
return;
}
if (this.isCalculating) {
return;
}
try {
this.isCalculating = true;
this.loading = true;
const totalAmount = this.remainingAmount;
const prepayment = Number(this.installmentData.prepayment) || 0;
const remainingAmount = totalAmount - prepayment;
const interestRate = Number(this.installmentData.interestRate) || 0;
const interestType = this.installmentData.interestType;
let count, monthlyPayment;
if (this.installmentData.calculationType === 'amount') {
monthlyPayment = Number(this.installmentData.installmentAmount);
if (monthlyPayment <= 0) {
this.installments = [];
this.showMessage('مبلغ هر قسط باید بزرگتر از صفر باشد', 'error');
return;
}
// محاسبه تعداد اقساط بر اساس مبلغ هر قسط
switch (interestType) {
case 'monthly': {
// برای سود ساده ماهانه
const monthlyInterest = interestRate / 100;
const principalPerMonth = remainingAmount / monthlyPayment;
const interestPerMonth = monthlyInterest;
count = Math.ceil(principalPerMonth / (1 - interestPerMonth));
break;
}
case 'yearly': {
// برای سود ساده سالانه
const yearlyInterest = interestRate / 100;
const monthlyInterest = yearlyInterest / 12;
const principalPerMonth = remainingAmount / monthlyPayment;
const interestPerMonth = monthlyInterest;
count = Math.ceil(principalPerMonth / (1 - interestPerMonth));
break;
}
default:
count = 0;
}
// محدود کردن تعداد اقساط به یک عدد منطقی
count = Math.min(Math.max(count, 1), 360); // حداکثر 30 سال
} else {
count = Number(this.installmentData.count) || 0;
if (count <= 0) {
this.installments = [];
this.showMessage('تعداد اقساط باید بزرگتر از صفر باشد', 'error');
return;
}
switch (interestType) {
case 'monthly': {
const monthlyInterest = interestRate / 100;
const totalInterest = monthlyInterest * count;
monthlyPayment = (remainingAmount * (1 + totalInterest)) / count;
break;
}
case 'yearly': {
const yearlyInterest = interestRate / 100;
const monthlyInterest = yearlyInterest / 12;
const totalInterest = monthlyInterest * count;
monthlyPayment = (remainingAmount * (1 + totalInterest)) / count;
break;
}
default:
monthlyPayment = 0;
}
}
// ایجاد اقساط
const newInstallments = [];
let currentDate = moment(this.installmentData.firstDate, 'jYYYY/jMM/jDD').toDate();
let remainingTotal = remainingAmount;
for (let i = 1; i <= count; i++) {
let installmentAmount;
if (i === count) {
installmentAmount = remainingTotal;
} else {
installmentAmount = Math.round(monthlyPayment);
remainingTotal -= installmentAmount;
}
newInstallments.push({
number: i,
amount: installmentAmount,
dueDate: moment(currentDate).format('jYYYY/jMM/jDD'),
status: 'پرداخت نشده',
latePaymentPenalty: this.installmentData.latePaymentPenalty
});
currentDate = moment(currentDate).add(1, 'month').toDate();
}
if (prepayment > 0) {
newInstallments.unshift({
number: 0,
amount: prepayment,
dueDate: moment().format('jYYYY/jMM/jDD'),
status: 'پرداخت شده',
latePaymentPenalty: 0
});
}
this.installments = newInstallments;
this.showMessage('اقساط با موفقیت محاسبه شد', 'success');
} catch (error) {
console.error('خطا در محاسبه اقساط:', error);
this.showMessage('خطا در محاسبه اقساط', 'error');
} finally {
this.isCalculating = false;
this.loading = false;
}
},
async loadInvoiceData() {
try {
this.loading = true;
@ -1055,7 +1096,7 @@ export default {
// تنظیم اطلاعات فاکتور
this.selectedInvoice = {
id: data.id,
code: data.id.toString(),
code: data.code,
date: moment.unix(data.dateSubmit).format('jYYYY/jMM/jDD'),
dateSubmit: data.dateSubmit,
des: 'فاکتور اقساطی',
@ -1063,7 +1104,8 @@ export default {
status: 'در انتظار پرداخت',
person: data.person,
personName: data.person.name || '',
personNikename: data.person.nikename || ''
personNikename: data.person.nikename || '',
relatedDocs: []
};
// تنظیم اطلاعات اقساط
@ -1077,13 +1119,16 @@ export default {
prepayment: 0
};
// تنظیم اقساط
// تنظیم اقساط با وضعیت پرداخت صحیح
this.installments = data.items.map(item => ({
id: item.id,
number: parseInt(item.num),
amount: parseFloat(item.amount),
dueDate: item.date,
status: item.hesabdariDoc ? 'پرداخت شده' : 'پرداخت نشده',
latePaymentPenalty: parseFloat(data.daysPay)
latePaymentPenalty: parseFloat(data.daysPay),
hesabdariDoc: item.hesabdariDoc,
isPaid: !!item.hesabdariDoc // اضافه کردن فلگ پرداخت شده
}));
// محاسبه مجدد اقساط برای نمایش صحیح

View file

@ -36,17 +36,19 @@
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
loading: false,
headers: [
{ title: this.$t('field.id'), key: 'id' },
{ title: this.$t('field.date'), key: 'date' },
{ title: this.$t('field.employee'), key: 'employee' },
{ title: this.$t('field.amount'), key: 'amount' },
{ title: this.$t('field.status'), key: 'status' },
{ title: this.$t('field.actions'), key: 'actions', sortable: false }
{ title: this.$t('dialog.field.id'), key: 'id' },
{ title: this.$t('dialog.field.date'), key: 'date' },
{ title: this.$t('dialog.field.employee'), key: 'employee' },
{ title: this.$t('dialog.field.amount'), key: 'amount' },
{ title: this.$t('dialog.field.status'), key: 'status' },
{ title: this.$t('dialog.field.actions'), key: 'actions', sortable: false }
],
items: []
}
@ -58,7 +60,7 @@ export default {
async loadData() {
this.loading = true
try {
const response = await this.$axios.post('/api/hrm/docs/list')
const response = await axios.post('/api/hrm/docs/list')
this.items = response.data
} catch (error) {
console.error('Error loading data:', error)

View file

@ -78,6 +78,11 @@
<v-btn v-bind="props" icon="mdi-delete" variant="text" size="small" color="error" @click="removeRow(index)"></v-btn>
</template>
</v-tooltip>
<v-tooltip text="کپی" location="bottom">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" icon="mdi-content-copy" variant="text" size="small" color="primary" @click="copyRow(index)"></v-btn>
</template>
</v-tooltip>
</td>
</tr>
</template>
@ -251,6 +256,17 @@ export default {
return sum + (Number(row[column]) || 0);
}, 0);
},
copyRow(index) {
const rowToCopy = this.tableItems[index];
this.tableItems.push({
person: null,
description: rowToCopy.description,
baseSalary: rowToCopy.baseSalary,
overtime: rowToCopy.overtime,
shift: rowToCopy.shift,
night: rowToCopy.night
});
},
}
}
</script>

View file

@ -80,31 +80,6 @@
</v-card-text>
</v-card>
</v-col>
<v-col cols="12" sm="6" md="3">
<v-card :class="['charge-card', { 'selected': isCustomAmount }]"
:elevation="isCustomAmount ? 4 : 1" class="h-100"
:color="isCustomAmount ? 'primary' : 'surface'" variant="elevated">
<v-card-text class="text-center">
<div class="text-h6 mb-2" :class="{ 'text-white': isCustomAmount }">مبلغ دلخواه</div>
<v-text-field
v-model="customAmount"
type="number"
density="compact"
variant="outlined"
hide-details
class="mt-2"
:class="{ 'custom-amount-input': isCustomAmount }"
placeholder="مبلغ را وارد کنید"
@click="selectCustomAmount"
@input="handleCustomAmountInput"
></v-text-field>
<div v-if="customAmount" class="text-caption mt-2"
:class="{ 'text-white': isCustomAmount, 'text-medium-emphasis': !isCustomAmount }">
با احتساب مالیات: {{ formatPrice(Number(customAmount) * 1.1) }} تومان
</div>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-col>
</v-row>
@ -187,13 +162,11 @@ export default defineComponent({
color: 'error'
},
smsCharge: 100000,
customAmount: '',
isCustomAmount: false,
chargeAmounts: [
{ label: '۱۰ هزار تومان', value: 10000 },
{ label: '۵۰ هزار تومان', value: 50000 },
{ label: '۱۰۰ هزار تومان', value: 100000 },
{ label: '۲۰۰ هزار تومان', value: 200000 }
{ label: '۲۰۰ هزار تومان', value: 200000 },
{ label: '۵۰۰ هزار تومان', value: 500000 }
],
searchValue: '',
loading: true,
@ -231,7 +204,8 @@ export default defineComponent({
},
pay() {
this.loading = true;
axios.post('/api/sms/charge', { price: this.smsCharge })
const amountInRial = this.smsCharge * 10; // تبدیل تومان به ریال
axios.post('/api/sms/charge', { price: amountInRial })
.then((response) => {
if (response.data.Success === true) {
window.location.href = response.data.targetURL;
@ -261,15 +235,6 @@ export default defineComponent({
formatPrice(price: number): string {
return new Intl.NumberFormat('fa-IR').format(price);
},
selectCustomAmount() {
this.isCustomAmount = true;
this.smsCharge = Number(this.customAmount);
},
handleCustomAmountInput() {
if (this.isCustomAmount) {
this.smsCharge = Number(this.customAmount);
}
},
},
beforeMount() {
this.loadData();

View file

@ -0,0 +1,142 @@
<script>
import axios from "axios";
import Swal from "sweetalert2";
export default {
name: "pluginTransactions",
data: () => {
return {
loading: false,
search: '',
transactions: [],
headers: [
{ title: 'نام افزونه', key: 'des', align: 'right' },
{ title: 'نام کسب و کار', key: 'businessName', align: 'right' },
{ title: 'نام خریدار', key: 'submitterName', align: 'right' },
{ title: 'قیمت', key: 'price', align: 'right' },
{ title: 'تاریخ خرید', key: 'dateSubmit', align: 'right' },
{ title: 'تاریخ انقضا', key: 'dateExpire', align: 'right' },
{ title: 'وضعیت', key: 'status', align: 'right' },
{ title: 'شماره کارت', key: 'cardPan', align: 'right' },
{ title: 'کد پیگیری', key: 'refID', align: 'right' },
],
}
},
methods: {
async loadTransactions() {
this.loading = true;
try {
const response = await axios.post('/api/admin/plugins/transactions');
this.transactions = response.data;
} catch (error) {
Swal.fire({
title: 'خطا',
text: 'در دریافت اطلاعات تراکنش‌ها مشکلی پیش آمده است',
icon: 'error',
confirmButtonText: 'باشه'
});
}
this.loading = false;
},
getStatusText(status) {
switch (parseInt(status)) {
case 0:
return 'در انتظار پرداخت';
case 100:
return 'پرداخت موفق';
case 101:
return 'پرداخت ناموفق';
case 102:
return 'لغو شده';
default:
return 'نامشخص';
}
},
getStatusColor(status) {
switch (parseInt(status)) {
case 0:
return 'warning';
case 100:
return 'success';
case 101:
return 'error';
case 102:
return 'grey';
default:
return 'error';
}
},
getStatusIcon(status) {
switch (parseInt(status)) {
case 0:
return 'mdi-clock-outline';
case 100:
return 'mdi-check-circle';
case 101:
return 'mdi-close-circle';
case 102:
return 'mdi-cancel';
default:
return 'mdi-help-circle';
}
}
},
mounted() {
this.loadTransactions();
}
}
</script>
<template>
<v-toolbar color="toolbar" :title="$t('dialog.plugins')">
<v-spacer></v-spacer>
</v-toolbar>
<v-container class="pa-4">
<v-card>
<v-card-text>
<v-text-field
v-model="search"
prepend-inner-icon="mdi-magnify"
label="جستجو"
single-line
hide-details
class="mb-4"
density="compact"
></v-text-field>
</v-card-text>
<v-data-table
:headers="headers"
:items="transactions"
:loading="loading"
:search="search"
class="elevation-1"
>
<template v-slot:item.status="{ item }">
<v-chip
:color="getStatusColor(item.status)"
size="small"
:prepend-icon="getStatusIcon(item.status)"
>
{{ getStatusText(item.status) }}
</v-chip>
</template>
<template v-slot:item.price="{ item }">
{{ item.price.toLocaleString() }} ریال
</template>
<template v-slot:no-data>
<v-alert
type="info"
text="هیچ تراکنشی یافت نشد"
class="ma-4"
></v-alert>
</template>
</v-data-table>
</v-card>
</v-container>
</template>
<style scoped>
.v-data-table {
direction: rtl;
}
</style>

View file

@ -35,6 +35,13 @@
<v-list-item v-for="(item, i) in adminSettings" :prepend-icon="item.icon" :to="item.url"
:title="item.text"></v-list-item>
</v-list-group>
<v-list-group v-if="ROLE_ADMIN == true">
<template v-slot:activator="{ props }">
<v-list-item v-bind="props" prepend-icon="mdi-toy-brick" title="افزونه‌ها"></v-list-item>
</template>
<v-list-item prepend-icon="mdi-format-list-bulleted" to="/profile/manager/plugins/list" title="فهرست افزونه‌ها"></v-list-item>
<v-list-item prepend-icon="mdi-cash-multiple" to="/profile/manager/plugins/transactions" title="تراکنش‌های خرید"></v-list-item>
</v-list-group>
<v-list-item color="primary">
<v-list-item-title>
<small class="text-primary">{{ siteName }} : {{ hesabix.version }}</small>
@ -101,13 +108,11 @@ export default defineComponent({
{ text: 'کسب‌و‌کارها', url: '/profile/manager/business/list', icon: 'mdi-home-city', visible: true },
{ text: 'کاربران', url: '/profile/manager/users/list', icon: 'mdi-account-multiple', visible: true },
{ text: 'کاربران آنلاین', url: '/profile/manager/users/onlinelist', icon: 'mdi-account-badge', visible: true },
{ text: 'افزونه‌ها', url: '/profile/manager/plugins/list', icon: 'mdi-toy-brick', visible: true },
{ text: 'به روز رسانی هسته', url: '/profile/manager/update-core', icon: 'mdi-undo', visible: true },
{ text: 'تغییرات', url: '/profile/manager/changes/list', icon: 'mdi-cellphone-arrow-down', visible: true },
{ text: 'تاریخچه سیستم', url: '/profile/manager/logs/list', icon: 'mdi-history', visible: true },
{ text: 'کیف پول', url: '/profile/manager/wallet/list', icon: 'mdi-wallet', visible: true },
{ text: 'اطلاعیه‌ها', url: '/profile/manager/statments/list', icon: 'mdi-bell', visible: true },
],
adminSettings: [
{ text: 'پیامک', url: '/profile/manager/system/sms/settings', icon: 'mdi-message-alert', visible: true },
@ -181,4 +186,24 @@ export default defineComponent({
});
</script>
<style scoped></style>
<style scoped>
.v-list-group__items .v-list-item {
padding-right: 32px !important;
}
.v-list-item {
min-height: 40px !important;
}
.v-list-item__content {
padding-right: 8px !important;
}
.v-list-group__header {
padding-right: 16px !important;
}
.v-list-group__items {
padding-right: 8px !important;
}
</style>