forked from morrning/hesabixCore
first commit for tax lugin
This commit is contained in:
parent
8adfdb09ee
commit
c20652b8cd
|
@ -109,7 +109,7 @@
|
|||
"symfony/browser-kit": "7.2.*",
|
||||
"symfony/css-selector": "7.2.*",
|
||||
"symfony/debug-bundle": "7.2.*",
|
||||
"symfony/maker-bundle": "^1.62",
|
||||
"symfony/maker-bundle": "^1.64",
|
||||
"symfony/phpunit-bridge": "^7.2",
|
||||
"symfony/stopwatch": "7.2.*",
|
||||
"symfony/web-profiler-bundle": "7.2.*"
|
||||
|
|
21
hesabixCore/composer.lock
generated
21
hesabixCore/composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "389f897ebd1e0befdd15876e5d6a43a7",
|
||||
"content-hash": "fc8e55a0f3d505b2453542a73030d32c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
|
@ -11063,21 +11063,21 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/maker-bundle",
|
||||
"version": "v1.62.1",
|
||||
"version": "v1.64.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/maker-bundle.git",
|
||||
"reference": "468ff2708200c95ebc0d85d3174b6c6711b8a590"
|
||||
"reference": "c86da84640b0586e92aee2b276ee3638ef2f425a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/maker-bundle/zipball/468ff2708200c95ebc0d85d3174b6c6711b8a590",
|
||||
"reference": "468ff2708200c95ebc0d85d3174b6c6711b8a590",
|
||||
"url": "https://api.github.com/repos/symfony/maker-bundle/zipball/c86da84640b0586e92aee2b276ee3638ef2f425a",
|
||||
"reference": "c86da84640b0586e92aee2b276ee3638ef2f425a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/inflector": "^2.0",
|
||||
"nikic/php-parser": "^4.18|^5.0",
|
||||
"nikic/php-parser": "^5.0",
|
||||
"php": ">=8.1",
|
||||
"symfony/config": "^6.4|^7.0",
|
||||
"symfony/console": "^6.4|^7.0",
|
||||
|
@ -11100,6 +11100,7 @@
|
|||
"symfony/http-client": "^6.4|^7.0",
|
||||
"symfony/phpunit-bridge": "^6.4.1|^7.0",
|
||||
"symfony/security-core": "^6.4|^7.0",
|
||||
"symfony/security-http": "^6.4|^7.0",
|
||||
"symfony/yaml": "^6.4|^7.0",
|
||||
"twig/twig": "^3.0|^4.x-dev"
|
||||
},
|
||||
|
@ -11135,7 +11136,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/symfony/maker-bundle/issues",
|
||||
"source": "https://github.com/symfony/maker-bundle/tree/v1.62.1"
|
||||
"source": "https://github.com/symfony/maker-bundle/tree/v1.64.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -11151,7 +11152,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-01-15T00:21:40+00:00"
|
||||
"time": "2025-06-23T16:12:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/phpunit-bridge",
|
||||
|
@ -11370,7 +11371,7 @@
|
|||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
@ -11380,6 +11381,6 @@
|
|||
"ext-fileinfo": "*",
|
||||
"ext-iconv": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
|
@ -544,6 +544,7 @@ class BusinessController extends AbstractController
|
|||
'plugRepservice' => true,
|
||||
'plugHrmDocs' => true,
|
||||
'plugGhestaManager' => true,
|
||||
'plugTaxSettings' => true,
|
||||
];
|
||||
} elseif ($perm) {
|
||||
$result = [
|
||||
|
@ -587,6 +588,7 @@ class BusinessController extends AbstractController
|
|||
'plugAccproPresell' => $perm->isPlugAccproPresell(),
|
||||
'plugHrmDocs' => $perm->isPlugHrmDocs(),
|
||||
'plugGhestaManager' => $perm->isPlugGhestaManager(),
|
||||
'plugTaxSettings' => $perm->isPlugTaxSettings(),
|
||||
];
|
||||
}
|
||||
return $this->json($result);
|
||||
|
|
484
hesabixCore/src/Controller/Plugins/TaxSettingsController.php
Normal file
484
hesabixCore/src/Controller/Plugins/TaxSettingsController.php
Normal file
|
@ -0,0 +1,484 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\Plugins;
|
||||
|
||||
use App\Service\Access;
|
||||
use App\Service\Extractor;
|
||||
use App\Service\Log;
|
||||
use App\Service\registryMGR;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use App\Entity\PluginTaxsettingsKey;
|
||||
use App\Entity\HesabdariDoc;
|
||||
use App\Entity\PluginTaxInvoice;
|
||||
|
||||
class TaxSettingsController extends AbstractController
|
||||
{
|
||||
#[Route('/api/plugins/tax/settings/get', name: 'plugin_tax_settings_get', methods: ['GET'])]
|
||||
public function plugin_tax_settings_get(EntityManagerInterface $em, Access $access): JsonResponse
|
||||
{
|
||||
$acc = $access->hasRole('plugTaxSettings');
|
||||
if (!$acc) {
|
||||
throw $this->createAccessDeniedException('شما دسترسی لازم را ندارید.');
|
||||
}
|
||||
|
||||
$businessId = is_object($acc['bid']) ? $acc['bid']->getId() : $acc['bid'];
|
||||
$userId = $this->getUser()->getId();
|
||||
|
||||
// دریافت تنظیمات از جدول اختصاصی
|
||||
$repo = $em->getRepository(PluginTaxsettingsKey::class);
|
||||
$entity = $repo->findOneBy(['business_id' => $businessId, 'user_id' => $userId]);
|
||||
|
||||
$settings = [
|
||||
'taxMemoryId' => $entity ? $entity->getTaxMemoryId() : '',
|
||||
'economicCode' => $entity ? $entity->getEconomicCode() : '',
|
||||
'privateKey' => $entity ? $entity->getPrivateKey() : '',
|
||||
];
|
||||
|
||||
return $this->json($settings);
|
||||
}
|
||||
|
||||
#[Route('/api/plugins/tax/settings/save', name: 'plugin_tax_settings_save', methods: ['POST'])]
|
||||
public function plugin_tax_settings_save(Request $request, registryMGR $registryMGR, Access $access, Log $log, EntityManagerInterface $em): JsonResponse
|
||||
{
|
||||
$acc = $access->hasRole('plugTaxSettings');
|
||||
if (!$acc) {
|
||||
throw $this->createAccessDeniedException('شما دسترسی لازم را ندارید.');
|
||||
}
|
||||
|
||||
$params = $request->getPayload()->all();
|
||||
$businessId = is_object($acc['bid']) ? $acc['bid']->getId() : $acc['bid'];
|
||||
$userId = $this->getUser()->getId();
|
||||
|
||||
// بررسی وجود رکورد قبلی
|
||||
$repo = $em->getRepository(PluginTaxsettingsKey::class);
|
||||
$entity = $repo->findOneBy(['business_id' => $businessId, 'user_id' => $userId]);
|
||||
if (!$entity) {
|
||||
$entity = new PluginTaxsettingsKey();
|
||||
$entity->setBusinessId($businessId);
|
||||
$entity->setUserId($userId);
|
||||
$entity->setCreatedAt(new \DateTime());
|
||||
}
|
||||
$entity->setPrivateKey($params['privateKey'] ?? '');
|
||||
$entity->setTaxMemoryId($params['taxMemoryId'] ?? null);
|
||||
$entity->setEconomicCode($params['economicCode'] ?? null);
|
||||
$entity->setUpdatedAt(new \DateTime());
|
||||
|
||||
$em->persist($entity);
|
||||
$em->flush();
|
||||
|
||||
$log->insert('تنظیمات مالیاتی', 'تنظیمات مالیاتی ذخیره شد (در جدول اختصاصی)', $this->getUser(), $businessId);
|
||||
|
||||
return $this->json(['success' => true, 'message' => 'تنظیمات با موفقیت ذخیره شد']);
|
||||
}
|
||||
|
||||
private function generatePrivateKey(): string
|
||||
{
|
||||
// تولید کلید خصوصی واقعی با OpenSSL
|
||||
$config = [
|
||||
"private_key_bits" => 2048,
|
||||
"private_key_type" => OPENSSL_KEYTYPE_RSA,
|
||||
];
|
||||
|
||||
$res = openssl_pkey_new($config);
|
||||
if (!$res) {
|
||||
throw new \Exception('خطا در تولید کلید خصوصی: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
$privateKey = '';
|
||||
if (!openssl_pkey_export($res, $privateKey)) {
|
||||
throw new \Exception('خطا در استخراج کلید خصوصی: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
openssl_pkey_free($res);
|
||||
return $privateKey;
|
||||
}
|
||||
|
||||
private function generatePublicKey(string $privateKey): string
|
||||
{
|
||||
// استخراج کلید عمومی از کلید خصوصی
|
||||
$res = openssl_pkey_get_private($privateKey);
|
||||
if (!$res) {
|
||||
throw new \Exception('خطا در خواندن کلید خصوصی: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
$keyDetails = openssl_pkey_get_details($res);
|
||||
if (!$keyDetails) {
|
||||
throw new \Exception('خطا در استخراج جزئیات کلید: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
openssl_pkey_free($res);
|
||||
return $keyDetails['key'];
|
||||
}
|
||||
|
||||
#[Route('/api/plugins/tax/settings/generate-csr', name: 'plugin_tax_settings_generate_csr', methods: ['POST'])]
|
||||
public function plugin_tax_settings_generate_csr(Request $request, registryMGR $registryMGR, Access $access, Log $log): JsonResponse
|
||||
{
|
||||
$acc = $access->hasRole('plugTaxSettings');
|
||||
if (!$acc) {
|
||||
throw $this->createAccessDeniedException('شما دسترسی لازم را ندارید.');
|
||||
}
|
||||
|
||||
$params = $request->getPayload()->all();
|
||||
|
||||
// بررسی فیلدهای اجباری
|
||||
if (empty($params['nationalId']) || empty($params['nameFa']) || empty($params['nameEn']) || empty($params['email'])) {
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'message' => 'تمام فیلدها الزامی هستند'
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
$privateKey = $this->generatePrivateKey();
|
||||
$publicKey = $this->generatePublicKey($privateKey);
|
||||
$csr = $this->generateCSR($privateKey, $params);
|
||||
|
||||
// هیچ ذخیرهای در دیتابیس انجام نمیشود
|
||||
$businessId = is_object($acc['bid']) ? $acc['bid']->getId() : $acc['bid'];
|
||||
$log->insert('تنظیمات مالیاتی', 'کلید و CSR تولید شد (بدون ذخیره)', $this->getUser(), $businessId);
|
||||
|
||||
return $this->json([
|
||||
'success' => true,
|
||||
'message' => 'کلید و CSR با موفقیت تولید شد',
|
||||
'privateKey' => $privateKey,
|
||||
'publicKey' => $publicKey,
|
||||
'csr' => $csr
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'message' => 'خطا در تولید کلید و CSR: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function generateCSR(string $privateKey, array $params): string
|
||||
{
|
||||
// تولید CSR واقعی با OpenSSL
|
||||
$dn = [
|
||||
"countryName" => "IR",
|
||||
"stateOrProvinceName" => "Tehran",
|
||||
"localityName" => "Tehran",
|
||||
"organizationName" => $params['nameEn'],
|
||||
"organizationalUnitName" => "Tax Department",
|
||||
"commonName" => $params['nameFa'],
|
||||
"emailAddress" => $params['email']
|
||||
];
|
||||
|
||||
// اضافه کردن شناسه ملی به عنوان extension
|
||||
$config = [
|
||||
"req" => [
|
||||
"distinguished_name" => $dn,
|
||||
"req_extensions" => "v3_req",
|
||||
"x509_extensions" => "v3_req"
|
||||
],
|
||||
"v3_req" => [
|
||||
"subjectAltName" => "email:" . $params['email'],
|
||||
"subjectKeyIdentifier" => "hash"
|
||||
]
|
||||
];
|
||||
|
||||
// ایجاد CSR
|
||||
$res = openssl_csr_new($dn, $privateKey, [
|
||||
'config' => $config,
|
||||
'digest_alg' => 'sha256',
|
||||
'req_extensions' => 'v3_req'
|
||||
]);
|
||||
|
||||
if (!$res) {
|
||||
throw new \Exception('خطا در تولید CSR: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
$csr = '';
|
||||
if (!openssl_csr_export($res, $csr)) {
|
||||
throw new \Exception('خطا در استخراج CSR: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
return $csr;
|
||||
}
|
||||
|
||||
#[Route('/api/plugins/tax/settings/send-invoice', name: 'plugin_tax_settings_send_invoice', methods: ['POST'])]
|
||||
public function plugin_tax_settings_send_invoice(Request $request, Access $access, Log $log, EntityManagerInterface $em): JsonResponse
|
||||
{
|
||||
$acc = $access->hasRole('plugTaxSettings');
|
||||
if (!$acc) {
|
||||
throw $this->createAccessDeniedException('شما دسترسی لازم را ندارید.');
|
||||
}
|
||||
|
||||
$params = $request->getPayload()->all();
|
||||
$invoiceCode = $params['code'] ?? null;
|
||||
|
||||
if (!$invoiceCode) {
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'message' => 'کد فاکتور الزامی است'
|
||||
]);
|
||||
}
|
||||
|
||||
$businessId = is_object($acc['bid']) ? $acc['bid']->getId() : $acc['bid'];
|
||||
$userId = $this->getUser()->getId();
|
||||
|
||||
try {
|
||||
// دریافت اطلاعات فاکتور از دیتابیس
|
||||
$invoiceRepo = $em->getRepository(HesabdariDoc::class);
|
||||
$invoice = $invoiceRepo->findOneBy([
|
||||
'code' => $invoiceCode,
|
||||
'bid' => $businessId,
|
||||
'type' => 'sell'
|
||||
]);
|
||||
|
||||
if (!$invoice) {
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'message' => 'فاکتور مورد نظر یافت نشد'
|
||||
]);
|
||||
}
|
||||
|
||||
// دریافت تنظیمات مالیاتی
|
||||
$taxRepo = $em->getRepository(PluginTaxsettingsKey::class);
|
||||
$taxSettings = $taxRepo->findOneBy([
|
||||
'business_id' => $businessId,
|
||||
'user_id' => $userId
|
||||
]);
|
||||
|
||||
if (!$taxSettings || !$taxSettings->getPrivateKey()) {
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'message' => 'تنظیمات مالیاتی تکمیل نشده است. لطفاً ابتدا تنظیمات را تکمیل کنید.'
|
||||
]);
|
||||
}
|
||||
|
||||
// اینجا کد ارسال به سامانه مودیان قرار میگیرد
|
||||
// فعلاً فقط پیام موفقیت برمیگردانیم
|
||||
$result = $this->sendInvoiceToTaxSystem($invoice, $taxSettings, $em, $businessId, $userId);
|
||||
|
||||
if ($result['success']) {
|
||||
$log->insert('ارسال به سامانه مودیان', 'فاکتور ' . $invoiceCode . ' به سامانه مودیان ارسال شد', $this->getUser(), $businessId);
|
||||
|
||||
return $this->json([
|
||||
'success' => true,
|
||||
'message' => 'فاکتور با موفقیت به سامانه مودیان ارسال شد',
|
||||
'data' => $result['data'] ?? null
|
||||
]);
|
||||
} else {
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'message' => $result['message'] ?? 'خطا در ارسال به سامانه مودیان'
|
||||
]);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$log->insert('خطا در ارسال به سامانه مودیان', 'خطا در ارسال فاکتور ' . $invoiceCode . ': ' . $e->getMessage(), $this->getUser(), $businessId);
|
||||
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'message' => 'خطا در ارسال به سامانه مودیان: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function sendInvoiceToTaxSystem($invoice, $taxSettings, $em, $businessId, $userId): array
|
||||
{
|
||||
try {
|
||||
// بررسی اینکه آیا این فاکتور قبلاً ارسال شده یا نه
|
||||
$taxInvoiceRepo = $em->getRepository(PluginTaxInvoice::class);
|
||||
$existingRecord = $taxInvoiceRepo->findByInvoiceCodeAndBusiness($invoice->getCode(), $businessId);
|
||||
|
||||
if ($existingRecord) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'این فاکتور قبلاً به سامانه مودیان ارسال شده است.'
|
||||
];
|
||||
}
|
||||
|
||||
// ایجاد رکورد جدید
|
||||
$taxInvoice = new PluginTaxInvoice();
|
||||
$taxInvoice->setBusiness($em->getRepository(\App\Entity\Business::class)->find($businessId));
|
||||
$taxInvoice->setUser($em->getRepository(\App\Entity\User::class)->find($userId));
|
||||
$taxInvoice->setInvoice($invoice);
|
||||
$taxInvoice->setInvoiceCode($invoice->getCode());
|
||||
$taxInvoice->setAmount($invoice->getAmount());
|
||||
$taxInvoice->setStatus('pending');
|
||||
|
||||
// دریافت اطلاعات مشتری
|
||||
$customerName = null;
|
||||
$customerId = null;
|
||||
$rows = $invoice->getHesabdariRows();
|
||||
foreach ($rows as $row) {
|
||||
if ($row->getPerson()) {
|
||||
$customerName = $row->getPerson()->getNikename();
|
||||
$customerId = $row->getPerson()->getCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
$taxInvoice->setCustomerName($customerName);
|
||||
$taxInvoice->setCustomerId($customerId);
|
||||
|
||||
// ذخیره رکورد
|
||||
$em->persist($taxInvoice);
|
||||
$em->flush();
|
||||
|
||||
// اینجا کد واقعی ارسال به سامانه مودیان قرار میگیرد
|
||||
// فعلاً یک پیام موفقیت برمیگردانیم
|
||||
|
||||
// مثال کد ارسال به API سامانه مودیان:
|
||||
/*
|
||||
$invoiceData =
|
||||
invoiceNumber => $invoice->getCode(),
|
||||
date => $invoice->getDate(),
|
||||
totalAmount => $invoice->getAmount(),
|
||||
customerName=> $customerName,
|
||||
customerNationalId' => $customerNationalId,
|
||||
// سایر اطلاعات فاکتور
|
||||
];
|
||||
|
||||
$response = $this->callTaxSystemAPI($invoiceData, $taxSettings);
|
||||
|
||||
if ($response['success']) {
|
||||
// بهروزرسانی وضعیت به sent
|
||||
$taxInvoice->setStatus('sent');
|
||||
$taxInvoice->setSentAt(new \DateTimeImmutable());
|
||||
$taxInvoice->setTaxSystemInvoiceNumber($response['data']['invoiceNumber'] ?? null);
|
||||
$taxInvoice->setTaxSystemReferenceNumber($response['data']['referenceNumber'] ?? null);
|
||||
$taxInvoice->setResponseData(json_encode($response['data']));
|
||||
$em->flush();
|
||||
|
||||
return [
|
||||
success' => true,
|
||||
data' => $response['data] ];
|
||||
} else {
|
||||
// بهروزرسانی وضعیت به failed
|
||||
$taxInvoice->setStatus('failed');
|
||||
$taxInvoice->setErrorMessage($response['message']);
|
||||
$em->flush();
|
||||
|
||||
return [
|
||||
success' => false,
|
||||
message' => $response['message] ];
|
||||
}
|
||||
*/
|
||||
|
||||
// فعلاً برای تست، پیام موفقیت برمیگردانیم
|
||||
$taxInvoice->setStatus('sent');
|
||||
$taxInvoice->setSentAt(new \DateTimeImmutable());
|
||||
$taxInvoice->setTaxSystemInvoiceNumber('TAX-' . $invoice->getCode());
|
||||
$taxInvoice->setTaxSystemReferenceNumber('REF-' . $invoice->getCode());
|
||||
$taxInvoice->setResponseData(json_encode(['status' => 'success', 'message' => 'Test response']));
|
||||
$em->flush();
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'invoiceNumber' => $invoice->getCode(),
|
||||
'taxSystemInvoiceNumber' => $taxInvoice->getTaxSystemInvoiceNumber(),
|
||||
'taxSystemReferenceNumber' => $taxInvoice->getTaxSystemReferenceNumber(),
|
||||
'sentAt' => $taxInvoice->getSentAt()->format('Y-m-d H:i:s')
|
||||
]
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// در صورت خطا، وضعیت را به failed تغییر دهید
|
||||
if (isset($taxInvoice)) {
|
||||
$taxInvoice->setStatus('failed');
|
||||
$taxInvoice->setErrorMessage($e->getMessage());
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'خطا در ارسال به سامانه مودیان: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/api/plugins/tax/invoices/list', name: 'plugin_tax_settings_invoices_list', methods: ['GET'])]
|
||||
public function plugin_tax_settings_invoices_list(Request $request, Access $access, EntityManagerInterface $em): JsonResponse
|
||||
{
|
||||
$acc = $access->hasRole('plugTaxSettings');
|
||||
if (!$acc) {
|
||||
throw $this->createAccessDeniedException('شما دسترسی لازم را ندارید.');
|
||||
}
|
||||
|
||||
$businessId = is_object($acc['bid']) ? $acc['bid']->getId() : $acc['bid'];
|
||||
|
||||
try {
|
||||
$taxInvoiceRepo = $em->getRepository(PluginTaxInvoice::class);
|
||||
$invoices = $taxInvoiceRepo->findByBusiness($businessId);
|
||||
|
||||
$result = [];
|
||||
foreach ($invoices as $taxInvoice) {
|
||||
$invoice = $taxInvoice->getInvoice();
|
||||
|
||||
// دریافت اطلاعات کامل فاکتور اصلی
|
||||
$invoiceDetails = null;
|
||||
if ($invoice) {
|
||||
$invoiceDetails = [
|
||||
'id' => $invoice->getId(),
|
||||
'code' => $invoice->getCode(),
|
||||
'date' => $invoice->getDate(),
|
||||
'des' => $invoice->getDes(),
|
||||
'amount' => $invoice->getAmount(),
|
||||
'type' => $invoice->getType(),
|
||||
'status' => $invoice->getStatus(),
|
||||
'shortlink' => $invoice->getShortlink(),
|
||||
'taxPercent' => $invoice->getTaxPercent(),
|
||||
'discountType' => $invoice->getDiscountType(),
|
||||
'discountPercent' => $invoice->getDiscountPercent()
|
||||
];
|
||||
}
|
||||
|
||||
$result[] = [
|
||||
'id' => $taxInvoice->getId(),
|
||||
'invoiceNumber' => $taxInvoice->getInvoiceCode(),
|
||||
'date' => $invoice ? $invoice->getDate() : null,
|
||||
'customerName' => $taxInvoice->getCustomerName(),
|
||||
'customerId' => $taxInvoice->getCustomerId(),
|
||||
'totalAmount' => $taxInvoice->getAmount(),
|
||||
'status' => $taxInvoice->getStatus(),
|
||||
'sentDate' => $taxInvoice->getSentAt() ? $taxInvoice->getSentAt()->format('Y-m-d H:i:s') : null,
|
||||
'errorMessage' => $taxInvoice->getErrorMessage(),
|
||||
'createdAt' => $taxInvoice->getCreatedAt()->format('Y-m-d H:i:s'),
|
||||
'uniqueTaxNumber' => $taxInvoice->getTaxSystemInvoiceNumber(),
|
||||
'referenceUniqueTaxNumber' => $taxInvoice->getTaxSystemReferenceNumber(),
|
||||
'invoiceType' => $this->getInvoiceType($invoice),
|
||||
'invoiceDetails' => $invoiceDetails
|
||||
];
|
||||
}
|
||||
|
||||
return $this->json([
|
||||
'success' => true,
|
||||
'data' => $result
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'message' => 'خطا در دریافت لیست فاکتورها: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function getInvoiceType($invoice): string
|
||||
{
|
||||
if (!$invoice) {
|
||||
return 'اصلی';
|
||||
}
|
||||
|
||||
switch ($invoice->getType()) {
|
||||
case 'sell':
|
||||
return 'اصلی';
|
||||
case 'return_sell':
|
||||
return 'برگشت از فروش';
|
||||
case 'correction':
|
||||
return 'اصلاحی';
|
||||
case 'cancel':
|
||||
return 'ابطالی';
|
||||
default:
|
||||
return 'اصلی';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -129,6 +129,9 @@ class Permission
|
|||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $plugGhestaManager = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $plugTaxSettings = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
|
@ -590,4 +593,16 @@ class Permission
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function isPlugTaxSettings(): ?bool
|
||||
{
|
||||
return $this->plugTaxSettings;
|
||||
}
|
||||
|
||||
public function setPlugTaxSettings(?bool $plugTaxSettings): static
|
||||
{
|
||||
$this->plugTaxSettings = $plugTaxSettings;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
239
hesabixCore/src/Entity/PluginTaxInvoice.php
Normal file
239
hesabixCore/src/Entity/PluginTaxInvoice.php
Normal file
|
@ -0,0 +1,239 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\PluginTaxInvoiceRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: PluginTaxInvoiceRepository::class)]
|
||||
class PluginTaxInvoice
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?Business $business = null;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?User $user = null;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?HesabdariDoc $invoice = null;
|
||||
|
||||
#[ORM\Column(length:255)]
|
||||
private ?string $invoiceCode = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $taxSystemInvoiceNumber = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $taxSystemReferenceNumber = null;
|
||||
|
||||
#[ORM\Column(length:255)]
|
||||
private ?string $status = 'pending'; // pending, sent, failed, confirmed
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $responseData = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $errorMessage = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?\DateTimeImmutable $createdAt = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?\DateTimeImmutable $sentAt = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?\DateTimeImmutable $confirmedAt = null;
|
||||
|
||||
#[ORM\Column(type: Types::DECIMAL, precision: 30, scale: 0)]
|
||||
private ?string $amount = '0';
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $customerName = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $customerId = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->createdAt = new \DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getBusiness(): ?Business
|
||||
{
|
||||
return $this->business;
|
||||
}
|
||||
|
||||
public function setBusiness(?Business $business): static
|
||||
{
|
||||
$this->business = $business;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUser(): ?User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function setUser(?User $user): static
|
||||
{
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInvoice(): ?HesabdariDoc
|
||||
{
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
public function setInvoice(?HesabdariDoc $invoice): static
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInvoiceCode(): ?string
|
||||
{
|
||||
return $this->invoiceCode;
|
||||
}
|
||||
|
||||
public function setInvoiceCode(string $invoiceCode): static
|
||||
{
|
||||
$this->invoiceCode = $invoiceCode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTaxSystemInvoiceNumber(): ?string
|
||||
{
|
||||
return $this->taxSystemInvoiceNumber;
|
||||
}
|
||||
|
||||
public function setTaxSystemInvoiceNumber(?string $taxSystemInvoiceNumber): static
|
||||
{
|
||||
$this->taxSystemInvoiceNumber = $taxSystemInvoiceNumber;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTaxSystemReferenceNumber(): ?string
|
||||
{
|
||||
return $this->taxSystemReferenceNumber;
|
||||
}
|
||||
|
||||
public function setTaxSystemReferenceNumber(?string $taxSystemReferenceNumber): static
|
||||
{
|
||||
$this->taxSystemReferenceNumber = $taxSystemReferenceNumber;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStatus(): ?string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function setStatus(string $status): static
|
||||
{
|
||||
$this->status = $status;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getResponseData(): ?string
|
||||
{
|
||||
return $this->responseData;
|
||||
}
|
||||
|
||||
public function setResponseData(?string $responseData): static
|
||||
{
|
||||
$this->responseData = $responseData;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getErrorMessage(): ?string
|
||||
{
|
||||
return $this->errorMessage;
|
||||
}
|
||||
|
||||
public function setErrorMessage(?string $errorMessage): static
|
||||
{
|
||||
$this->errorMessage = $errorMessage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function setCreatedAt(\DateTimeImmutable $createdAt): static
|
||||
{
|
||||
$this->createdAt = $createdAt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSentAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->sentAt;
|
||||
}
|
||||
|
||||
public function setSentAt(?\DateTimeImmutable $sentAt): static
|
||||
{
|
||||
$this->sentAt = $sentAt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getConfirmedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->confirmedAt;
|
||||
}
|
||||
|
||||
public function setConfirmedAt(?\DateTimeImmutable $confirmedAt): static
|
||||
{
|
||||
$this->confirmedAt = $confirmedAt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAmount(): ?string
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
public function setAmount(string $amount): static
|
||||
{
|
||||
$this->amount = $amount;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustomerName(): ?string
|
||||
{
|
||||
return $this->customerName;
|
||||
}
|
||||
|
||||
public function setCustomerName(?string $customerName): static
|
||||
{
|
||||
$this->customerName = $customerName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustomerId(): ?string
|
||||
{
|
||||
return $this->customerId;
|
||||
}
|
||||
|
||||
public function setCustomerId(?string $customerId): static
|
||||
{
|
||||
$this->customerId = $customerId;
|
||||
return $this;
|
||||
}
|
||||
}
|
53
hesabixCore/src/Entity/PluginTaxsettingsKey.php
Normal file
53
hesabixCore/src/Entity/PluginTaxsettingsKey.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: "plugin_tax_settings")]
|
||||
class PluginTaxsettingsKey
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: "integer")]
|
||||
private $id;
|
||||
|
||||
#[ORM\Column(type: "integer")]
|
||||
private $business_id;
|
||||
|
||||
#[ORM\Column(type: "integer")]
|
||||
private $user_id;
|
||||
|
||||
#[ORM\Column(type: "text", nullable: true)]
|
||||
private $private_key;
|
||||
|
||||
#[ORM\Column(type: "string", length: 64, nullable: true)]
|
||||
private $tax_memory_id;
|
||||
|
||||
#[ORM\Column(type: "string", length: 64, nullable: true)]
|
||||
private $economic_code;
|
||||
|
||||
#[ORM\Column(type: "datetime")]
|
||||
private $created_at;
|
||||
|
||||
#[ORM\Column(type: "datetime")]
|
||||
private $updated_at;
|
||||
|
||||
// Getters and setters ...
|
||||
public function getId() { return $this->id; }
|
||||
public function getBusinessId() { return $this->business_id; }
|
||||
public function setBusinessId($val) { $this->business_id = $val; }
|
||||
public function getUserId() { return $this->user_id; }
|
||||
public function setUserId($val) { $this->user_id = $val; }
|
||||
public function getPrivateKey() { return $this->private_key; }
|
||||
public function setPrivateKey($val) { $this->private_key = $val; }
|
||||
public function getTaxMemoryId() { return $this->tax_memory_id; }
|
||||
public function setTaxMemoryId($val) { $this->tax_memory_id = $val; }
|
||||
public function getEconomicCode() { return $this->economic_code; }
|
||||
public function setEconomicCode($val) { $this->economic_code = $val; }
|
||||
public function getCreatedAt() { return $this->created_at; }
|
||||
public function setCreatedAt($val) { $this->created_at = $val; }
|
||||
public function getUpdatedAt() { return $this->updated_at; }
|
||||
public function setUpdatedAt($val) { $this->updated_at = $val; }
|
||||
}
|
106
hesabixCore/src/Repository/PluginTaxInvoiceRepository.php
Normal file
106
hesabixCore/src/Repository/PluginTaxInvoiceRepository.php
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\PluginTaxInvoice;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<PluginTaxInvoice>
|
||||
*
|
||||
* @method PluginTaxInvoice|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method PluginTaxInvoice|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method PluginTaxInvoice findAll()
|
||||
* @method PluginTaxInvoice findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class PluginTaxInvoiceRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, PluginTaxInvoice::class);
|
||||
}
|
||||
|
||||
public function save(PluginTaxInvoice $entity, bool $flush = false): void
|
||||
{
|
||||
$this->getEntityManager()->persist($entity);
|
||||
|
||||
if ($flush) {
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
}
|
||||
|
||||
public function remove(PluginTaxInvoice $entity, bool $flush = false): void
|
||||
{
|
||||
$this->getEntityManager()->remove($entity);
|
||||
|
||||
if ($flush) {
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* پیدا کردن فاکتورهای ارسال شده برای یک کسبوکار
|
||||
*/
|
||||
public function findByBusiness($businessId, $limit = null, $offset = null)
|
||||
{
|
||||
$qb = $this->createQueryBuilder('pti')
|
||||
->leftJoin('pti.invoice', 'invoice')
|
||||
->leftJoin('pti.user', 'user')
|
||||
->where('pti.business = :businessId')
|
||||
->setParameter('businessId', $businessId)
|
||||
->orderBy('pti.createdAt', 'DESC');
|
||||
if ($limit) {
|
||||
$qb->setMaxResults($limit);
|
||||
}
|
||||
if ($offset) {
|
||||
$qb->setFirstResult($offset);
|
||||
}
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* پیدا کردن فاکتور بر اساس کد فاکتور و کسبوکار
|
||||
*/
|
||||
public function findByInvoiceCodeAndBusiness($invoiceCode, $businessId)
|
||||
{
|
||||
return $this->createQueryBuilder('pti')
|
||||
->where('pti.invoiceCode = :invoiceCode')
|
||||
->andWhere('pti.business = :businessId')
|
||||
->setParameter('invoiceCode', $invoiceCode)
|
||||
->setParameter('businessId', $businessId)
|
||||
->getQuery()
|
||||
->getOneOrNullResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* آمار فاکتورهای ارسال شده بر اساس وضعیت
|
||||
*/
|
||||
public function getStatusStats($businessId)
|
||||
{
|
||||
$qb = $this->createQueryBuilder('pti')
|
||||
->select('pti.status, COUNT(pti.id) as count')
|
||||
->where('pti.business = :businessId')
|
||||
->setParameter('businessId', $businessId)
|
||||
->groupBy('pti.status');
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* فاکتورهای با وضعیت مشخص
|
||||
*/
|
||||
public function findByStatus($businessId, $status)
|
||||
{
|
||||
return $this->createQueryBuilder('pti')
|
||||
->leftJoin('pti.invoice', 'invoice')
|
||||
->where('pti.business = :businessId')
|
||||
->andWhere('pti.status = :status')
|
||||
->setParameter('businessId', $businessId)
|
||||
->setParameter('status', $status)
|
||||
->orderBy('pti.createdAt', 'DESC')
|
||||
->getQuery()
|
||||
->getResult();
|
||||
}
|
||||
}
|
|
@ -8,6 +8,15 @@
|
|||
"ref": "64d8583af5ea57b7afa4aba4b159907f3a148b05"
|
||||
}
|
||||
},
|
||||
"doctrine/deprecations": {
|
||||
"version": "1.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "1.0",
|
||||
"ref": "87424683adc81d7dc305eefec1fced883084aab9"
|
||||
}
|
||||
},
|
||||
"doctrine/doctrine-bundle": {
|
||||
"version": "2.10",
|
||||
"recipe": {
|
||||
|
|
0
webUI/.github/workflows/release.yml
vendored
Normal file → Executable file
0
webUI/.github/workflows/release.yml
vendored
Normal file → Executable file
0
webUI/.gitignore
vendored
Normal file → Executable file
0
webUI/.gitignore
vendored
Normal file → Executable file
0
webUI/LICENSE
Normal file → Executable file
0
webUI/LICENSE
Normal file → Executable file
0
webUI/env.d.ts
vendored
Normal file → Executable file
0
webUI/env.d.ts
vendored
Normal file → Executable file
0
webUI/index.html
Normal file → Executable file
0
webUI/index.html
Normal file → Executable file
0
webUI/package.json
Normal file → Executable file
0
webUI/package.json
Normal file → Executable file
0
webUI/public/.htaccess
Normal file → Executable file
0
webUI/public/.htaccess
Normal file → Executable file
0
webUI/public/dashmix/dashmix.app.min.js
vendored
Normal file → Executable file
0
webUI/public/dashmix/dashmix.app.min.js
vendored
Normal file → Executable file
0
webUI/public/dashmix/dashmix.min.css
vendored
Normal file → Executable file
0
webUI/public/dashmix/dashmix.min.css
vendored
Normal file → Executable file
0
webUI/public/favicon.ico
Normal file → Executable file
0
webUI/public/favicon.ico
Normal file → Executable file
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
0
webUI/public/fonts/fontawesome/fa-brands-400.ttf
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-brands-400.ttf
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-brands-400.woff2
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-brands-400.woff2
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-regular-400.ttf
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-regular-400.ttf
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-regular-400.woff2
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-regular-400.woff2
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-solid-900.ttf
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-solid-900.ttf
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-solid-900.woff2
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-solid-900.woff2
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-v4compatibility.ttf
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-v4compatibility.ttf
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-v4compatibility.woff2
Normal file → Executable file
0
webUI/public/fonts/fontawesome/fa-v4compatibility.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-300.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-300.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-500.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-500.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-600.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-600.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-700.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-700.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-800.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-800.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-900.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-900.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-regular.woff2
Normal file → Executable file
0
webUI/public/fonts/inter/inter-v11-latin-regular.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Black-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Black-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Black-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Black-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Black-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Black-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Black-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Black-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Bold-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Bold-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Bold-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Bold-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Bold-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Bold-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Bold-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Bold-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Light-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Light-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Light-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Light-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Light-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Light-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Light-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-Light-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-SemiBold-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-SemiBold-FD.eot
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-SemiBold-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-SemiBold-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-SemiBold-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-SemiBold-FD.woff
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-SemiBold-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/Sahel-SemiBold-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/sahel/sahel.css
Normal file → Executable file
0
webUI/public/fonts/sahel/sahel.css
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Bold-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Bold-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Bold-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Bold-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Bold-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Bold-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Bold-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Bold-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Light-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Light-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Light-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Light-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Light-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Light-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Light-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Light-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Medium-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Medium-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Medium-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Medium-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Medium-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Medium-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Medium-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Medium-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Thin-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Thin-FD.eot
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Thin-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Thin-FD.ttf
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Thin-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Thin-FD.woff
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Thin-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/Shabnam-Thin-FD.woff2
Normal file → Executable file
0
webUI/public/fonts/shabnam/shabnam.css
Normal file → Executable file
0
webUI/public/fonts/shabnam/shabnam.css
Normal file → Executable file
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.eot
Normal file → Executable file
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.eot
Normal file → Executable file
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.svg
Normal file → Executable file
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.svg
Normal file → Executable file
Before Width: | Height: | Size: 235 KiB After Width: | Height: | Size: 235 KiB |
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.ttf
Normal file → Executable file
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.ttf
Normal file → Executable file
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.woff
Normal file → Executable file
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.woff
Normal file → Executable file
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.woff2
Normal file → Executable file
0
webUI/public/fonts/simple-line-icons/Simple-Line-Icons.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Black.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Black.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Bold.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Bold.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-ExtraBold.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-ExtraBold.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-ExtraLight.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-ExtraLight.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Light.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Light.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Medium.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Medium.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Regular.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Regular.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-SemiBold.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-SemiBold.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Thin.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/ttf/Vazirmatn-Thin.ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/variable/Vazirmatn[wght].ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/variable/Vazirmatn[wght].ttf
Normal file → Executable file
0
webUI/public/fonts/vazir/vazir.css
Normal file → Executable file
0
webUI/public/fonts/vazir/vazir.css
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-Black.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-Black.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-Bold.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-Bold.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-ExtraBold.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-ExtraBold.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-ExtraLight.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-ExtraLight.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-FD-Black.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-FD-Black.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-FD-Bold.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-FD-Bold.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-FD-ExtraBold.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-FD-ExtraBold.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-FD-ExtraLight.woff2
Normal file → Executable file
0
webUI/public/fonts/vazir/webfonts/Vazirmatn-FD-ExtraLight.woff2
Normal file → Executable file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue