progress in webui
This commit is contained in:
parent
cc1fe8216d
commit
36802cbfcf
|
@ -7,16 +7,11 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use App\Entity\PlugGhestaDoc;
|
||||
use App\Entity\PlugGhestaItem;
|
||||
use App\Entity\HesabdariDoc;
|
||||
use App\Entity\PlugHrmDoc;
|
||||
use App\Entity\PlugHrmDocItem;
|
||||
use App\Entity\Person;
|
||||
use App\Service\Access;
|
||||
use App\Service\Provider;
|
||||
use App\Service\Printers;
|
||||
use App\Entity\PrintOptions;
|
||||
use App\Service\Log;
|
||||
use App\Entity\Business;
|
||||
|
||||
class DocsController extends AbstractController
|
||||
{
|
||||
|
@ -28,24 +23,209 @@ class DocsController extends AbstractController
|
|||
}
|
||||
|
||||
#[Route('/api/hrm/docs/list', name: 'hrm_docs_list', methods: ['POST'])]
|
||||
public function list(Request $request): JsonResponse
|
||||
public function list(Request $request, Access $access): JsonResponse
|
||||
{
|
||||
// TODO: پیادهسازی دریافت لیست اسناد حقوق
|
||||
return new JsonResponse([]);
|
||||
try {
|
||||
$params = [];
|
||||
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'])]
|
||||
public function get(int $id): JsonResponse
|
||||
public function get(int $id, Access $access): JsonResponse
|
||||
{
|
||||
// TODO: پیادهسازی دریافت اطلاعات یک سند حقوق
|
||||
return new JsonResponse([]);
|
||||
try {
|
||||
$acc = $access->hasRole('hrm');
|
||||
|
||||
$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'])]
|
||||
public function insert(Request $request): JsonResponse
|
||||
public function insert(Request $request, Access $access, Log $log): JsonResponse
|
||||
{
|
||||
// TODO: پیادهسازی ثبت سند حقوق جدید
|
||||
return new JsonResponse([]);
|
||||
try {
|
||||
$params = [];
|
||||
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'])]
|
||||
|
@ -56,9 +236,47 @@ class DocsController extends AbstractController
|
|||
}
|
||||
|
||||
#[Route('/api/hrm/docs/delete', name: 'hrm_docs_delete', methods: ['POST'])]
|
||||
public function delete(Request $request): JsonResponse
|
||||
public function delete(Request $request, Access $access, Log $log, EntityManagerInterface $entityManager): JsonResponse
|
||||
{
|
||||
// TODO: پیادهسازی حذف سند حقوق
|
||||
return new JsonResponse([]);
|
||||
try {
|
||||
$params = [];
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -297,6 +297,9 @@ class Business
|
|||
#[ORM\OneToMany(targetEntity: PlugGhestaDoc::class, mappedBy: 'bid', orphanRemoval: true)]
|
||||
private Collection $PlugGhestaDocs;
|
||||
|
||||
#[ORM\OneToMany(mappedBy: 'business', targetEntity: PlugHrmDoc::class)]
|
||||
private Collection $plugHrmDocs;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logs = new ArrayCollection();
|
||||
|
@ -339,6 +342,7 @@ class Business
|
|||
$this->hesabdariTables = new ArrayCollection();
|
||||
$this->accountingPackageOrders = new ArrayCollection();
|
||||
$this->PlugGhestaDocs = new ArrayCollection();
|
||||
$this->plugHrmDocs = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
|
@ -2055,4 +2059,31 @@ class Business
|
|||
|
||||
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,6 +140,12 @@ class HesabdariDoc
|
|||
#[ORM\OneToMany(targetEntity: PlugGhestaDoc::class, mappedBy: 'mainDoc', orphanRemoval: true)]
|
||||
private Collection $plugGhestaDocs;
|
||||
|
||||
/**
|
||||
* @var Collection<int, PlugHrmDoc>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: PlugHrmDoc::class, mappedBy: 'hesabdariDoc')]
|
||||
private Collection $plugHrmDocs;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->hesabdariRows = new ArrayCollection();
|
||||
|
@ -151,6 +157,7 @@ class HesabdariDoc
|
|||
$this->pairDoc = new ArrayCollection();
|
||||
$this->plugGhestaItems = new ArrayCollection();
|
||||
$this->plugGhestaDocs = new ArrayCollection();
|
||||
$this->plugHrmDocs = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
|
@ -689,4 +696,34 @@ class HesabdariDoc
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
144
hesabixCore/src/Entity/PlugHrmDoc.php
Normal file
144
hesabixCore/src/Entity/PlugHrmDoc.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?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;
|
||||
}
|
||||
}
|
125
hesabixCore/src/Entity/PlugHrmDocItem.php
Normal file
125
hesabixCore/src/Entity/PlugHrmDocItem.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?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;
|
||||
}
|
||||
}
|
15
hesabixCore/src/Repository/PlugHrmDocItemRepository.php
Normal file
15
hesabixCore/src/Repository/PlugHrmDocItemRepository.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?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);
|
||||
}
|
||||
}
|
15
hesabixCore/src/Repository/PlugHrmDocRepository.php
Normal file
15
hesabixCore/src/Repository/PlugHrmDocRepository.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?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);
|
||||
}
|
||||
}
|
|
@ -1,72 +1,251 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
{{ $t('drawer.hrm_docs') }}
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" prepend-icon="mdi-plus" to="/acc/hrm/docs/mod/">
|
||||
{{ $t('dialog.add_new') }}
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="items"
|
||||
:loading="loading"
|
||||
class="elevation-1"
|
||||
>
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn
|
||||
icon="mdi-eye"
|
||||
variant="text"
|
||||
size="small"
|
||||
:to="'/acc/hrm/docs/view/' + item.id"
|
||||
></v-btn>
|
||||
<v-btn
|
||||
icon="mdi-pencil"
|
||||
variant="text"
|
||||
size="small"
|
||||
:to="'/acc/hrm/docs/mod/' + item.id"
|
||||
></v-btn>
|
||||
<div>
|
||||
<v-toolbar color="toolbar" title="لیست حقوق">
|
||||
<template v-slot:prepend>
|
||||
<v-tooltip :text="$t('dialog.back')" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn v-bind="props" @click="$router.back()" class="d-none d-sm-flex" variant="text"
|
||||
icon="mdi-arrow-right" />
|
||||
</template>
|
||||
</v-data-table>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</v-tooltip>
|
||||
</template>
|
||||
<v-spacer></v-spacer>
|
||||
<v-tooltip text="افزودن سند حقوق" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<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>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
<v-menu>
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn variant="text" size="small" color="error" icon="mdi-menu" v-bind="props" />
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item :title="$t('dialog.view')" :to="'/acc/hrm/docs/view/' + item.id">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="green-darken-4" icon="mdi-eye"></v-icon>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item :title="$t('dialog.edit')" :to="'/acc/hrm/docs/mod/' + item.id">
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-file-edit"></v-icon>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="صدور سند حسابداری" :to="'/acc/hrm/docs/accounting/' + item.id">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="primary" icon="mdi-file-document-outline"></v-icon>
|
||||
</template>
|
||||
</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>
|
||||
</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>
|
||||
</div>
|
||||
</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>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import axios from 'axios'
|
||||
import moment from 'jalali-moment'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
headers: [
|
||||
{ title: this.$t('dialog.field.id'), key: 'id' },
|
||||
{ title: this.$t('dialog.field.date'), key: 'date' },
|
||||
{ title: this.$t('dialog.field.employee'), key: 'employee' },
|
||||
{ title: this.$t('dialog.field.amount'), key: 'amount' },
|
||||
{ title: this.$t('dialog.field.status'), key: 'status' },
|
||||
{ title: this.$t('dialog.field.actions'), key: 'actions', sortable: false }
|
||||
],
|
||||
items: []
|
||||
const searchValue = ref('')
|
||||
const loading = ref(true)
|
||||
const items = ref([])
|
||||
const deleteDialog = ref(false)
|
||||
const deleteLoading = ref(false)
|
||||
const selectedItem = ref(null)
|
||||
const snackbar = ref({
|
||||
show: false,
|
||||
message: '',
|
||||
color: 'success'
|
||||
})
|
||||
|
||||
const headers = [
|
||||
{ title: 'عملیات', key: 'actions' },
|
||||
{ title: 'تاریخ', key: 'date', sortable: true },
|
||||
{ title: 'ایجاد کننده', key: 'employee', sortable: true },
|
||||
{ title: 'مبلغ', key: 'amount', sortable: true },
|
||||
{ title: 'سند حسابداری', key: 'accounting_doc', sortable: true },
|
||||
{ title: 'توضیحات', key: 'description', sortable: true },
|
||||
]
|
||||
|
||||
const loadData = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await axios.post('/api/hrm/docs/list', {
|
||||
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'
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.loading = true
|
||||
try {
|
||||
const response = await axios.post('/api/hrm/docs/list')
|
||||
this.items = response.data
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error)
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
snackbar.value = {
|
||||
show: true,
|
||||
message: 'خطا در بارگذاری دادهها',
|
||||
color: 'error'
|
||||
};
|
||||
} finally {
|
||||
loading.value = 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'
|
||||
}
|
||||
this.loading = false
|
||||
}
|
||||
} catch (error) {
|
||||
snackbar.value = {
|
||||
show: true,
|
||||
message: error.response?.data?.message || 'خطا در ارتباط با سرور',
|
||||
color: 'error'
|
||||
}
|
||||
} finally {
|
||||
deleteLoading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-data-table {
|
||||
direction: rtl;
|
||||
}
|
||||
</style>
|
|
@ -25,7 +25,7 @@
|
|||
<v-row>
|
||||
<v-col cols="12" sm="6" md="6">
|
||||
<Hdatepicker v-model="form.date" :label="$t('dialog.hrm.date')"
|
||||
:rules="[v => !!v || $t('dialog.hrm.required_fields.date')]" required />
|
||||
:rules="[v => !!v || $t('dialog.hrm.required_fields.date')]" required density="compact" />
|
||||
</v-col>
|
||||
<v-col cols="12" sm="6" md="6">
|
||||
<v-text-field v-model="form.description" :label="$t('dialog.hrm.description')"
|
||||
|
@ -131,6 +131,9 @@
|
|||
import Hdatepicker from '@/components/forms/Hdatepicker.vue';
|
||||
import Hpersonsearch from '@/components/forms/Hpersonsearch.vue';
|
||||
import Hnumberinput from '@/components/forms/Hnumberinput.vue';
|
||||
import axios from 'axios';
|
||||
import moment from 'jalali-moment';
|
||||
|
||||
export default {
|
||||
components: { Hdatepicker, Hpersonsearch, Hnumberinput },
|
||||
data() {
|
||||
|
@ -150,20 +153,47 @@ export default {
|
|||
tableItems: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const id = this.$route.params.id
|
||||
if (id) {
|
||||
this.isEdit = true
|
||||
this.loadData(id)
|
||||
async mounted() {
|
||||
try {
|
||||
// دریافت تاریخ فعلی
|
||||
const response = await axios.get('/api/year/get');
|
||||
this.form.date = response.data.now;
|
||||
|
||||
const id = this.$route.params.id
|
||||
if (id) {
|
||||
this.isEdit = true
|
||||
await this.loadData(id)
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorMessage = error.response?.data?.error || 'خطا در دریافت تاریخ';
|
||||
this.showError = true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadData(id) {
|
||||
try {
|
||||
const response = await this.$axios.post('/api/hrm/docs/get/' + id)
|
||||
this.form = response.data
|
||||
const response = await axios.post('/api/hrm/docs/get/' + id)
|
||||
const data = response.data.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) {
|
||||
this.errorMessage = 'خطا در دریافت اطلاعات';
|
||||
this.errorMessage = error.response?.data?.error || 'خطا در دریافت اطلاعات';
|
||||
this.showError = true;
|
||||
}
|
||||
},
|
||||
|
@ -193,16 +223,35 @@ export default {
|
|||
},
|
||||
async save() {
|
||||
try {
|
||||
console.log('Starting save process...');
|
||||
this.loading = true;
|
||||
const url = this.isEdit ? '/api/hrm/docs/update' : '/api/hrm/docs/insert'
|
||||
await this.$axios.post(url, this.form)
|
||||
const url = this.isEdit ? '/api/hrm/docs/update' : '/api/hrm/docs/insert';
|
||||
const data = {
|
||||
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.showSuccess = true;
|
||||
setTimeout(() => {
|
||||
this.$router.push('/acc/hrm/docs/list')
|
||||
}, 1200)
|
||||
this.$router.push('/acc/hrm/docs/list');
|
||||
}, 1200);
|
||||
} catch (error) {
|
||||
this.errorMessage = this.$t('dialog.hrm.save_error');
|
||||
console.error('Save error:', error);
|
||||
this.errorMessage = error.response?.data?.error || this.$t('dialog.hrm.save_error');
|
||||
this.showError = true;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
|
@ -211,7 +260,7 @@ export default {
|
|||
async confirmDelete() {
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.$axios.post('/api/hrm/docs/delete', { id: this.$route.params.id })
|
||||
await axios.post('/api/hrm/docs/delete', { id: this.$route.params.id })
|
||||
this.successMessage = 'سند با موفقیت حذف شد';
|
||||
this.showSuccess = true;
|
||||
setTimeout(() => {
|
||||
|
@ -318,6 +367,14 @@ export default {
|
|||
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 {
|
||||
height: 100%;
|
||||
transition: all 0.3s ease;
|
||||
|
|
Loading…
Reference in a new issue