diff --git a/hesabixCore/src/Controller/AdminController.php b/hesabixCore/src/Controller/AdminController.php index bba72a1..bdf2c16 100644 --- a/hesabixCore/src/Controller/AdminController.php +++ b/hesabixCore/src/Controller/AdminController.php @@ -19,6 +19,7 @@ use App\Entity\WalletTransaction; use App\Service\Extractor; use App\Service\Jdate; use App\Service\JsonResp; +use App\Service\Log; use App\Service\Notification; use App\Service\Provider; use App\Service\registryMGR; @@ -603,12 +604,16 @@ class AdminController extends AbstractController } $temp['totalPays'] = $totalPays; - $walletIncomes = $entityManager->getRepository(WalletTransaction::class)->findAllIncome($bid); - $totalIcome = 0; - foreach ($walletIncomes as $walletIncome) { - $totalIcome += $walletIncome->getAmount(); + // محاسبه درآمد از تراکنشهای sell + $walletSells = $entityManager->getRepository(WalletTransaction::class)->findBy(['bid' => $bid, 'type' => 'sell']); + $totalIncome = 0; + foreach ($walletSells as $walletSell) { + $totalIncome += (float) $walletSell->getAmount(); } - $temp['totalIncome'] = $totalIcome; + $temp['totalIncome'] = $totalIncome; + + // محاسبه موجودی (درآمد - هزینه) + $temp['walletBalance'] = $totalIncome - $totalPays; $temp['id'] = $bid->getId(); $temp['bidName'] = $bid->getName(); @@ -724,4 +729,457 @@ class AdminController extends AbstractController return $this->json($res); } + #[Route('/api/admin/business/charge/add', name: 'admin_business_charge_add', methods: ['POST'])] + public function admin_business_charge_add( + Request $request, + EntityManagerInterface $entityManager, + Log $logService, + Jdate $jdate + ): JsonResponse { + $params = json_decode($request->getContent(), true); + + if (!isset($params['businessId']) || !isset($params['amount']) || !isset($params['description'])) { + return $this->json(['success' => false, 'message' => 'تمام فیلدهای ضروری را وارد کنید']); + } + + $business = $entityManager->getRepository(Business::class)->find($params['businessId']); + if (!$business) { + return $this->json(['success' => false, 'message' => 'کسب و کار یافت نشد']); + } + + $currentCharge = (float) ($business->getSmsCharge() ?? 0); + $newAmount = (float) $params['amount']; + $newCharge = $currentCharge + $newAmount; + + $business->setSmsCharge((string) $newCharge); + $entityManager->persist($business); + $entityManager->flush(); + + // ثبت لاگ + $logService->insert( + 'مدیریت اعتبار', + "افزایش اعتبار پیامک به مبلغ {$newAmount} ریال. اعتبار قبلی: {$currentCharge} ریال، اعتبار جدید: {$newCharge} ریال. توضیحات: {$params['description']}", + $this->getUser(), + $business + ); + + return $this->json([ + 'success' => true, + 'message' => 'اعتبار با موفقیت افزایش یافت', + 'data' => [ + 'previousCharge' => $currentCharge, + 'newCharge' => $newCharge, + 'addedAmount' => $newAmount + ] + ]); + } + + #[Route('/api/admin/business/plugin/activate', name: 'admin_business_plugin_activate', methods: ['POST'])] + public function admin_business_plugin_activate( + Request $request, + EntityManagerInterface $entityManager, + Log $logService + ): JsonResponse { + $params = json_decode($request->getContent(), true); + + if (!isset($params['businessId']) || !isset($params['pluginCode']) || !isset($params['duration'])) { + return $this->json(['success' => false, 'message' => 'تمام فیلدهای ضروری را وارد کنید']); + } + + $business = $entityManager->getRepository(Business::class)->find($params['businessId']); + if (!$business) { + return $this->json(['success' => false, 'message' => 'کسب و کار یافت نشد']); + } + + $pluginProduct = $entityManager->getRepository(\App\Entity\PluginProdect::class)->findOneBy(['code' => $params['pluginCode']]); + if (!$pluginProduct) { + return $this->json(['success' => false, 'message' => 'افزونه یافت نشد']); + } + + // بررسی اینکه آیا افزونه قبلاً فعال شده یا خیر + $existingPlugin = $entityManager->getRepository(\App\Entity\Plugin::class)->findOneBy([ + 'bid' => $business, + 'name' => $params['pluginCode'] + ]); + + $currentTime = time(); + $expireTime = $currentTime + ($params['duration'] * 86400); // تبدیل روز به ثانیه + + if ($existingPlugin) { + // اگر افزونه قبلاً فعال بوده، تاریخ انقضا را تمدید کن + $oldExpire = $existingPlugin->getDateExpire(); + $existingPlugin->setDateExpire((string) $expireTime); + $existingPlugin->setStatus('100'); + $entityManager->persist($existingPlugin); + } else { + // ایجاد افزونه جدید + $plugin = new \App\Entity\Plugin(); + $plugin->setBid($business); + $plugin->setName($params['pluginCode']); + $plugin->setDateSubmit((string) $currentTime); + $plugin->setDateExpire((string) $expireTime); + $plugin->setStatus('100'); + $plugin->setSubmitter($this->getUser()); + $plugin->setPrice('0'); // رایگان برای ادمین + $plugin->setDes($params['description'] ?? 'فعالسازی توسط ادمین'); + $entityManager->persist($plugin); + } + + $entityManager->flush(); + + // ثبت لاگ + $durationText = $params['duration'] . ' روز'; + $logService->insert( + 'مدیریت افزونه', + "فعالسازی افزونه {$pluginProduct->getName()} برای مدت {$durationText}. توضیحات: " . (isset($params['description']) ? $params['description'] : 'فعالسازی توسط ادمین'), + $this->getUser(), + $business + ); + + return $this->json([ + 'success' => true, + 'message' => 'افزونه با موفقیت فعال شد', + 'data' => [ + 'pluginName' => $pluginProduct->getName(), + 'expireDate' => date('Y-m-d H:i:s', $expireTime), + 'duration' => $params['duration'] + ] + ]); + } + + #[Route('/api/admin/business/report/{id}', name: 'admin_business_report', methods: ['GET'])] + public function admin_business_report( + string $id, + EntityManagerInterface $entityManager, + Jdate $jdate + ): JsonResponse { + $business = $entityManager->getRepository(Business::class)->find($id); + if (!$business) { + return $this->json(['success' => false, 'message' => 'کسب و کار یافت نشد']); + } + + // آمار اشخاص + $personsCount = count($entityManager->getRepository(\App\Entity\Person::class)->findBy(['bid' => $business])); + + // آمار کالا و خدمات + $commodityCount = count($entityManager->getRepository(\App\Entity\Commodity::class)->findBy(['bid' => $business])); + + // آمار اسناد حسابداری + $hesabdariDocsCount = count($entityManager->getRepository(\App\Entity\HesabdariDoc::class)->findBy(['bid' => $business])); + + // آمار اسناد انبار + $storeroomDocsCount = count($entityManager->getRepository(\App\Entity\StoreroomTicket::class)->findBy(['bid' => $business])); + + // آمار بانکها + $bankAccountsCount = count($entityManager->getRepository(\App\Entity\BankAccount::class)->findBy(['bid' => $business])); + + // آمار سالهای مالی + $yearsCount = count($entityManager->getRepository(\App\Entity\Year::class)->findBy(['bid' => $business])); + + // آمار افزونههای فعال + $activePlugins = $entityManager->getRepository(\App\Entity\Plugin::class)->findBy([ + 'bid' => $business, + 'status' => '100' + ]); + $activePluginsCount = count($activePlugins); + + // لیست افزونههای فعال + $activePluginsList = []; + foreach ($activePlugins as $plugin) { + $pluginProduct = $entityManager->getRepository(\App\Entity\PluginProdect::class)->findOneBy(['code' => $plugin->getName()]); + $activePluginsList[] = [ + 'name' => $pluginProduct ? $pluginProduct->getName() : $plugin->getName(), + 'expireDate' => $jdate->jdate('Y/n/d H:i', $plugin->getDateExpire()), + 'isExpired' => $plugin->getDateExpire() < time() + ]; + } + + // محاسبه فضای آرشیو + $archiveFiles = $entityManager->getRepository(\App\Entity\ArchiveFile::class)->findBy(['bid' => $business]); + $totalArchiveSize = 0; + foreach ($archiveFiles as $file) { + $totalArchiveSize += (int) ($file->getFileSize() ? $file->getFileSize() : 0); + } + + // آمار کیف پول + $walletTransactions = $entityManager->getRepository(\App\Entity\WalletTransaction::class)->findBy(['bid' => $business]); + $walletIncome = 0; + $walletExpense = 0; + foreach ($walletTransactions as $transaction) { + if ($transaction->getType() === 'sell') { + $walletIncome += (float) $transaction->getAmount(); + } elseif ($transaction->getType() === 'pay') { + $walletExpense += (float) $transaction->getAmount(); + } + } + + $report = [ + 'businessInfo' => [ + 'id' => $business->getId(), + 'name' => $business->getName(), + 'legalName' => $business->getLegalName(), + 'owner' => $business->getOwner()->getFullName(), + 'ownerMobile' => $business->getOwner()->getMobile(), + 'ownerEmail' => $business->getOwner()->getEmail(), + 'dateRegister' => $jdate->jdate('Y/n/d H:i', $business->getDateSubmit()), + 'field' => $business->getField(), + 'type' => $business->getType(), + 'address' => $business->getAddress(), + 'tel' => $business->getTel(), + 'mobile' => $business->getMobile(), + 'email' => $business->getEmail(), + 'website' => $business->getWesite(), + 'shenasemeli' => $business->getShenasemeli(), + 'codeeghtesadi' => $business->getCodeeghtesadi(), + 'shomaresabt' => $business->getShomaresabt(), + 'country' => $business->getCountry(), + 'ostan' => $business->getOstan(), + 'shahrestan' => $business->getShahrestan(), + 'postalcode' => $business->getPostalcode(), + 'maliyatafzode' => $business->getMaliyatafzode(), + 'avatar' => $business->getAvatar(), + 'sealFile' => $business->getSealFile(), + ], + 'statistics' => [ + 'personsCount' => $personsCount, + 'commodityCount' => $commodityCount, + 'hesabdariDocsCount' => $hesabdariDocsCount, + 'storeroomDocsCount' => $storeroomDocsCount, + 'bankAccountsCount' => $bankAccountsCount, + 'yearsCount' => $yearsCount, + 'activePluginsCount' => $activePluginsCount, + ], + 'financial' => [ + 'smsCharge' => (float) ($business->getSmsCharge() ?? 0), + 'walletEnabled' => $business->isWalletEnable(), + 'walletIncome' => $walletIncome, + 'walletExpense' => $walletExpense, + 'walletBalance' => $walletIncome - $walletExpense, + ], + 'storage' => [ + 'archiveSize' => $business->getArchiveSize(), + 'totalArchiveSize' => $totalArchiveSize, + 'archiveFilesCount' => count($archiveFiles), + ], + 'plugins' => [ + 'activeCount' => $activePluginsCount, + 'activeList' => $activePluginsList, + ], + 'features' => [ + 'storeOnline' => $business->isStoreOnline(), + 'shortlinks' => $business->isShortlinks(), + 'walletEnable' => $business->isWalletEnable(), + 'commodityUpdateSellPriceAuto' => $business->isCommodityUpdateSellPriceAuto(), + 'commodityUpdateBuyPriceAuto' => $business->isCommodityUpdateBuyPriceAuto(), + 'profitCalcType' => $business->getProfitCalcType(), + ] + ]; + + return $this->json([ + 'success' => true, + 'data' => $report + ]); + } + + #[Route('/api/admin/business/wallet/balance/{id}', name: 'admin_business_wallet_balance', methods: ['GET'])] + public function admin_business_wallet_balance( + string $id, + EntityManagerInterface $entityManager, + Jdate $jdate + ): JsonResponse { + $business = $entityManager->getRepository(Business::class)->find($id); + if (!$business) { + return $this->json(['success' => false, 'message' => 'کسب و کار یافت نشد']); + } + + if (!$business->isWalletEnable()) { + return $this->json(['success' => false, 'message' => 'کیف پول برای این کسب و کار فعال نیست']); + } + + // محاسبه موجودی با استفاده از repository + $walletBalance = $entityManager->getRepository(\App\Entity\WalletTransaction::class)->calculateWalletBalance($business); + + // محاسبه درآمد و هزینه جداگانه + $walletSells = $entityManager->getRepository(\App\Entity\WalletTransaction::class)->findBy(['bid' => $business, 'type' => 'sell']); + $walletPays = $entityManager->getRepository(\App\Entity\WalletTransaction::class)->findBy(['bid' => $business, 'type' => 'pay']); + + $totalIncome = 0; + foreach ($walletSells as $sell) { + $totalIncome += (float) $sell->getAmount(); + } + + $totalExpense = 0; + foreach ($walletPays as $pay) { + $totalExpense += (float) $pay->getAmount(); + } + + return $this->json([ + 'success' => true, + 'data' => [ + 'businessId' => $business->getId(), + 'businessName' => $business->getName(), + 'walletBalance' => $walletBalance, + 'totalIncome' => $totalIncome, + 'totalExpense' => $totalExpense, + 'transactionsCount' => [ + 'sell' => count($walletSells), + 'pay' => count($walletPays) + ], + 'lastTransactions' => [ + 'sells' => array_slice(array_map(function($sell) use ($jdate) { + return [ + 'id' => $sell->getId(), + 'amount' => (float) $sell->getAmount(), + 'date' => $jdate->jdate('Y/n/d H:i', $sell->getDateSubmit()), + 'description' => $sell->getDes() + ]; + }, $walletSells), 0, 5), + 'pays' => array_slice(array_map(function($pay) use ($jdate) { + return [ + 'id' => $pay->getId(), + 'amount' => (float) $pay->getAmount(), + 'date' => $jdate->jdate('Y/n/d H:i', $pay->getDateSubmit()), + 'description' => $pay->getDes(), + 'refID' => $pay->getRefID() + ]; + }, $walletPays), 0, 5) + ] + ] + ]); + } + + #[Route('/api/admin/business/wallet/transactions/{id}', name: 'admin_business_wallet_transactions', methods: ['GET'])] + public function admin_business_wallet_transactions( + string $id, + EntityManagerInterface $entityManager, + Jdate $jdate, + Request $request + ): JsonResponse { + $business = $entityManager->getRepository(Business::class)->find($id); + if (!$business) { + return $this->json(['success' => false, 'message' => 'کسب و کار یافت نشد']); + } + + if (!$business->isWalletEnable()) { + return $this->json(['success' => false, 'message' => 'کیف پول برای این کسب و کار فعال نیست']); + } + + // پارامترهای صفحهبندی + $page = max(1, (int) ($request->query->get('page', 1))); + $limit = max(1, min(100, (int) ($request->query->get('limit', 20)))); + $offset = ($page - 1) * $limit; + + // فیلتر نوع تراکنش + $type = $request->query->get('type'); // 'sell' یا 'pay' یا null برای همه + + $qb = $entityManager->createQueryBuilder(); + $qb->select('w') + ->from(\App\Entity\WalletTransaction::class, 'w') + ->where('w.bid = :business') + ->setParameter('business', $business) + ->orderBy('w.dateSubmit', 'DESC'); + + if ($type && in_array($type, ['sell', 'pay'])) { + $qb->andWhere('w.type = :type') + ->setParameter('type', $type); + } + + // محاسبه تعداد کل + $countQb = clone $qb; + $totalCount = $countQb->select('COUNT(w.id)')->getQuery()->getSingleScalarResult(); + + // اعمال صفحهبندی + $qb->setFirstResult($offset) + ->setMaxResults($limit); + + $transactions = $qb->getQuery()->getResult(); + + $transactionsData = []; + foreach ($transactions as $transaction) { + $transactionsData[] = [ + 'id' => $transaction->getId(), + 'type' => $transaction->getType(), + 'amount' => (float) $transaction->getAmount(), + 'date' => $jdate->jdate('Y/n/d H:i', $transaction->getDateSubmit()), + 'description' => $transaction->getDes(), + 'refID' => $transaction->getRefID(), + 'shaba' => $transaction->getShaba(), + 'cardPan' => $transaction->getCardPan(), + 'gatePay' => $transaction->getGatePay(), + 'bank' => $transaction->getBank(), + 'submitter' => $transaction->getSubmitter() ? $transaction->getSubmitter()->getFullName() : null + ]; + } + + return $this->json([ + 'success' => true, + 'data' => [ + 'businessId' => $business->getId(), + 'businessName' => $business->getName(), + 'transactions' => $transactionsData, + 'pagination' => [ + 'page' => $page, + 'limit' => $limit, + 'total' => (int) $totalCount, + 'totalPages' => ceil($totalCount / $limit) + ] + ] + ]); + } + + #[Route('/api/admin/business/plugins/list/{id}', name: 'admin_business_plugins_list', methods: ['GET'])] + public function admin_business_plugins_list( + string $id, + EntityManagerInterface $entityManager, + Jdate $jdate + ): JsonResponse { + $business = $entityManager->getRepository(Business::class)->find($id); + if (!$business) { + return $this->json(['success' => false, 'message' => 'کسب و کار یافت نشد']); + } + + // دریافت همه افزونههای موجود + $allPlugins = $entityManager->getRepository(\App\Entity\PluginProdect::class)->findAll(); + + // دریافت افزونههای فعال این کسب و کار + $businessPlugins = $entityManager->getRepository(\App\Entity\Plugin::class)->findBy([ + 'bid' => $business, + 'status' => '100' + ]); + $businessPluginCodes = array_map(fn($p) => $p->getName(), $businessPlugins); + + $pluginsList = []; + foreach ($allPlugins as $plugin) { + $isActive = in_array($plugin->getCode(), $businessPluginCodes); + $businessPlugin = null; + + if ($isActive) { + $businessPlugin = $entityManager->getRepository(\App\Entity\Plugin::class)->findOneBy([ + 'bid' => $business, + 'name' => $plugin->getCode(), + 'status' => '100' + ]); + } + + $pluginsList[] = [ + 'id' => $plugin->getId(), + 'name' => $plugin->getName(), + 'code' => $plugin->getCode(), + 'price' => $plugin->getPrice(), + 'timeLabel' => $plugin->getTimelabel(), + 'icon' => $plugin->getIcon(), + 'defaultOn' => $plugin->isDefaultOn(), + 'isActive' => $isActive, + 'expireDate' => $businessPlugin ? $jdate->jdate('Y/n/d H:i', $businessPlugin->getDateExpire()) : null, + 'isExpired' => $businessPlugin ? $businessPlugin->getDateExpire() < time() : false, + 'status' => $businessPlugin ? $businessPlugin->getStatus() : null, + ]; + } + + return $this->json([ + 'success' => true, + 'data' => $pluginsList + ]); + } + } diff --git a/hesabixCore/src/Repository/WalletTransactionRepository.php b/hesabixCore/src/Repository/WalletTransactionRepository.php index 34c9514..1403af5 100644 --- a/hesabixCore/src/Repository/WalletTransactionRepository.php +++ b/hesabixCore/src/Repository/WalletTransactionRepository.php @@ -29,7 +29,7 @@ class WalletTransactionRepository extends ServiceEntityRepository { return $this->createQueryBuilder('w') ->andWhere('w.bid = :val') - ->andWhere("w.type != 'pay'") + ->andWhere("w.type = 'sell'") ->setParameter('val', $business) ->orderBy('w.id', 'DESC') ->getQuery() @@ -37,6 +37,31 @@ class WalletTransactionRepository extends ServiceEntityRepository ; } + public function calculateWalletBalance(Business $business): float + { + $qb = $this->createQueryBuilder('w'); + + // محاسبه مجموع تراکنشهای sell (درآمد) + $incomeQuery = $qb->select('SUM(CAST(w.amount AS DECIMAL(10,2)))') + ->where('w.bid = :business') + ->andWhere("w.type = 'sell'") + ->setParameter('business', $business) + ->getQuery(); + + $income = $incomeQuery->getSingleScalarResult() ?? 0; + + // محاسبه مجموع تراکنشهای pay (هزینه) + $expenseQuery = $qb->select('SUM(CAST(w.amount AS DECIMAL(10,2)))') + ->where('w.bid = :business') + ->andWhere("w.type = 'pay'") + ->setParameter('business', $business) + ->getQuery(); + + $expense = $expenseQuery->getSingleScalarResult() ?? 0; + + return (float) $income - (float) $expense; + } + // public function findOneBySomeField($value): ?WalletTransaction // { // return $this->createQueryBuilder('w') diff --git a/webUI/src/components/admin/BusinessChargeDialog.vue b/webUI/src/components/admin/BusinessChargeDialog.vue new file mode 100644 index 0000000..fafd739 --- /dev/null +++ b/webUI/src/components/admin/BusinessChargeDialog.vue @@ -0,0 +1,126 @@ + + + + + mdi-credit-card + افزایش اعتبار پیامک - {{ business?.name || 'انتخاب نشده' }} + + + mdi-close + + + + + + + + + + + + + + mdi-close + انصراف + + + mdi-check + افزایش اعتبار + + + + + + + \ No newline at end of file diff --git a/webUI/src/components/admin/BusinessPluginDialog.vue b/webUI/src/components/admin/BusinessPluginDialog.vue new file mode 100644 index 0000000..3fdaab0 --- /dev/null +++ b/webUI/src/components/admin/BusinessPluginDialog.vue @@ -0,0 +1,179 @@ + + + + + mdi-puzzle + فعالسازی افزونه - {{ business?.name || 'انتخاب نشده' }} + + + mdi-close + + + + + + + + + {{ item.raw.name }} + + {{ item.raw.timeLabel }} - {{ item.raw.price }} ریال + فعال + منقضی شده + + + + + + + + + + + + + mdi-close + انصراف + + + mdi-check + فعالسازی + + + + + + + \ No newline at end of file diff --git a/webUI/src/components/admin/BusinessReportDialog.vue b/webUI/src/components/admin/BusinessReportDialog.vue new file mode 100644 index 0000000..6f77215 --- /dev/null +++ b/webUI/src/components/admin/BusinessReportDialog.vue @@ -0,0 +1,701 @@ + + + + + + + mdi-domain + + + + گزارش کامل کسب و کار + + + {{ businessReport?.businessInfo?.name || 'انتخاب نشده' }} + + + + + mdi-close + + + + + + + + + + + + + + + + {{ businessReport.statistics.personsCount }} + اشخاص + + + + + {{ businessReport.statistics.commodityCount }} + کالا و خدمات + + + + + {{ businessReport.statistics.hesabdariDocsCount }} + اسناد حسابداری + + + + + {{ businessReport.statistics.storeroomDocsCount }} + اسناد انبار + + + + + + + + + نمای کلی + + + اطلاعات پایه + + + مالی + + + افزونهها + + + فضای ذخیره + + + + + + + + + + + + + + mdi-domain + اطلاعات کسب و کار + + + + + + mdi-account + + مالک + {{ businessReport.businessInfo.owner }} + + + + mdi-phone + + موبایل + {{ businessReport.businessInfo.ownerMobile }} + + + + mdi-email + + ایمیل + {{ businessReport.businessInfo.ownerEmail }} + + + + mdi-calendar + + تاریخ ثبت + {{ businessReport.businessInfo.dateRegister }} + + + + + + + + + + + mdi-wallet + خلاصه مالی + + + + + اعتبار پیامک + {{ Math.floor(businessReport.financial.smsCharge).toLocaleString() }} ریال + + + + + + + موجودی کیف پول + + {{ Math.floor(businessReport.financial.walletBalance).toLocaleString() }} ریال + + + + + موجودی = تراکنشهای فروش - تراکنشهای پرداخت + + + + + + سالهای مالی + {{ businessReport.statistics.yearsCount }} + + + حسابهای بانکی + {{ businessReport.statistics.bankAccountsCount }} + + + افزونههای فعال + {{ businessReport.plugins.activeCount }} + + + + + + + + + + + mdi-cloud + استفاده از فضای ذخیره + + + + + {{ (businessReport.storage.totalArchiveSize / 1024 / 1024).toFixed(2) }} مگابایت + {{ businessReport.storage.archiveFilesCount }} فایل + + + mdi-cloud + + + + + + + + + + + + + + + + mdi-information + اطلاعات اصلی + + + + + + mdi-domain + + نام کسب و کار + {{ businessReport.businessInfo.name }} + + + + mdi-file-document + + نام قانونی + {{ businessReport.businessInfo.legalName }} + + + + mdi-briefcase + + رشته فعالیت + {{ businessReport.businessInfo.field || 'تعریف نشده' }} + + + + mdi-tag + + نوع + {{ businessReport.businessInfo.type || 'تعریف نشده' }} + + + + + + + + + + mdi-map-marker + اطلاعات تماس + + + + + + mdi-map-marker + + آدرس + {{ businessReport.businessInfo.address || 'تعریف نشده' }} + + + + mdi-phone + + تلفن + {{ businessReport.businessInfo.tel || 'تعریف نشده' }} + + + + mdi-cellphone + + موبایل + {{ businessReport.businessInfo.mobile || 'تعریف نشده' }} + + + + mdi-email + + ایمیل + {{ businessReport.businessInfo.email || 'تعریف نشده' }} + + + + + + + + + + + + + + + + mdi-message-text + اعتبار پیامک + + + + mdi-message-text + + {{ Math.floor(businessReport.financial.smsCharge).toLocaleString() }} + ریال + + + + + + + + + mdi-wallet + کیف پول + + + + + + + + + mdi-trending-up + + {{ Math.floor(businessReport.financial.walletIncome).toLocaleString() }} + درآمد (فروش) + + + مجموع تراکنشهای فروش (sell) + + + + + + + + mdi-trending-down + + {{ Math.floor(businessReport.financial.walletExpense).toLocaleString() }} + هزینه (پرداخت) + + + مجموع تراکنشهای پرداخت (pay) + + + + + + + + mdi-wallet + + {{ Math.floor(businessReport.financial.walletBalance).toLocaleString() }} + موجودی + + + موجودی = درآمد (فروش) - هزینه (پرداخت) + + + + + + + + + + + + mdi-chart-line + آمار مالی + + + + + + + mdi-calendar + + {{ businessReport.statistics.yearsCount }} + سالهای مالی + + + + + + mdi-bank + + {{ businessReport.statistics.bankAccountsCount }} + حسابهای بانکی + + + + + + mdi-file-document + + {{ businessReport.statistics.hesabdariDocsCount }} + اسناد حسابداری + + + + + + mdi-warehouse + + {{ businessReport.statistics.storeroomDocsCount }} + اسناد انبار + + + + + + + + + + + + + + + + + mdi-puzzle + افزونههای فعال + + + {{ businessReport.plugins.activeCount }} افزونه + + + + + + + + + + + + + {{ plugin.isExpired ? 'mdi-alert' : 'mdi-check' }} + + + + {{ plugin.name }} + انقضا: {{ plugin.expireDate }} + + + + {{ plugin.isExpired ? 'منقضی شده' : 'فعال' }} + + + + + + + + + + mdi-information + هیچ افزونه فعالی یافت نشد + + + + + + + + + + + + + + mdi-cloud + فضای آرشیو + + + + + {{ (businessReport.storage.totalArchiveSize / 1024 / 1024).toFixed(2) }} + مگابایت استفاده شده + + + mdi-cloud + + + + + + فضای استفاده شده + {{ (businessReport.storage.totalArchiveSize / 1024 / 1024).toFixed(2) }} MB + + + + {{ Math.ceil(value) }}% + + + + + + + + {{ businessReport.storage.archiveFilesCount }} + تعداد فایلهای آرشیو شده + + + + + + + + + mdi-information + نکات مهم + + + + + + mdi-check-circle + + فضای آرشیو برای نگهداری فایلهای قدیمی + + + + mdi-alert + + پیشنهاد میشود فضای خالی کافی داشته باشید + + + + mdi-download + + امکان دانلود فایلهای آرشیو + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/webUI/src/utils/number.js b/webUI/src/utils/number.js index be37579..1e31b91 100755 --- a/webUI/src/utils/number.js +++ b/webUI/src/utils/number.js @@ -5,7 +5,7 @@ */ export const formatNumber = (number) => { if (!number) return '0' - return new Intl.NumberFormat('fa-IR').format(number) + return new Intl.NumberFormat('fa-IR').format(Math.floor(number)) } /** diff --git a/webUI/src/views/acc/inquiry/panel.vue b/webUI/src/views/acc/inquiry/panel.vue index 729c32f..49c176e 100644 --- a/webUI/src/views/acc/inquiry/panel.vue +++ b/webUI/src/views/acc/inquiry/panel.vue @@ -582,7 +582,7 @@ export default { // فرمت کردن عدد به ریال formatCurrency(number) { - return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + return Math.floor(number).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); }, // تعیین رنگ کارت اعتبار بر اساس میزان اعتبار diff --git a/webUI/src/views/user/manager/business/list.vue b/webUI/src/views/user/manager/business/list.vue index a8e1581..cfeea9b 100755 --- a/webUI/src/views/user/manager/business/list.vue +++ b/webUI/src/views/user/manager/business/list.vue @@ -2,67 +2,147 @@ import { defineComponent, ref, watch } from 'vue' import axios from "axios"; import Swal from "sweetalert2"; -import type { Header, Item, ServerOptions } from "vue3-easy-data-table"; +import BusinessChargeDialog from '@/components/admin/BusinessChargeDialog.vue' +import BusinessPluginDialog from '@/components/admin/BusinessPluginDialog.vue' +import BusinessReportDialog from '@/components/admin/BusinessReportDialog.vue' - -const headers: Header[] = [ - { text: "نام", value: "name" }, - { text: "مالک", value: "owner" }, - { text: "موبایل", value: "ownerMobile" }, - { text: "تاریخ ایجاد", value: "dateRegister" }, - { text: "کالا و خدمات", value: "commodityCount" }, - { text: "اشخاص", value: "personsCount" }, - { text: "اسناد حسابداری", value: "hesabdariDocsCount" }, - { text: "اسناد انبار", value: "StoreroomDocsCount" }, +const headers = [ + { title: "نام", key: "name", sortable: true }, + { title: "مالک", key: "owner", sortable: true }, + { title: "موبایل", key: "ownerMobile", sortable: false }, + { title: "تاریخ ایجاد", key: "dateRegister", sortable: true }, + { title: "کالا و خدمات", key: "commodityCount", sortable: true }, + { title: "اشخاص", key: "personsCount", sortable: true }, + { title: "اسناد حسابداری", key: "hesabdariDocsCount", sortable: true }, + { title: "اسناد انبار", key: "StoreroomDocsCount", sortable: true }, + { title: "عملیات", key: "actions", sortable: false, width: '200px' }, ]; -const items = ref([]); +const items = ref([]); const loading = ref(false); -const serverItemsLength = ref(0); +const totalItems = ref(0); const searchValue = ref(''); -const serverOptions = ref({ +const options = ref({ page: 1, - rowsPerPage: 25, - sortBy: 'id', - sortType: 'desc', + itemsPerPage: 25, + sortBy: ['id'], + sortDesc: [true], }); +// متغیرهای مربوط به دیالوگها +const showChargeDialog = ref(false); +const showPluginDialog = ref(false); +const showReportDialog = ref(false); +const selectedBusiness = ref(null); + const loadFromServer = async () => { loading.value = true; - axios.post('/api/admin/business/count') - .then((response) => { - serverItemsLength.value = response.data; - }); - //load items - await axios.post('/api/admin/business/search', { - options: serverOptions.value, - search: searchValue.value - }) - .then((response) => { - items.value = response.data.data; - loading.value = false; + try { + // دریافت تعداد کل + const countResponse = await axios.post('/api/admin/business/count'); + totalItems.value = countResponse.data; + + // تنظیم مقادیر پیشفرض برای sort + const sortBy = options.value.sortBy?.[0] || 'id'; + const sortDesc = options.value.sortDesc?.[0] || true; + + // دریافت آیتمها + const response = await axios.post('/api/admin/business/search', { + options: { + page: options.value.page, + rowsPerPage: options.value.itemsPerPage, + sortBy: sortBy, + sortType: sortDesc ? 'desc' : 'asc' + }, + search: searchValue.value }); + + items.value = response.data.data; + } catch (error) { + console.error('خطا در بارگذاری دادهها:', error); + } finally { + loading.value = false; + } +}; + +// تابع باز کردن دیالوگ افزایش اعتبار +const openChargeDialog = (business: any) => { + console.log('openChargeDialog called with:', business); + if (!business) { + console.log('business is null/undefined, returning'); + return; + } + selectedBusiness.value = business; + showChargeDialog.value = true; + console.log('Charge dialog should be open, showChargeDialog:', showChargeDialog.value); +}; + +// تابع باز کردن دیالوگ فعالسازی افزونه +const openPluginDialog = (business: any) => { + console.log('openPluginDialog called with:', business); + if (!business) { + console.log('business is null/undefined, returning'); + return; + } + selectedBusiness.value = business; + showPluginDialog.value = true; + console.log('Plugin dialog should be open, showPluginDialog:', showPluginDialog.value); +}; + +// تابع نمایش گزارش کسب و کار +const showBusinessReport = (business: any) => { + console.log('showBusinessReport called with:', business); + if (!business) { + console.log('business is null/undefined, returning'); + return; + } + selectedBusiness.value = business; + showReportDialog.value = true; + console.log('Report dialog should be open, showReportDialog:', showReportDialog.value); +}; + +// تابع موفقیت عملیات +const onSuccess = () => { + loadFromServer(); // بارگذاری مجدد لیست }; // initial load loadFromServer(); -watch(serverOptions, (value) => { loadFromServer(); }, { deep: true }); -watch(searchValue, (value) => { loadFromServer(); }, { deep: true }); +// watch برای تغییرات options +watch(options, () => { + loadFromServer(); +}, { deep: true }); + +// watch برای تغییرات search +watch(searchValue, () => { + options.value.page = 1; // بازگشت به صفحه اول + loadFromServer(); +}); - + - + - + @@ -71,25 +151,92 @@ watch(searchValue, (value) => { loadFromServer(); }, { deep: true }); - - - - {{ $t('dialog.prev_page') }} - - - {{ $t('dialog.next_page') }} - + + + + + + + + + + + + + + + + افزایش اعتبار + افزایش اعتبار پیامک + + + فعالسازی افزونه + فعالسازی یا تمدید افزونه + + + گزارش کامل + مشاهده گزارش جامع + + + + - + + + + + + + + \ No newline at end of file