Compare commits
No commits in common. "dad184671ba2a9f255eebc64b345755af177674e" and "888c76c63315f26859065be56eaf1ddd9dbb319b" have entirely different histories.
dad184671b
...
888c76c633
|
@ -23,20 +23,6 @@ services:
|
||||||
networks:
|
networks:
|
||||||
- hesabix-network
|
- hesabix-network
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: >
|
|
||||||
bash -c "
|
|
||||||
apt-get update &&
|
|
||||||
apt-get install -y curl unzip php-mbstring php-gd php-soap &&
|
|
||||||
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer &&
|
|
||||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - &&
|
|
||||||
apt-get install -y nodejs &&
|
|
||||||
cd /var/www/html/hesabixCore &&
|
|
||||||
composer install &&
|
|
||||||
cd /var/www/html/webUI &&
|
|
||||||
npm install &&
|
|
||||||
npm run build-only &&
|
|
||||||
apache2-foreground
|
|
||||||
"
|
|
||||||
|
|
||||||
# Database service
|
# Database service
|
||||||
db:
|
db:
|
||||||
|
@ -48,7 +34,7 @@ services:
|
||||||
- MYSQL_PASSWORD=hesabix_password
|
- MYSQL_PASSWORD=hesabix_password
|
||||||
volumes:
|
volumes:
|
||||||
- mysql_data:/var/lib/mysql
|
- mysql_data:/var/lib/mysql
|
||||||
- ./hesabixBackup/databasefiles:/docker-entrypoint-initdb.d
|
- ./hesabixBackup:/docker-entrypoint-initdb.d
|
||||||
networks:
|
networks:
|
||||||
- hesabix-network
|
- hesabix-network
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
@ -57,12 +43,6 @@ services:
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: >
|
|
||||||
bash -c "
|
|
||||||
docker-entrypoint.sh mysqld &
|
|
||||||
sleep 30 &&
|
|
||||||
mysql -u root -proot_password hesabix_db < /docker-entrypoint-initdb.d/hesabix-db-default.sql
|
|
||||||
"
|
|
||||||
|
|
||||||
# phpMyAdmin service
|
# phpMyAdmin service
|
||||||
phpmyadmin:
|
phpmyadmin:
|
||||||
|
|
|
@ -1938,5 +1938,4 @@ class PersonsController extends AbstractController
|
||||||
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
|
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,16 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use App\Entity\PlugHrmDoc;
|
use App\Entity\PlugGhestaDoc;
|
||||||
use App\Entity\PlugHrmDocItem;
|
use App\Entity\PlugGhestaItem;
|
||||||
|
use App\Entity\HesabdariDoc;
|
||||||
use App\Entity\Person;
|
use App\Entity\Person;
|
||||||
use App\Service\Access;
|
use App\Service\Access;
|
||||||
|
use App\Service\Provider;
|
||||||
|
use App\Service\Printers;
|
||||||
|
use App\Entity\PrintOptions;
|
||||||
use App\Service\Log;
|
use App\Service\Log;
|
||||||
|
use App\Entity\Business;
|
||||||
|
|
||||||
class DocsController extends AbstractController
|
class DocsController extends AbstractController
|
||||||
{
|
{
|
||||||
|
@ -23,209 +28,24 @@ class DocsController extends AbstractController
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/api/hrm/docs/list', name: 'hrm_docs_list', methods: ['POST'])]
|
#[Route('/api/hrm/docs/list', name: 'hrm_docs_list', methods: ['POST'])]
|
||||||
public function list(Request $request, Access $access): JsonResponse
|
public function list(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
// TODO: پیادهسازی دریافت لیست اسناد حقوق
|
||||||
$params = [];
|
return new JsonResponse([]);
|
||||||
if ($content = $request->getContent()) {
|
|
||||||
$params = json_decode($content, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$acc = $access->hasRole('hrm');
|
|
||||||
|
|
||||||
// دریافت پارامترهای فیلتر
|
|
||||||
$page = $params['page'] ?? 1;
|
|
||||||
$limit = $params['limit'] ?? 20;
|
|
||||||
$search = $params['search'] ?? '';
|
|
||||||
$fromDate = $params['fromDate'] ?? null;
|
|
||||||
$toDate = $params['toDate'] ?? null;
|
|
||||||
$personId = $params['personId'] ?? null;
|
|
||||||
|
|
||||||
// ایجاد کوئری
|
|
||||||
$qb = $this->entityManager->createQueryBuilder();
|
|
||||||
$qb->select('d')
|
|
||||||
->from(PlugHrmDoc::class, 'd')
|
|
||||||
->where('d.business = :bid')
|
|
||||||
->setParameter('bid', $acc['bid']);
|
|
||||||
|
|
||||||
// اعمال فیلترها
|
|
||||||
if ($search) {
|
|
||||||
$qb->andWhere('d.description LIKE :search')
|
|
||||||
->setParameter('search', '%' . $search . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($fromDate) {
|
|
||||||
$qb->andWhere('d.date >= :fromDate')
|
|
||||||
->setParameter('fromDate', $fromDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($toDate) {
|
|
||||||
$qb->andWhere('d.date <= :toDate')
|
|
||||||
->setParameter('toDate', $toDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($personId) {
|
|
||||||
$qb->andWhere('d.person = :personId')
|
|
||||||
->setParameter('personId', $personId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// محاسبه تعداد کل رکوردها
|
|
||||||
$countQb = clone $qb;
|
|
||||||
$countQb->select('COUNT(d.id)');
|
|
||||||
$total = $countQb->getQuery()->getSingleScalarResult();
|
|
||||||
|
|
||||||
// اعمال مرتبسازی و صفحهبندی
|
|
||||||
$qb->orderBy('d.date', 'DESC')
|
|
||||||
->setFirstResult(($page - 1) * $limit)
|
|
||||||
->setMaxResults($limit);
|
|
||||||
|
|
||||||
$docs = $qb->getQuery()->getResult();
|
|
||||||
|
|
||||||
// تبدیل نتایج به آرایه
|
|
||||||
$result = [];
|
|
||||||
foreach ($docs as $doc) {
|
|
||||||
$result[] = [
|
|
||||||
'id' => $doc->getId(),
|
|
||||||
'date' => $doc->getDate(),
|
|
||||||
'description' => $doc->getDescription(),
|
|
||||||
'creator' => $doc->getCreator() ? [
|
|
||||||
'id' => $doc->getCreator()->getId(),
|
|
||||||
'name' => $doc->getCreator()->getFullName()
|
|
||||||
] : null,
|
|
||||||
'total' => $this->calculateTotalAmount($doc),
|
|
||||||
'accounting_doc' => $doc->getHesabdariDoc() ? 'صدور شده' : 'صدور نشده',
|
|
||||||
'status' => $doc->getHesabdariDoc() ? 'تایید شده' : 'تایید نشده'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JsonResponse([
|
|
||||||
'success' => true,
|
|
||||||
'data' => $result,
|
|
||||||
'total' => $total,
|
|
||||||
'page' => $page,
|
|
||||||
'limit' => $limit
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return new JsonResponse(['error' => 'خطا در دریافت لیست اسناد: ' . $e->getMessage()], 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function calculateTotalAmount(PlugHrmDoc $doc): int
|
|
||||||
{
|
|
||||||
$total = 0;
|
|
||||||
foreach ($doc->getItems() as $item) {
|
|
||||||
$total += $item->getBaseSalary();
|
|
||||||
$total += $item->getNight();
|
|
||||||
$total += $item->getShift();
|
|
||||||
$total += $item->getOvertime();
|
|
||||||
}
|
|
||||||
return $total;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/api/hrm/docs/get/{id}', name: 'hrm_docs_get', methods: ['POST'])]
|
#[Route('/api/hrm/docs/get/{id}', name: 'hrm_docs_get', methods: ['POST'])]
|
||||||
public function get(int $id, Access $access): JsonResponse
|
public function get(int $id): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
// TODO: پیادهسازی دریافت اطلاعات یک سند حقوق
|
||||||
$acc = $access->hasRole('hrm');
|
return new JsonResponse([]);
|
||||||
|
|
||||||
$doc = $this->entityManager->getRepository(PlugHrmDoc::class)->findOneBy([
|
|
||||||
'id' => $id,
|
|
||||||
'business' => $acc['bid']
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!$doc) {
|
|
||||||
return new JsonResponse(['error' => 'سند مورد نظر یافت نشد'], 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$items = [];
|
|
||||||
foreach ($doc->getItems() as $item) {
|
|
||||||
$items[] = [
|
|
||||||
'id' => $item->getId(),
|
|
||||||
'person' => [
|
|
||||||
'id' => $item->getPerson()->getId(),
|
|
||||||
'name' => $item->getPerson()->getNikename(),
|
|
||||||
'code' => $item->getPerson()->getCode(),
|
|
||||||
],
|
|
||||||
'baseSalary' => $item->getBaseSalary(),
|
|
||||||
'overtime' => $item->getOvertime(),
|
|
||||||
'shift' => $item->getShift(),
|
|
||||||
'night' => $item->getNight(),
|
|
||||||
'description' => $item->getDescription()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JsonResponse([
|
|
||||||
'success' => true,
|
|
||||||
'data' => [
|
|
||||||
'id' => $doc->getId(),
|
|
||||||
'date' => $doc->getDate(),
|
|
||||||
'description' => $doc->getDescription(),
|
|
||||||
'items' => $items
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return new JsonResponse(['error' => 'خطا در دریافت اطلاعات سند: ' . $e->getMessage()], 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/api/hrm/docs/insert', name: 'hrm_docs_insert', methods: ['POST'])]
|
#[Route('/api/hrm/docs/insert', name: 'hrm_docs_insert', methods: ['POST'])]
|
||||||
public function insert(Request $request, Access $access, Log $log): JsonResponse
|
public function insert(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
// TODO: پیادهسازی ثبت سند حقوق جدید
|
||||||
$params = [];
|
return new JsonResponse([]);
|
||||||
if ($content = $request->getContent()) {
|
|
||||||
$params = json_decode($content, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$acc = $access->hasRole('hrm');
|
|
||||||
|
|
||||||
// بررسی دادههای ورودی
|
|
||||||
if (empty($params['date']) || empty($params['description']) || empty($params['items'])) {
|
|
||||||
return new JsonResponse(['error' => 'اطلاعات ناقص است'], 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ایجاد سند جدید
|
|
||||||
$doc = new PlugHrmDoc();
|
|
||||||
$doc->setDate($params['date']);
|
|
||||||
$doc->setCreator($this->getUser());
|
|
||||||
$doc->setBusiness($acc['bid']);
|
|
||||||
$doc->setDescription($params['description']);
|
|
||||||
$doc->setCreateDate(time());
|
|
||||||
// افزودن آیتمها
|
|
||||||
foreach ($params['items'] as $itemData) {
|
|
||||||
if (empty($itemData['person'])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$item = new PlugHrmDocItem();
|
|
||||||
$item->setPerson($this->entityManager->getReference(Person::class, $itemData['person']));
|
|
||||||
$item->setBaseSalary($itemData['baseSalary'] ?? 0);
|
|
||||||
$item->setOvertime($itemData['overtime'] ?? 0);
|
|
||||||
$item->setShift($itemData['shift'] ?? 0);
|
|
||||||
$item->setNight($itemData['night'] ?? 0);
|
|
||||||
$item->setDescription($itemData['description'] ?? '');
|
|
||||||
$item->setDoc($doc);
|
|
||||||
|
|
||||||
$this->entityManager->persist($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->entityManager->persist($doc);
|
|
||||||
$this->entityManager->flush();
|
|
||||||
|
|
||||||
|
|
||||||
return new JsonResponse([
|
|
||||||
'success' => true,
|
|
||||||
'message' => 'سند با موفقیت ثبت شد',
|
|
||||||
'data' => [
|
|
||||||
'id' => $doc->getId()
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return new JsonResponse(['error' => 'خطا در ثبت سند: ' . $e->getMessage()], 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/api/hrm/docs/update', name: 'hrm_docs_update', methods: ['POST'])]
|
#[Route('/api/hrm/docs/update', name: 'hrm_docs_update', methods: ['POST'])]
|
||||||
|
@ -236,47 +56,9 @@ class DocsController extends AbstractController
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/api/hrm/docs/delete', name: 'hrm_docs_delete', methods: ['POST'])]
|
#[Route('/api/hrm/docs/delete', name: 'hrm_docs_delete', methods: ['POST'])]
|
||||||
public function delete(Request $request, Access $access, Log $log, EntityManagerInterface $entityManager): JsonResponse
|
public function delete(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
// TODO: پیادهسازی حذف سند حقوق
|
||||||
$params = [];
|
return new JsonResponse([]);
|
||||||
if ($content = $request->getContent()) {
|
|
||||||
$params = json_decode($content, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$acc = $access->hasRole('hrm');
|
|
||||||
$id = $params['id'] ?? null;
|
|
||||||
|
|
||||||
if (!$id) {
|
|
||||||
return new JsonResponse(['error' => 'شناسه سند الزامی است'], 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
$doc = $entityManager->getRepository(PlugHrmDoc::class)->findOneBy([
|
|
||||||
'id' => $id,
|
|
||||||
'business' => $acc['bid']
|
|
||||||
]);
|
|
||||||
if (!$doc) {
|
|
||||||
return new JsonResponse(['error' => 'سند مورد نظر یافت نشد'], 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
// حذف آیتمهای سند
|
|
||||||
foreach ($doc->getItems() as $item) {
|
|
||||||
$entityManager->remove($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// حذف سند حسابداری در صورت وجود
|
|
||||||
if($doc->getHesabdariDoc()){
|
|
||||||
$entityManager->remove($doc->getHesabdariDoc());
|
|
||||||
}
|
|
||||||
// حذف سند
|
|
||||||
$entityManager->remove($doc);
|
|
||||||
$entityManager->flush();
|
|
||||||
|
|
||||||
|
|
||||||
return new JsonResponse(['success' => true, 'message' => 'سند با موفقیت حذف شد']);
|
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return new JsonResponse(['error' => 'خطا در حذف سند: ' . $e->getMessage()], 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -30,7 +30,6 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use App\Entity\BankAccount;
|
use App\Entity\BankAccount;
|
||||||
use App\Entity\Cashdesk;
|
use App\Entity\Cashdesk;
|
||||||
use App\Entity\Salary;
|
use App\Entity\Salary;
|
||||||
use App\Entity\Year;
|
|
||||||
|
|
||||||
class SellController extends AbstractController
|
class SellController extends AbstractController
|
||||||
{
|
{
|
||||||
|
@ -47,16 +46,8 @@ class SellController extends AbstractController
|
||||||
'code' => $code,
|
'code' => $code,
|
||||||
'money' => $acc['money']
|
'money' => $acc['money']
|
||||||
]);
|
]);
|
||||||
if (!$doc) {
|
if (count($doc->getRelatedDocs()) != 0)
|
||||||
$canEdit = false;
|
$canEdit = false;
|
||||||
}
|
|
||||||
$year = $entityManager->getRepository(Year::class)->findOneBy([
|
|
||||||
'bid' => $acc['bid'],
|
|
||||||
'head' => true
|
|
||||||
]);
|
|
||||||
if ($doc->getYear()->getId() != $year->getId()) {
|
|
||||||
$canEdit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$tickets = $entityManager->getRepository(StoreroomTicket::class)->findBy(['doc' => $doc]);
|
$tickets = $entityManager->getRepository(StoreroomTicket::class)->findBy(['doc' => $doc]);
|
||||||
if (count($tickets) != 0)
|
if (count($tickets) != 0)
|
||||||
|
@ -759,23 +750,6 @@ class SellController extends AbstractController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$pdfPid = 0;
|
$pdfPid = 0;
|
||||||
|
|
||||||
// فیلد جدید وضعیت حساب مشتری
|
|
||||||
$personItems = $entityManager->getRepository(HesabdariRow::class)->findBy(['bid' => $acc['bid'], 'person' => $person]);
|
|
||||||
$accountStatus = [];
|
|
||||||
$bs = 0;
|
|
||||||
$bd = 0;
|
|
||||||
foreach ($personItems as $item) {
|
|
||||||
$bs += $item->getBs();
|
|
||||||
$bd += $item->getBd();
|
|
||||||
}
|
|
||||||
if ($bs > $bd) {
|
|
||||||
$accountStatus['label'] = 'بستانکار';
|
|
||||||
$accountStatus['value'] = $bs - $bd;
|
|
||||||
} else {
|
|
||||||
$accountStatus['label'] = 'بدهکار';
|
|
||||||
$accountStatus['value'] = $bd - $bs;
|
|
||||||
}
|
|
||||||
if ($params['pdf'] == true || $params['printers'] == true) {
|
if ($params['pdf'] == true || $params['printers'] == true) {
|
||||||
$note = '';
|
$note = '';
|
||||||
if ($printSettings) {
|
if ($printSettings) {
|
||||||
|
@ -785,7 +759,6 @@ class SellController extends AbstractController
|
||||||
$acc['bid'],
|
$acc['bid'],
|
||||||
$this->getUser(),
|
$this->getUser(),
|
||||||
$this->renderView('pdf/printers/sell.html.twig', [
|
$this->renderView('pdf/printers/sell.html.twig', [
|
||||||
'accountStatus' => $accountStatus,
|
|
||||||
'bid' => $acc['bid'],
|
'bid' => $acc['bid'],
|
||||||
'doc' => $doc,
|
'doc' => $doc,
|
||||||
'rows' => array_map(function($row) {
|
'rows' => array_map(function($row) {
|
||||||
|
@ -895,8 +868,7 @@ class SellController extends AbstractController
|
||||||
Access $access,
|
Access $access,
|
||||||
Log $log,
|
Log $log,
|
||||||
EntityManagerInterface $entityManager,
|
EntityManagerInterface $entityManager,
|
||||||
registryMGR $registryMGR,
|
registryMGR $registryMGR
|
||||||
Jdate $jdate
|
|
||||||
): JsonResponse {
|
): JsonResponse {
|
||||||
$params = [];
|
$params = [];
|
||||||
if ($content = $request->getContent()) {
|
if ($content = $request->getContent()) {
|
||||||
|
@ -960,22 +932,12 @@ class SellController extends AbstractController
|
||||||
}
|
}
|
||||||
|
|
||||||
// تنظیم اطلاعات اصلی فاکتور
|
// تنظیم اطلاعات اصلی فاکتور
|
||||||
if (isset($params['invoiceDescription'])) {
|
|
||||||
$doc->setDes($params['invoiceDescription']);
|
$doc->setDes($params['invoiceDescription']);
|
||||||
} else {
|
|
||||||
$doc->setDes('');
|
|
||||||
}
|
|
||||||
if (isset($params['invoiceDate'])) {
|
|
||||||
$doc->setDate($params['invoiceDate']);
|
$doc->setDate($params['invoiceDate']);
|
||||||
} else {
|
|
||||||
$doc->setDate($jdate->jdate('Y/n/d', time()));
|
|
||||||
}
|
|
||||||
if (isset($params['taxPercent'])) {
|
|
||||||
$doc->setTaxPercent($params['taxPercent'] ?? 0);
|
$doc->setTaxPercent($params['taxPercent'] ?? 0);
|
||||||
}
|
|
||||||
|
|
||||||
// افزودن هزینه حمل
|
// افزودن هزینه حمل
|
||||||
if (isset($params['shippingCost']) && $params['shippingCost'] > 0) {
|
if ($params['shippingCost'] > 0) {
|
||||||
$hesabdariRow = new HesabdariRow();
|
$hesabdariRow = new HesabdariRow();
|
||||||
$hesabdariRow->setDes('حمل و نقل کالا');
|
$hesabdariRow->setDes('حمل و نقل کالا');
|
||||||
$hesabdariRow->setBid($acc['bid']);
|
$hesabdariRow->setBid($acc['bid']);
|
||||||
|
@ -990,21 +952,17 @@ class SellController extends AbstractController
|
||||||
|
|
||||||
// افزودن تخفیف کلی
|
// افزودن تخفیف کلی
|
||||||
$totalDiscount = 0;
|
$totalDiscount = 0;
|
||||||
if (isset($params['discountType']) && $params['discountType'] === 'percent') {
|
if ($params['discountType'] === 'percent') {
|
||||||
$totalDiscount = round(($params['totalInvoice'] * $params['discountPercent']) / 100);
|
$totalDiscount = round(($params['totalInvoice'] * $params['discountPercent']) / 100);
|
||||||
$doc->setDiscountType('percent');
|
$doc->setDiscountType('percent');
|
||||||
$doc->setDiscountPercent((float)$params['discountPercent']);
|
$doc->setDiscountPercent((float)$params['discountPercent']);
|
||||||
} else {
|
} else {
|
||||||
if (isset($params['totalDiscount']) && $params['totalDiscount'] > 0) {
|
|
||||||
$totalDiscount = $params['totalDiscount'];
|
$totalDiscount = $params['totalDiscount'];
|
||||||
} else {
|
|
||||||
$totalDiscount = 0;
|
|
||||||
}
|
|
||||||
$doc->setDiscountType('fixed');
|
$doc->setDiscountType('fixed');
|
||||||
$doc->setDiscountPercent(null);
|
$doc->setDiscountPercent(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($totalDiscount) && $totalDiscount > 0) {
|
if ($totalDiscount > 0) {
|
||||||
$hesabdariRow = new HesabdariRow();
|
$hesabdariRow = new HesabdariRow();
|
||||||
$hesabdariRow->setDes('تخفیف فاکتور');
|
$hesabdariRow->setDes('تخفیف فاکتور');
|
||||||
$hesabdariRow->setBid($acc['bid']);
|
$hesabdariRow->setBid($acc['bid']);
|
||||||
|
@ -1088,25 +1046,10 @@ class SellController extends AbstractController
|
||||||
$ref = $entityManager->getRepository(HesabdariTable::class)->findOneBy(['code' => '3']);
|
$ref = $entityManager->getRepository(HesabdariTable::class)->findOneBy(['code' => '3']);
|
||||||
$hesabdariRow->setRef($ref);
|
$hesabdariRow->setRef($ref);
|
||||||
|
|
||||||
if (!isset($params['customer']) || $params['customer'] == '') {
|
|
||||||
$person = $entityManager->getRepository(Person::class)->findOneBy([
|
|
||||||
'bid' => $acc['bid'],
|
|
||||||
'nikename' => 'مشتری پیش فرض'
|
|
||||||
]);
|
|
||||||
if (!$person) {
|
|
||||||
$person = new Person();
|
|
||||||
$person->setBid($acc['bid']);
|
|
||||||
$person->setNikename('مشتری پیش فرض');
|
|
||||||
$person->setCode($provider->getAccountingCode($acc['bid'], 'person'));
|
|
||||||
$entityManager->persist($person);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$person = $entityManager->getRepository(Person::class)->findOneBy([
|
$person = $entityManager->getRepository(Person::class)->findOneBy([
|
||||||
'bid' => $acc['bid'],
|
'bid' => $acc['bid'],
|
||||||
'id' => $params['customer']
|
'id' => $params['customer']
|
||||||
]);
|
]);
|
||||||
}
|
|
||||||
|
|
||||||
if (!$person) {
|
if (!$person) {
|
||||||
throw new \Exception('خریدار یافت نشد');
|
throw new \Exception('خریدار یافت نشد');
|
||||||
}
|
}
|
||||||
|
@ -1248,8 +1191,7 @@ class SellController extends AbstractController
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return $this->json([
|
return $this->json([
|
||||||
'result' => 0,
|
'result' => 0,
|
||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage()
|
||||||
'data' => $params
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ final class DatabaseController extends AbstractController
|
||||||
{
|
{
|
||||||
$this->registryMGR = $registryMGR;
|
$this->registryMGR = $registryMGR;
|
||||||
$this->entityManager = $entityManager;
|
$this->entityManager = $entityManager;
|
||||||
$this->backupPath = dirname(__DIR__, 4) . '/hesabixBackup/versions';
|
$this->backupPath = dirname(__DIR__, 2) . '/hesabixBackup/versions';
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/api/admin/database/backup/info', name: 'app_admin_database_backup_info', methods: ['GET'])]
|
#[Route('/api/admin/database/backup/info', name: 'app_admin_database_backup_info', methods: ['GET'])]
|
||||||
|
@ -53,11 +53,6 @@ final class DatabaseController extends AbstractController
|
||||||
$filename = 'Hesabix-' . time() . '.sql';
|
$filename = 'Hesabix-' . time() . '.sql';
|
||||||
$filepath = $this->backupPath . '/' . $filename;
|
$filepath = $this->backupPath . '/' . $filename;
|
||||||
|
|
||||||
// بررسی دسترسی پوشه مقصد
|
|
||||||
if (!is_writable($this->backupPath)) {
|
|
||||||
throw new \Exception('پوشه مقصد قابل نوشتن نیست: ' . $this->backupPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// دریافت تنظیمات دیتابیس از EntityManager
|
// دریافت تنظیمات دیتابیس از EntityManager
|
||||||
$connection = $this->entityManager->getConnection();
|
$connection = $this->entityManager->getConnection();
|
||||||
$params = $connection->getParams();
|
$params = $connection->getParams();
|
||||||
|
@ -70,7 +65,7 @@ final class DatabaseController extends AbstractController
|
||||||
|
|
||||||
// دستور mysqldump
|
// دستور mysqldump
|
||||||
$command = sprintf(
|
$command = sprintf(
|
||||||
'mysqldump -h %s -P %s -u %s -p%s %s > %s 2>&1',
|
'mysqldump -h %s -P %s -u %s -p%s %s > %s',
|
||||||
escapeshellarg($dbHost),
|
escapeshellarg($dbHost),
|
||||||
escapeshellarg($dbPort),
|
escapeshellarg($dbPort),
|
||||||
escapeshellarg($dbUser),
|
escapeshellarg($dbUser),
|
||||||
|
@ -165,16 +160,12 @@ final class DatabaseController extends AbstractController
|
||||||
$remoteDir = dirname($remotePath);
|
$remoteDir = dirname($remotePath);
|
||||||
|
|
||||||
// بررسی دسترسی نوشتن در مسیر
|
// بررسی دسترسی نوشتن در مسیر
|
||||||
$testFileLocal = tempnam(sys_get_temp_dir(), 'ftp_test_');
|
$testFile = 'test_' . time() . '.txt';
|
||||||
file_put_contents($testFileLocal, 'test');
|
if (!@ftp_put($ftp, $testFile, 'test', FTP_ASCII)) {
|
||||||
$testFileRemote = 'test_' . time() . '.txt';
|
|
||||||
if (!@ftp_put($ftp, $testFileRemote, $testFileLocal, FTP_ASCII)) {
|
|
||||||
unlink($testFileLocal);
|
|
||||||
ftp_close($ftp);
|
ftp_close($ftp);
|
||||||
throw new \Exception('کاربر FTP دسترسی نوشتن ندارد');
|
throw new \Exception('کاربر FTP دسترسی نوشتن ندارد');
|
||||||
}
|
}
|
||||||
ftp_delete($ftp, $testFileRemote);
|
ftp_delete($ftp, $testFile);
|
||||||
unlink($testFileLocal);
|
|
||||||
|
|
||||||
// ایجاد مسیر در صورت عدم وجود
|
// ایجاد مسیر در صورت عدم وجود
|
||||||
$this->createFtpDirectory($ftp, $remoteDir);
|
$this->createFtpDirectory($ftp, $remoteDir);
|
||||||
|
@ -186,8 +177,7 @@ final class DatabaseController extends AbstractController
|
||||||
}
|
}
|
||||||
|
|
||||||
// آپلود فایل
|
// آپلود فایل
|
||||||
$result = ftp_put($ftp, basename($remotePath), $filepath, FTP_BINARY);
|
if (!ftp_put($ftp, basename($remotePath), $filepath, FTP_BINARY)) {
|
||||||
if (!$result) {
|
|
||||||
$error = error_get_last();
|
$error = error_get_last();
|
||||||
ftp_close($ftp);
|
ftp_close($ftp);
|
||||||
throw new \Exception('خطا در آپلود فایل به سرور FTP: ' . ($error['message'] ?? 'خطای نامشخص'));
|
throw new \Exception('خطا در آپلود فایل به سرور FTP: ' . ($error['message'] ?? 'خطای نامشخص'));
|
||||||
|
|
|
@ -155,13 +155,11 @@ final class RegistrySettingsController extends AbstractController
|
||||||
}
|
}
|
||||||
|
|
||||||
// تست دسترسی به مسیر
|
// تست دسترسی به مسیر
|
||||||
if (!@ftp_chdir($ftp, $data['path'])) {
|
if (!ftp_chdir($ftp, $data['path'])) {
|
||||||
$currentDir = ftp_pwd($ftp); // دریافت مسیر فعلی
|
|
||||||
ftp_close($ftp);
|
ftp_close($ftp);
|
||||||
return $this->json([
|
return $this->json([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'message' => 'مسیر مورد نظر قابل دسترسی نیست',
|
'message' => 'مسیر مورد نظر قابل دسترسی نیست'
|
||||||
'suggested_path' => $currentDir // پیشنهاد مسیر فعلی
|
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -297,9 +297,6 @@ class Business
|
||||||
#[ORM\OneToMany(targetEntity: PlugGhestaDoc::class, mappedBy: 'bid', orphanRemoval: true)]
|
#[ORM\OneToMany(targetEntity: PlugGhestaDoc::class, mappedBy: 'bid', orphanRemoval: true)]
|
||||||
private Collection $PlugGhestaDocs;
|
private Collection $PlugGhestaDocs;
|
||||||
|
|
||||||
#[ORM\OneToMany(mappedBy: 'business', targetEntity: PlugHrmDoc::class)]
|
|
||||||
private Collection $plugHrmDocs;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->logs = new ArrayCollection();
|
$this->logs = new ArrayCollection();
|
||||||
|
@ -342,7 +339,6 @@ class Business
|
||||||
$this->hesabdariTables = new ArrayCollection();
|
$this->hesabdariTables = new ArrayCollection();
|
||||||
$this->accountingPackageOrders = new ArrayCollection();
|
$this->accountingPackageOrders = new ArrayCollection();
|
||||||
$this->PlugGhestaDocs = new ArrayCollection();
|
$this->PlugGhestaDocs = new ArrayCollection();
|
||||||
$this->plugHrmDocs = new ArrayCollection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): ?int
|
public function getId(): ?int
|
||||||
|
@ -2059,31 +2055,4 @@ class Business
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Collection<int, PlugHrmDoc>
|
|
||||||
*/
|
|
||||||
public function getPlugHrmDocs(): Collection
|
|
||||||
{
|
|
||||||
return $this->plugHrmDocs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addPlugHrmDoc(PlugHrmDoc $plugHrmDoc): static
|
|
||||||
{
|
|
||||||
if (!$this->plugHrmDocs->contains($plugHrmDoc)) {
|
|
||||||
$this->plugHrmDocs->add($plugHrmDoc);
|
|
||||||
$plugHrmDoc->setBusiness($this);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removePlugHrmDoc(PlugHrmDoc $plugHrmDoc): static
|
|
||||||
{
|
|
||||||
if ($this->plugHrmDocs->removeElement($plugHrmDoc)) {
|
|
||||||
if ($plugHrmDoc->getBusiness() === $this) {
|
|
||||||
$plugHrmDoc->setBusiness(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,12 +140,6 @@ class HesabdariDoc
|
||||||
#[ORM\OneToMany(targetEntity: PlugGhestaDoc::class, mappedBy: 'mainDoc', orphanRemoval: true)]
|
#[ORM\OneToMany(targetEntity: PlugGhestaDoc::class, mappedBy: 'mainDoc', orphanRemoval: true)]
|
||||||
private Collection $plugGhestaDocs;
|
private Collection $plugGhestaDocs;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Collection<int, PlugHrmDoc>
|
|
||||||
*/
|
|
||||||
#[ORM\OneToMany(targetEntity: PlugHrmDoc::class, mappedBy: 'hesabdariDoc')]
|
|
||||||
private Collection $plugHrmDocs;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->hesabdariRows = new ArrayCollection();
|
$this->hesabdariRows = new ArrayCollection();
|
||||||
|
@ -157,7 +151,6 @@ class HesabdariDoc
|
||||||
$this->pairDoc = new ArrayCollection();
|
$this->pairDoc = new ArrayCollection();
|
||||||
$this->plugGhestaItems = new ArrayCollection();
|
$this->plugGhestaItems = new ArrayCollection();
|
||||||
$this->plugGhestaDocs = new ArrayCollection();
|
$this->plugGhestaDocs = new ArrayCollection();
|
||||||
$this->plugHrmDocs = new ArrayCollection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): ?int
|
public function getId(): ?int
|
||||||
|
@ -696,34 +689,4 @@ class HesabdariDoc
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Collection<int, PlugHrmDoc>
|
|
||||||
*/
|
|
||||||
public function getPlugHrmDocs(): Collection
|
|
||||||
{
|
|
||||||
return $this->plugHrmDocs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addPlugHrmDoc(PlugHrmDoc $plugHrmDoc): static
|
|
||||||
{
|
|
||||||
if (!$this->plugHrmDocs->contains($plugHrmDoc)) {
|
|
||||||
$this->plugHrmDocs->add($plugHrmDoc);
|
|
||||||
$plugHrmDoc->setHesabdariDoc($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removePlugHrmDoc(PlugHrmDoc $plugHrmDoc): static
|
|
||||||
{
|
|
||||||
if ($this->plugHrmDocs->removeElement($plugHrmDoc)) {
|
|
||||||
// set the owning side to null (unless already changed)
|
|
||||||
if ($plugHrmDoc->getHesabdariDoc() === $this) {
|
|
||||||
$plugHrmDoc->setHesabdariDoc(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,144 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Entity;
|
|
||||||
|
|
||||||
use App\Repository\PlugHrmDocRepository;
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
|
||||||
use Doctrine\Common\Collections\Collection;
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
|
|
||||||
#[ORM\Entity(repositoryClass: PlugHrmDocRepository::class)]
|
|
||||||
class PlugHrmDoc
|
|
||||||
{
|
|
||||||
#[ORM\Id]
|
|
||||||
#[ORM\GeneratedValue]
|
|
||||||
#[ORM\Column]
|
|
||||||
private ?int $id = null;
|
|
||||||
|
|
||||||
#[ORM\Column(length: 255)]
|
|
||||||
private ?string $description = null;
|
|
||||||
|
|
||||||
#[ORM\Column(type: 'string', length: 10)]
|
|
||||||
private ?string $date = null;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne(inversedBy: 'plugHrmDocs')]
|
|
||||||
#[ORM\JoinColumn(nullable: false)]
|
|
||||||
private ?Business $business = null;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne]
|
|
||||||
#[ORM\JoinColumn(nullable: false)]
|
|
||||||
private ?User $creator = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
private ?int $createDate = null;
|
|
||||||
|
|
||||||
#[ORM\OneToMany(mappedBy: 'doc', targetEntity: PlugHrmDocItem::class, orphanRemoval: true)]
|
|
||||||
private Collection $items;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne(inversedBy: 'plugHrmDocs')]
|
|
||||||
private ?HesabdariDoc $hesabdariDoc = null;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->items = new ArrayCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): ?int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription(): ?string
|
|
||||||
{
|
|
||||||
return $this->description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setDescription(string $description): static
|
|
||||||
{
|
|
||||||
$this->description = $description;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDate(): ?string
|
|
||||||
{
|
|
||||||
return $this->date;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setDate(string $date): self
|
|
||||||
{
|
|
||||||
$this->date = $date;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBusiness(): ?Business
|
|
||||||
{
|
|
||||||
return $this->business;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBusiness(?Business $business): static
|
|
||||||
{
|
|
||||||
$this->business = $business;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCreator(): ?User
|
|
||||||
{
|
|
||||||
return $this->creator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCreator(?User $creator): static
|
|
||||||
{
|
|
||||||
$this->creator = $creator;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCreateDate(): ?int
|
|
||||||
{
|
|
||||||
return $this->createDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCreateDate(int $createDate): static
|
|
||||||
{
|
|
||||||
$this->createDate = $createDate;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Collection<int, PlugHrmDocItem>
|
|
||||||
*/
|
|
||||||
public function getItems(): Collection
|
|
||||||
{
|
|
||||||
return $this->items;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addItem(PlugHrmDocItem $item): static
|
|
||||||
{
|
|
||||||
if (!$this->items->contains($item)) {
|
|
||||||
$this->items->add($item);
|
|
||||||
$item->setDoc($this);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removeItem(PlugHrmDocItem $item): static
|
|
||||||
{
|
|
||||||
if ($this->items->removeElement($item)) {
|
|
||||||
if ($item->getDoc() === $this) {
|
|
||||||
$item->setDoc(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHesabdariDoc(): ?HesabdariDoc
|
|
||||||
{
|
|
||||||
return $this->hesabdariDoc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setHesabdariDoc(?HesabdariDoc $hesabdariDoc): static
|
|
||||||
{
|
|
||||||
$this->hesabdariDoc = $hesabdariDoc;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,125 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Entity;
|
|
||||||
|
|
||||||
use App\Repository\PlugHrmDocItemRepository;
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
|
|
||||||
#[ORM\Entity(repositoryClass: PlugHrmDocItemRepository::class)]
|
|
||||||
class PlugHrmDocItem
|
|
||||||
{
|
|
||||||
#[ORM\Id]
|
|
||||||
#[ORM\GeneratedValue]
|
|
||||||
#[ORM\Column]
|
|
||||||
private ?int $id = null;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne(inversedBy: 'items')]
|
|
||||||
#[ORM\JoinColumn(nullable: false)]
|
|
||||||
private ?PlugHrmDoc $doc = null;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne]
|
|
||||||
#[ORM\JoinColumn(nullable: false)]
|
|
||||||
private ?Person $person = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
private ?int $baseSalary = 0;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
private ?int $overtime = 0;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
private ?int $shift = 0;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
private ?int $night = 0;
|
|
||||||
|
|
||||||
#[ORM\Column(length: 255, nullable: true)]
|
|
||||||
private ?string $description = null;
|
|
||||||
|
|
||||||
public function getId(): ?int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDoc(): ?PlugHrmDoc
|
|
||||||
{
|
|
||||||
return $this->doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setDoc(?PlugHrmDoc $doc): static
|
|
||||||
{
|
|
||||||
$this->doc = $doc;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPerson(): ?Person
|
|
||||||
{
|
|
||||||
return $this->person;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setPerson(?Person $person): static
|
|
||||||
{
|
|
||||||
$this->person = $person;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseSalary(): ?int
|
|
||||||
{
|
|
||||||
return $this->baseSalary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBaseSalary(int $baseSalary): static
|
|
||||||
{
|
|
||||||
$this->baseSalary = $baseSalary;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOvertime(): ?int
|
|
||||||
{
|
|
||||||
return $this->overtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setOvertime(int $overtime): static
|
|
||||||
{
|
|
||||||
$this->overtime = $overtime;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getShift(): ?int
|
|
||||||
{
|
|
||||||
return $this->shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setShift(int $shift): static
|
|
||||||
{
|
|
||||||
$this->shift = $shift;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNight(): ?int
|
|
||||||
{
|
|
||||||
return $this->night;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setNight(int $night): static
|
|
||||||
{
|
|
||||||
$this->night = $night;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription(): ?string
|
|
||||||
{
|
|
||||||
return $this->description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setDescription(?string $description): static
|
|
||||||
{
|
|
||||||
$this->description = $description;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTotal(): int
|
|
||||||
{
|
|
||||||
return $this->baseSalary + $this->overtime + $this->shift + $this->night;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Repository;
|
|
||||||
|
|
||||||
use App\Entity\PlugHrmDocItem;
|
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
|
||||||
|
|
||||||
class PlugHrmDocItemRepository extends ServiceEntityRepository
|
|
||||||
{
|
|
||||||
public function __construct(ManagerRegistry $registry)
|
|
||||||
{
|
|
||||||
parent::__construct($registry, PlugHrmDocItem::class);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Repository;
|
|
||||||
|
|
||||||
use App\Entity\PlugHrmDoc;
|
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
|
||||||
|
|
||||||
class PlugHrmDocRepository extends ServiceEntityRepository
|
|
||||||
{
|
|
||||||
public function __construct(ManagerRegistry $registry)
|
|
||||||
{
|
|
||||||
parent::__construct($registry, PlugHrmDoc::class);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -81,7 +81,7 @@
|
||||||
<td class="center item">تفضیل</td>
|
<td class="center item">تفضیل</td>
|
||||||
<td class="center item">بدهکار</td>
|
<td class="center item">بدهکار</td>
|
||||||
<td class="center item">بستانکار</td>
|
<td class="center item">بستانکار</td>
|
||||||
<td class="center item">شرح سند</td>
|
<td class="center item">سال مالی</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% set sumBs = 0 %}
|
{% set sumBs = 0 %}
|
||||||
{% set sumBd = 0 %}
|
{% set sumBd = 0 %}
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
<td class="center item">{{ item.ref.name }}</td>
|
<td class="center item">{{ item.ref.name }}</td>
|
||||||
<td class="center item">{{ item.bd | number_format }}</td>
|
<td class="center item">{{ item.bd | number_format }}</td>
|
||||||
<td class="center item">{{ item.bs | number_format }}</td>
|
<td class="center item">{{ item.bs | number_format }}</td>
|
||||||
<td class="center item">{{ item.doc.des }}</td>
|
<td class="center item">{{ item.year.label }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -199,7 +199,7 @@
|
||||||
<tr class="stimol">
|
<tr class="stimol">
|
||||||
<td class="item" style="padding:1%">
|
<td class="item" style="padding:1%">
|
||||||
<h4>توضیحات:</h4>
|
<h4>توضیحات:</h4>
|
||||||
{{ note|raw }}
|
{{ note|nl2br }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
<p>
|
<p>
|
||||||
<b>نام:
|
<b>نام:
|
||||||
</b>
|
</b>
|
||||||
{% if bid.legalName is not empty %}{{ bid.legalName }}{% endif %}
|
{{ bid.legalName }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
|
@ -78,27 +78,27 @@
|
||||||
<b>
|
<b>
|
||||||
شناسه ملی:
|
شناسه ملی:
|
||||||
</b>
|
</b>
|
||||||
{% if bid.shenasemeli is not empty %}{{ bid.shenasemeli }}{% endif %}
|
{{ bid.shenasemeli }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<p>
|
<p>
|
||||||
<b>شماره ثبت:
|
<b>شماره ثبت:
|
||||||
</b>
|
</b>
|
||||||
{% if bid.shomaresabt is not empty %}{{ bid.shomaresabt }}{% endif %}
|
{{ bid.shomaresabt }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<p>
|
<p>
|
||||||
<b>شماره اقتصادی:
|
<b>شماره اقتصادی:
|
||||||
</b>
|
</b>
|
||||||
{% if bid.codeeghtesadi is not empty %}{{ bid.codeeghtesadi }}{% endif %}
|
{{ bid.codeeghtesadi }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<p>
|
<p>
|
||||||
<b>تلفن / نمابر:</b>
|
<b>تلفن / نمابر:</b>
|
||||||
{% if bid.tel is not empty %}{{ bid.tel }}{% endif %}
|
{{ bid.tel }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -106,14 +106,17 @@
|
||||||
<td class="" colspan="1">
|
<td class="" colspan="1">
|
||||||
<p>
|
<p>
|
||||||
<b>کد پستی:</b>
|
<b>کد پستی:</b>
|
||||||
{% if bid.postalcode is not empty %}{{ bid.postalcode }}{% endif %}
|
{{ bid.postalcode }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="" colspan="3">
|
<td class="" colspan="3">
|
||||||
<p>
|
<p>
|
||||||
<b>آدرس:
|
<b>آدرس:
|
||||||
</b>
|
</b>
|
||||||
{% if bid.ostan is not empty %}استان {{ bid.ostan }}{% endif %}{% if bid.shahrestan is not empty %}، شهر {{ bid.shahrestan }}{% endif %}{% if bid.address is not empty %}، {{ bid.address }}{% endif %}
|
استان
|
||||||
|
{{ bid.ostan }}، شهر
|
||||||
|
{{ bid.shahrestan }}،
|
||||||
|
{{ bid.address }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -135,34 +138,34 @@
|
||||||
<b>نام:
|
<b>نام:
|
||||||
</b>
|
</b>
|
||||||
{% if person.prelabel is not null %}{{ person.prelabel.label }}{% endif %}
|
{% if person.prelabel is not null %}{{ person.prelabel.label }}{% endif %}
|
||||||
{% if person.nikename is not empty %}{{ person.nikename }}{% endif %}
|
{{ person.nikename }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<p>
|
<p>
|
||||||
<b> شناسه ملی:
|
<b> شناسه ملی:
|
||||||
</b>
|
</b>
|
||||||
{% if person.shenasemeli is not empty %}{{ person.shenasemeli }}{% endif %}
|
{{ person.shenasemeli }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<p>
|
<p>
|
||||||
<b>شماره ثبت:
|
<b>شماره ثبت:
|
||||||
</b>
|
</b>
|
||||||
{% if person.sabt is not empty %}{{ person.sabt }}{% endif %}
|
{{ person.sabt }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<p>
|
<p>
|
||||||
<b>شماره اقتصادی:
|
<b>شماره اقتصادی:
|
||||||
</b>
|
</b>
|
||||||
{% if person.codeeghtesadi is not empty %}{{ person.codeeghtesadi }}{% endif %}
|
{{ person.codeeghtesadi }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<p>
|
<p>
|
||||||
<b>تلفن / نمابر:</b>
|
<b>تلفن / نمابر:</b>
|
||||||
{% if person.tel is not empty %}{{ person.tel }}{% endif %}
|
{{ person.tel }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -170,14 +173,17 @@
|
||||||
<td class="" colspan="1">
|
<td class="" colspan="1">
|
||||||
<p>
|
<p>
|
||||||
<b>کد پستی:</b>
|
<b>کد پستی:</b>
|
||||||
{% if person.postalcode is not empty %}{{ person.postalcode }}{% endif %}
|
{{ person.postalcode }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="" colspan="3">
|
<td class="" colspan="3">
|
||||||
<p>
|
<p>
|
||||||
<b>آدرس:
|
<b>آدرس:
|
||||||
</b>
|
</b>
|
||||||
{% if person.ostan is not empty %}استان {{ person.ostan }}{% endif %}{% if person.shahr is not empty %}، شهر {{ person.shahr }}{% endif %}{% if person.address is not empty %}، {{ person.address }}{% endif %}
|
استان
|
||||||
|
{{ person.ostan }}، شهر
|
||||||
|
{{ person.shahr }}،
|
||||||
|
{{ person.address }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -224,12 +230,7 @@
|
||||||
<td class="center item">
|
<td class="center item">
|
||||||
{% if item.commodityCount > 0 %}
|
{% if item.commodityCount > 0 %}
|
||||||
{% if item.showPercentDiscount %}
|
{% if item.showPercentDiscount %}
|
||||||
{% set discountDivisor = 1 - (item.discountPercent / 100) %}
|
{% set originalPrice = item.bs / (1 - (item.discountPercent / 100)) %}
|
||||||
{% if discountDivisor <= 0 %}
|
|
||||||
{% set originalPrice = item.bs %}
|
|
||||||
{% else %}
|
|
||||||
{% set originalPrice = item.bs / discountDivisor %}
|
|
||||||
{% endif %}
|
|
||||||
{% set unitPrice = originalPrice / item.commodityCount %}
|
{% set unitPrice = originalPrice / item.commodityCount %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% set originalPrice = item.bs + item.discount %}
|
{% set originalPrice = item.bs + item.discount %}
|
||||||
|
@ -251,12 +252,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="center item">
|
<td class="center item">
|
||||||
{% if item.showPercentDiscount %}
|
{% if item.showPercentDiscount %}
|
||||||
{% set discountDivisor = 1 - (item.discountPercent / 100) %}
|
{% set originalPrice = item.bs / (1 - (item.discountPercent / 100)) %}
|
||||||
{% if discountDivisor <= 0 %}
|
|
||||||
{% set originalPrice = item.bs %}
|
|
||||||
{% else %}
|
|
||||||
{% set originalPrice = item.bs / discountDivisor %}
|
|
||||||
{% endif %}
|
|
||||||
{{ originalPrice|round|number_format }} {{ doc.money.shortName }}
|
{{ originalPrice|round|number_format }} {{ doc.money.shortName }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ (item.bs + item.discount)|number_format }} {{ doc.money.shortName }}
|
{{ (item.bs + item.discount)|number_format }} {{ doc.money.shortName }}
|
||||||
|
@ -304,17 +300,6 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{# فیلد جدید وضعیت حساب مشتری #}
|
|
||||||
{% if accountStatus is defined %}
|
|
||||||
<h4 class="">
|
|
||||||
وضعیت حساب مشتری با احتساب این فاکتور:
|
|
||||||
{{ accountStatus.value | number_format}}
|
|
||||||
{{ doc.money.shortName }}
|
|
||||||
{{ accountStatus.label }}
|
|
||||||
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</h4>
|
</h4>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -1,251 +1,72 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<v-container>
|
||||||
<v-toolbar color="toolbar" title="لیست حقوق">
|
<v-card>
|
||||||
<template v-slot:prepend>
|
<v-card-title class="d-flex align-center">
|
||||||
<v-tooltip :text="$t('dialog.back')" location="bottom">
|
{{ $t('drawer.hrm_docs') }}
|
||||||
<template v-slot:activator="{ props }">
|
|
||||||
<v-btn v-bind="props" @click="$router.back()" class="d-none d-sm-flex" variant="text"
|
|
||||||
icon="mdi-arrow-right" />
|
|
||||||
</template>
|
|
||||||
</v-tooltip>
|
|
||||||
</template>
|
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-tooltip text="افزودن سند حقوق" location="bottom">
|
<v-btn color="primary" prepend-icon="mdi-plus" to="/acc/hrm/docs/mod/">
|
||||||
<template v-slot:activator="{ props }">
|
{{ $t('dialog.add_new') }}
|
||||||
<v-btn v-bind="props" icon="mdi-plus" variant="text" color="success" :to="'/acc/hrm/docs/mod/'"></v-btn>
|
|
||||||
</template>
|
|
||||||
</v-tooltip>
|
|
||||||
</v-toolbar>
|
|
||||||
|
|
||||||
<v-text-field v-model="searchValue" prepend-inner-icon="mdi-magnify" density="compact" hide-details :rounded="false"
|
|
||||||
placeholder="جست و جو ...">
|
|
||||||
</v-text-field>
|
|
||||||
|
|
||||||
<v-data-table :headers="headers" :items="filteredItems" :search="searchValue" :loading="loading"
|
|
||||||
:header-props="{ class: 'custom-header' }" hover>
|
|
||||||
<template v-slot:item.actions="{ item }">
|
|
||||||
<v-tooltip text="مشاهده سند" location="bottom">
|
|
||||||
<template v-slot:activator="{ props }">
|
|
||||||
<v-btn v-bind="props" icon variant="text" color="success" :to="'/acc/hrm/docs/view/' + item.id">
|
|
||||||
<v-icon>mdi-eye</v-icon>
|
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</v-card-title>
|
||||||
</v-tooltip>
|
<v-card-text>
|
||||||
<v-menu>
|
<v-data-table
|
||||||
<template v-slot:activator="{ props }">
|
:headers="headers"
|
||||||
<v-btn variant="text" size="small" color="error" icon="mdi-menu" v-bind="props" />
|
:items="items"
|
||||||
</template>
|
:loading="loading"
|
||||||
<v-list>
|
class="elevation-1"
|
||||||
<v-list-item :title="$t('dialog.view')" :to="'/acc/hrm/docs/view/' + item.id">
|
>
|
||||||
<template v-slot:prepend>
|
<template v-slot:item.actions="{ item }">
|
||||||
<v-icon color="green-darken-4" icon="mdi-eye"></v-icon>
|
<v-btn
|
||||||
</template>
|
icon="mdi-eye"
|
||||||
</v-list-item>
|
variant="text"
|
||||||
<v-list-item :title="$t('dialog.edit')" :to="'/acc/hrm/docs/mod/' + item.id">
|
size="small"
|
||||||
<template v-slot:prepend>
|
:to="'/acc/hrm/docs/view/' + item.id"
|
||||||
<v-icon icon="mdi-file-edit"></v-icon>
|
></v-btn>
|
||||||
</template>
|
<v-btn
|
||||||
</v-list-item>
|
icon="mdi-pencil"
|
||||||
<v-list-item title="صدور سند حسابداری" :to="'/acc/hrm/docs/accounting/' + item.id">
|
variant="text"
|
||||||
<template v-slot:prepend>
|
size="small"
|
||||||
<v-icon color="primary" icon="mdi-file-document-outline"></v-icon>
|
:to="'/acc/hrm/docs/mod/' + item.id"
|
||||||
</template>
|
></v-btn>
|
||||||
</v-list-item>
|
|
||||||
<v-list-item :title="$t('dialog.delete')" @click="openDeleteDialog(item)">
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<v-icon color="deep-orange-accent-4" icon="mdi-trash-can"></v-icon>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
</v-list>
|
|
||||||
</v-menu>
|
|
||||||
</template>
|
</template>
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
|
|
||||||
<!-- دیالوگ تأیید حذف -->
|
|
||||||
<v-dialog v-model="deleteDialog" max-width="500">
|
|
||||||
<v-card class="rounded-lg">
|
|
||||||
<v-card-title class="d-flex align-center pa-4">
|
|
||||||
<v-icon color="error" size="large" class="ml-2">mdi-alert-circle-outline</v-icon>
|
|
||||||
<span class="text-h5 font-weight-bold">حذف سند حقوق</span>
|
|
||||||
</v-card-title>
|
|
||||||
|
|
||||||
<v-divider></v-divider>
|
|
||||||
|
|
||||||
<v-card-text class="pa-4">
|
|
||||||
<div class="d-flex flex-column">
|
|
||||||
<div class="text-subtitle-1 mb-2">آیا مطمئن هستید که میخواهید سند زیر را حذف کنید؟</div>
|
|
||||||
|
|
||||||
<v-card variant="outlined" class="mt-2">
|
|
||||||
<v-card-text>
|
|
||||||
<div class="d-flex justify-space-between mb-2">
|
|
||||||
<span class="text-subtitle-2 font-weight-bold">کد سند:</span>
|
|
||||||
<span>{{ selectedItem?.id?.toLocaleString() }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-space-between mb-2">
|
|
||||||
<span class="text-subtitle-2 font-weight-bold">تاریخ:</span>
|
|
||||||
<span>{{ selectedItem?.date }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-space-between mb-2">
|
|
||||||
<span class="text-subtitle-2 font-weight-bold">کارمند:</span>
|
|
||||||
<span>{{ selectedItem?.employee }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-space-between">
|
|
||||||
<span class="text-subtitle-2 font-weight-bold">مبلغ:</span>
|
|
||||||
<span>{{ selectedItem?.amountRaw?.toLocaleString() }}</span>
|
|
||||||
</div>
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</div>
|
</v-container>
|
||||||
</v-card-text>
|
|
||||||
|
|
||||||
<v-divider></v-divider>
|
|
||||||
|
|
||||||
<v-card-actions class="pa-4">
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
<v-btn
|
|
||||||
color="grey-darken-1"
|
|
||||||
variant="text"
|
|
||||||
@click="deleteDialog = false"
|
|
||||||
:disabled="deleteLoading"
|
|
||||||
>
|
|
||||||
انصراف
|
|
||||||
</v-btn>
|
|
||||||
<v-btn
|
|
||||||
color="error"
|
|
||||||
variant="tonal"
|
|
||||||
@click="confirmDelete"
|
|
||||||
:loading="deleteLoading"
|
|
||||||
>
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<v-icon>mdi-delete</v-icon>
|
|
||||||
</template>
|
|
||||||
حذف سند
|
|
||||||
</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
|
|
||||||
<!-- اسنکبار برای نمایش پیام -->
|
|
||||||
<v-snackbar v-model="snackbar.show" :color="snackbar.color" timeout="3000">
|
|
||||||
{{ snackbar.message }}
|
|
||||||
<template v-slot:actions>
|
|
||||||
<v-btn variant="text" @click="snackbar.show = false">
|
|
||||||
بستن
|
|
||||||
</v-btn>
|
|
||||||
</template>
|
|
||||||
</v-snackbar>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script>
|
||||||
import { ref, onMounted, computed } from 'vue'
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import moment from 'jalali-moment'
|
|
||||||
|
|
||||||
const searchValue = ref('')
|
export default {
|
||||||
const loading = ref(true)
|
data() {
|
||||||
const items = ref([])
|
return {
|
||||||
const deleteDialog = ref(false)
|
loading: false,
|
||||||
const deleteLoading = ref(false)
|
headers: [
|
||||||
const selectedItem = ref(null)
|
{ title: this.$t('dialog.field.id'), key: 'id' },
|
||||||
const snackbar = ref({
|
{ title: this.$t('dialog.field.date'), key: 'date' },
|
||||||
show: false,
|
{ title: this.$t('dialog.field.employee'), key: 'employee' },
|
||||||
message: '',
|
{ title: this.$t('dialog.field.amount'), key: 'amount' },
|
||||||
color: 'success'
|
{ title: this.$t('dialog.field.status'), key: 'status' },
|
||||||
})
|
{ title: this.$t('dialog.field.actions'), key: 'actions', sortable: false }
|
||||||
|
],
|
||||||
const headers = [
|
items: []
|
||||||
{ title: 'عملیات', key: 'actions' },
|
}
|
||||||
{ title: 'تاریخ', key: 'date', sortable: true },
|
},
|
||||||
{ title: 'ایجاد کننده', key: 'employee', sortable: true },
|
mounted() {
|
||||||
{ title: 'مبلغ', key: 'amount', sortable: true },
|
this.loadData()
|
||||||
{ title: 'سند حسابداری', key: 'accounting_doc', sortable: true },
|
},
|
||||||
{ title: 'توضیحات', key: 'description', sortable: true },
|
methods: {
|
||||||
]
|
async loadData() {
|
||||||
|
this.loading = true
|
||||||
const loadData = async () => {
|
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
const response = await axios.post('/api/hrm/docs/list')
|
||||||
const response = await axios.post('/api/hrm/docs/list', {
|
this.items = response.data
|
||||||
search: searchValue.value
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
|
||||||
items.value = response.data.data.map(item => ({
|
|
||||||
...item,
|
|
||||||
amount: item.total ? item.total.toLocaleString('fa-IR') : '0',
|
|
||||||
amountRaw: item.total || 0,
|
|
||||||
employee: item.creator?.name || 'نامشخص',
|
|
||||||
status: item.status
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
snackbar.value = {
|
|
||||||
show: true,
|
|
||||||
message: 'خطا در بارگذاری دادهها',
|
|
||||||
color: 'error'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading data:', error);
|
console.error('Error loading data:', error)
|
||||||
snackbar.value = {
|
|
||||||
show: true,
|
|
||||||
message: 'خطا در بارگذاری دادهها',
|
|
||||||
color: 'error'
|
|
||||||
};
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
}
|
||||||
};
|
this.loading = false
|
||||||
|
|
||||||
const filteredItems = computed(() => {
|
|
||||||
return items.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
const openDeleteDialog = (item) => {
|
|
||||||
selectedItem.value = item
|
|
||||||
deleteDialog.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmDelete = async () => {
|
|
||||||
try {
|
|
||||||
deleteLoading.value = true
|
|
||||||
const response = await axios.post('/api/hrm/docs/delete',{id:selectedItem.value.id})
|
|
||||||
if (response.data.success) {
|
|
||||||
const index = items.value.findIndex(item => item.id === selectedItem.value.id)
|
|
||||||
if (index !== -1) {
|
|
||||||
items.value.splice(index, 1)
|
|
||||||
}
|
|
||||||
deleteDialog.value = false
|
|
||||||
snackbar.value = {
|
|
||||||
show: true,
|
|
||||||
message: 'سند با موفقیت حذف شد',
|
|
||||||
color: 'success'
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
snackbar.value = {
|
|
||||||
show: true,
|
|
||||||
message: response.data.message || 'خطا در حذف سند',
|
|
||||||
color: 'error'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
snackbar.value = {
|
|
||||||
show: true,
|
|
||||||
message: error.response?.data?.message || 'خطا در ارتباط با سرور',
|
|
||||||
color: 'error'
|
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
deleteLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
loadData()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.v-data-table {
|
|
||||||
direction: rtl;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -25,7 +25,7 @@
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" sm="6" md="6">
|
<v-col cols="12" sm="6" md="6">
|
||||||
<Hdatepicker v-model="form.date" :label="$t('dialog.hrm.date')"
|
<Hdatepicker v-model="form.date" :label="$t('dialog.hrm.date')"
|
||||||
:rules="[v => !!v || $t('dialog.hrm.required_fields.date')]" required density="compact" />
|
:rules="[v => !!v || $t('dialog.hrm.required_fields.date')]" required />
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" sm="6" md="6">
|
<v-col cols="12" sm="6" md="6">
|
||||||
<v-text-field v-model="form.description" :label="$t('dialog.hrm.description')"
|
<v-text-field v-model="form.description" :label="$t('dialog.hrm.description')"
|
||||||
|
@ -131,9 +131,6 @@
|
||||||
import Hdatepicker from '@/components/forms/Hdatepicker.vue';
|
import Hdatepicker from '@/components/forms/Hdatepicker.vue';
|
||||||
import Hpersonsearch from '@/components/forms/Hpersonsearch.vue';
|
import Hpersonsearch from '@/components/forms/Hpersonsearch.vue';
|
||||||
import Hnumberinput from '@/components/forms/Hnumberinput.vue';
|
import Hnumberinput from '@/components/forms/Hnumberinput.vue';
|
||||||
import axios from 'axios';
|
|
||||||
import moment from 'jalali-moment';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { Hdatepicker, Hpersonsearch, Hnumberinput },
|
components: { Hdatepicker, Hpersonsearch, Hnumberinput },
|
||||||
data() {
|
data() {
|
||||||
|
@ -153,47 +150,20 @@ export default {
|
||||||
tableItems: [],
|
tableItems: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
mounted() {
|
||||||
try {
|
|
||||||
// دریافت تاریخ فعلی
|
|
||||||
const response = await axios.get('/api/year/get');
|
|
||||||
this.form.date = response.data.now;
|
|
||||||
|
|
||||||
const id = this.$route.params.id
|
const id = this.$route.params.id
|
||||||
if (id) {
|
if (id) {
|
||||||
this.isEdit = true
|
this.isEdit = true
|
||||||
await this.loadData(id)
|
this.loadData(id)
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.errorMessage = error.response?.data?.error || 'خطا در دریافت تاریخ';
|
|
||||||
this.showError = true;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async loadData(id) {
|
async loadData(id) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post('/api/hrm/docs/get/' + id)
|
const response = await this.$axios.post('/api/hrm/docs/get/' + id)
|
||||||
const data = response.data.data
|
this.form = response.data
|
||||||
|
|
||||||
this.form = {
|
|
||||||
date: data.date ? moment(data.date, 'jYYYY/jMM/jDD').format('jYYYY/jMM/jDD') : '',
|
|
||||||
description: data.description || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tableItems = data.items.map(item => ({
|
|
||||||
person: {
|
|
||||||
id: item.person.id,
|
|
||||||
name: item.person.name,
|
|
||||||
code: item.person.code
|
|
||||||
},
|
|
||||||
description: item.description || '',
|
|
||||||
baseSalary: item.baseSalary || 0,
|
|
||||||
overtime: item.overtime || 0,
|
|
||||||
shift: item.shift || 0,
|
|
||||||
night: item.night || 0
|
|
||||||
}))
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.errorMessage = error.response?.data?.error || 'خطا در دریافت اطلاعات';
|
this.errorMessage = 'خطا در دریافت اطلاعات';
|
||||||
this.showError = true;
|
this.showError = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -223,35 +193,16 @@ export default {
|
||||||
},
|
},
|
||||||
async save() {
|
async save() {
|
||||||
try {
|
try {
|
||||||
console.log('Starting save process...');
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const url = this.isEdit ? '/api/hrm/docs/update' : '/api/hrm/docs/insert';
|
const url = this.isEdit ? '/api/hrm/docs/update' : '/api/hrm/docs/insert'
|
||||||
const data = {
|
await this.$axios.post(url, this.form)
|
||||||
date: this.form.date,
|
|
||||||
description: this.form.description,
|
|
||||||
items: this.tableItems.map(item => ({
|
|
||||||
person: item.person?.id,
|
|
||||||
baseSalary: Number(item.baseSalary) || 0,
|
|
||||||
overtime: Number(item.overtime) || 0,
|
|
||||||
shift: Number(item.shift) || 0,
|
|
||||||
night: Number(item.night) || 0,
|
|
||||||
description: item.description || ''
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
console.log('Sending request to:', url);
|
|
||||||
console.log('Request data:', data);
|
|
||||||
|
|
||||||
const response = await axios.post(url, data);
|
|
||||||
console.log('Server response:', response);
|
|
||||||
|
|
||||||
this.successMessage = this.isEdit ? this.$t('dialog.hrm.edit_success') : this.$t('dialog.hrm.save_success');
|
this.successMessage = this.isEdit ? this.$t('dialog.hrm.edit_success') : this.$t('dialog.hrm.save_success');
|
||||||
this.showSuccess = true;
|
this.showSuccess = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.$router.push('/acc/hrm/docs/list');
|
this.$router.push('/acc/hrm/docs/list')
|
||||||
}, 1200);
|
}, 1200)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Save error:', error);
|
this.errorMessage = this.$t('dialog.hrm.save_error');
|
||||||
this.errorMessage = error.response?.data?.error || this.$t('dialog.hrm.save_error');
|
|
||||||
this.showError = true;
|
this.showError = true;
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
@ -260,7 +211,7 @@ export default {
|
||||||
async confirmDelete() {
|
async confirmDelete() {
|
||||||
try {
|
try {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
await axios.post('/api/hrm/docs/delete', { id: this.$route.params.id })
|
await this.$axios.post('/api/hrm/docs/delete', { id: this.$route.params.id })
|
||||||
this.successMessage = 'سند با موفقیت حذف شد';
|
this.successMessage = 'سند با موفقیت حذف شد';
|
||||||
this.showSuccess = true;
|
this.showSuccess = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -367,14 +318,6 @@ export default {
|
||||||
z-index: 9999 !important;
|
z-index: 9999 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.v-date-picker__menu) {
|
|
||||||
z-index: 9999 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.v-date-picker__menu__content) {
|
|
||||||
z-index: 9999 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-section-card {
|
.settings-section-card {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="sticky-container">
|
|
||||||
<v-toolbar color="toolbar" :title="$t('dialog.person_with_det_report')">
|
<v-toolbar color="toolbar" :title="$t('dialog.person_with_det_report')">
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<v-tooltip :text="$t('dialog.back')" location="bottom">
|
<v-tooltip :text="$t('dialog.back')" location="bottom">
|
||||||
<template v-slot:activator="{ props }">
|
<template v-slot:activator="{ props }">
|
||||||
<v-btn v-bind="props" @click="$router.back()" class="d-none d-sm-flex" variant="text" icon="mdi-arrow-right" />
|
<v-btn v-bind="props" @click="$router.back()" class="d-none d-sm-flex" variant="text"
|
||||||
|
icon="mdi-arrow-right" />
|
||||||
</template>
|
</template>
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,52 +33,12 @@
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row>
|
|
||||||
<v-col cols="12" md="12">
|
|
||||||
<v-data-table-server
|
|
||||||
v-model:items-per-page="serverOptions.rowsPerPage"
|
|
||||||
v-model:page="serverOptions.page"
|
|
||||||
:headers="tableHeaders"
|
|
||||||
:items="items"
|
|
||||||
:items-length="totalItems"
|
|
||||||
:loading="loading"
|
|
||||||
class="elevation-1"
|
|
||||||
:items-per-page-options="[5, 10, 20, 50]"
|
|
||||||
item-value="id"
|
|
||||||
no-data-text="اطلاعاتی برای نمایش وجود ندارد"
|
|
||||||
:header-props="{ class: 'custom-header' }"
|
|
||||||
>
|
|
||||||
<template v-slot:item.index="{ index }">
|
|
||||||
{{ (serverOptions.page - 1) * serverOptions.rowsPerPage + index + 1 }}
|
|
||||||
</template>
|
|
||||||
<template v-slot:item.actions="{ item }">
|
|
||||||
<v-btn icon size="small" color="primary">
|
|
||||||
<v-icon>mdi-eye</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
</template>
|
|
||||||
<template v-slot:item.docType="{ item }">
|
|
||||||
{{ item.docType || '-' }}
|
|
||||||
</template>
|
|
||||||
<template v-slot:item.debit="{ item }">
|
|
||||||
{{ formatNumber(item.debit) }}
|
|
||||||
</template>
|
|
||||||
<template v-slot:item.credit="{ item }">
|
|
||||||
{{ formatNumber(item.credit) }}
|
|
||||||
</template>
|
|
||||||
<template v-slot:item.description="{ item }">
|
|
||||||
{{ item.description }}
|
|
||||||
</template>
|
|
||||||
</v-data-table-server>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
</v-container>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Hpersonsearch from '@/components/forms/Hpersonsearch.vue';
|
import Hpersonsearch from '@/components/forms/Hpersonsearch.vue'
|
||||||
import Hdatepicker from '@/components/forms/Hdatepicker.vue';
|
import Hdatepicker from '@/components/forms/Hdatepicker.vue'
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PersonWithDetReport',
|
name: 'PersonWithDetReport',
|
||||||
|
@ -90,75 +50,18 @@ export default {
|
||||||
return {
|
return {
|
||||||
selectedPerson: null,
|
selectedPerson: null,
|
||||||
startDate: '',
|
startDate: '',
|
||||||
endDate: '',
|
endDate: ''
|
||||||
loading: false,
|
}
|
||||||
items: [],
|
|
||||||
totalItems: 0,
|
|
||||||
serverOptions: {
|
|
||||||
page: 1,
|
|
||||||
rowsPerPage: 10,
|
|
||||||
sortBy: [],
|
|
||||||
},
|
|
||||||
tableHeaders: [
|
|
||||||
{ text: 'ردیف', value: 'index', align: 'center', sortable: false },
|
|
||||||
{ text: 'عملیات', value: 'actions', align: 'center', sortable: false },
|
|
||||||
{ text: 'نوع سند', value: 'docType', align: 'center' },
|
|
||||||
{ text: 'بدهکار', value: 'debit', align: 'center' },
|
|
||||||
{ text: 'بستانکار', value: 'credit', align: 'center' },
|
|
||||||
{ text: 'شرح', value: 'description', align: 'center' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatNumber(num) {
|
// متدهای مورد نیاز گزارش
|
||||||
if (!num) return '0';
|
|
||||||
return Number(num).toLocaleString('fa-IR');
|
|
||||||
},
|
|
||||||
async fetchData() {
|
|
||||||
if (!this.selectedPerson) {
|
|
||||||
this.items = [];
|
|
||||||
this.totalItems = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.loading = true;
|
|
||||||
try {
|
|
||||||
const response = await axios.post('/api/persons/listwithdet', {
|
|
||||||
person: this.selectedPerson.code,
|
|
||||||
startDate: this.startDate,
|
|
||||||
endDate: this.endDate,
|
|
||||||
page: this.serverOptions.page,
|
|
||||||
itemsPerPage: this.serverOptions.rowsPerPage,
|
|
||||||
});
|
|
||||||
this.items = response.data.items || [];
|
|
||||||
this.totalItems = response.data.total || this.items.length;
|
|
||||||
} catch (error) {
|
|
||||||
this.items = [];
|
|
||||||
this.totalItems = 0;
|
|
||||||
} finally {
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
selectedPerson: 'fetchData',
|
|
||||||
startDate: 'fetchData',
|
|
||||||
endDate: 'fetchData',
|
|
||||||
serverOptions: {
|
|
||||||
handler: 'fetchData',
|
|
||||||
deep: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// بارگذاری اولیه اگر شخص انتخاب شده باشد
|
// کدهای اجرایی در زمان بارگذاری کامپوننت
|
||||||
if (this.selectedPerson) {
|
}
|
||||||
this.fetchData();
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.sticky-container {
|
/* استایلهای مورد نیاز */
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
|
@ -792,21 +792,6 @@ export default {
|
||||||
// اول تنظیمات را لود میکنیم
|
// اول تنظیمات را لود میکنیم
|
||||||
this.loadSettings();
|
this.loadSettings();
|
||||||
|
|
||||||
// دریافت آیدی کسبوکار فعال از localStorage
|
|
||||||
const activeBid = localStorage.getItem('activeBid');
|
|
||||||
if (activeBid) {
|
|
||||||
try {
|
|
||||||
const businessRes = await axios.get(`/api/business/get/info/${activeBid}`);
|
|
||||||
if (businessRes.data && businessRes.data.maliyatafzode) {
|
|
||||||
// فقط اگر فاکتور جدید است مقدار پیشفرض مالیات را ست کن
|
|
||||||
if (!this.$route.params.id) {
|
|
||||||
this.taxPercent = Number(businessRes.data.maliyatafzode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('خطا در دریافت اطلاعات کسبوکار:', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// بررسی وضعیت پیشنویس
|
// بررسی وضعیت پیشنویس
|
||||||
this.isNewInvoice = !this.$route.params.id;
|
this.isNewInvoice = !this.$route.params.id;
|
||||||
|
|
||||||
|
|
|
@ -41,11 +41,6 @@ export default defineComponent({
|
||||||
recListWindowsState: { submited: false },
|
recListWindowsState: { submited: false },
|
||||||
notes: { count: 0 },
|
notes: { count: 0 },
|
||||||
bid: { legal_name: '', shortlinks: false },
|
bid: { legal_name: '', shortlinks: false },
|
||||||
snackbar: {
|
|
||||||
show: false,
|
|
||||||
text: '',
|
|
||||||
color: 'error'
|
|
||||||
},
|
|
||||||
item: {
|
item: {
|
||||||
doc: { id: 0, date: null, code: null, des: '', amount: 0, profit: 0, shortLink: null },
|
doc: { id: 0, date: null, code: null, des: '', amount: 0, profit: 0, shortLink: null },
|
||||||
relatedDocs: [],
|
relatedDocs: [],
|
||||||
|
@ -103,26 +98,6 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async checkCanEdit() {
|
|
||||||
try {
|
|
||||||
const response = await axios.get(`/api/sell/edit/can/${this.$route.params.id}`);
|
|
||||||
if (response.data.result) {
|
|
||||||
this.$router.push(`/acc/sell/mod/${this.$route.params.id}`);
|
|
||||||
} else {
|
|
||||||
this.snackbar = {
|
|
||||||
show: true,
|
|
||||||
text: 'شما مجاز به ویرایش این فاکتور نیستید',
|
|
||||||
color: 'error'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.snackbar = {
|
|
||||||
show: true,
|
|
||||||
text: 'خطا در بررسی دسترسی',
|
|
||||||
color: 'error'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
loadData() {
|
loadData() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.commoditys = [];
|
this.commoditys = [];
|
||||||
|
@ -198,7 +173,7 @@ export default defineComponent({
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-btn icon @click="checkCanEdit">
|
<v-btn icon :to="`/acc/sell/mod/${$route.params.id}`">
|
||||||
<v-icon>mdi-pencil</v-icon>
|
<v-icon>mdi-pencil</v-icon>
|
||||||
<v-tooltip activator="parent" location="bottom">ویرایش</v-tooltip>
|
<v-tooltip activator="parent" location="bottom">ویرایش</v-tooltip>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
@ -360,13 +335,6 @@ export default defineComponent({
|
||||||
</v-window-item>
|
</v-window-item>
|
||||||
</v-window>
|
</v-window>
|
||||||
</v-container>
|
</v-container>
|
||||||
<v-snackbar
|
|
||||||
v-model="snackbar.show"
|
|
||||||
:color="snackbar.color"
|
|
||||||
timeout="3000"
|
|
||||||
>
|
|
||||||
{{ snackbar.text }}
|
|
||||||
</v-snackbar>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
Loading…
Reference in a new issue