diff --git a/hesabixCore/src/Cog/HookService.php b/hesabixCore/src/Cog/HookService.php new file mode 100644 index 0000000..d125863 --- /dev/null +++ b/hesabixCore/src/Cog/HookService.php @@ -0,0 +1,182 @@ +entityManager = $entityManager; + $this->httpClient = $httpClient; + } + + /** + * دریافت تمام هوک‌های یک کسب و کار + */ + public function getHooksByBusiness(Business $business): array + { + return $this->entityManager->getRepository(Hook::class)->findBy([ + 'bid' => $business + ]); + } + + /** + * ارسال داده به تمام هوک‌های یک کسب و کار + */ + public function sendToHooks(Business $business, array $data, string $event = 'general'): array + { + $hooks = $this->getHooksByBusiness($business); + $results = []; + + foreach ($hooks as $hook) { + $result = $this->sendToHook($hook, $data, $event); + $results[] = [ + 'hook_id' => $hook->getId(), + 'url' => $hook->getUrl(), + 'success' => $result['success'], + 'response' => $result['response'], + 'error' => $result['error'] ?? null + ]; + } + + return $results; + } + + /** + * ارسال داده به یک هوک خاص + */ + public function sendToHook(Hook $hook, array $data, string $event = 'general'): array + { + $url = $hook->getUrl(); + $password = $hook->getPassword(); + + // آماده‌سازی داده‌های ارسالی + $payload = [ + 'event' => $event, + 'timestamp' => time(), + 'data' => $data, + 'password' => $password + ]; + + try { + $response = $this->httpClient->request('POST', $url, [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'User-Agent' => 'Hesabix-Hook-Service/1.0' + ], + 'json' => $payload, + 'timeout' => 10, + 'max_redirects' => 3 + ]); + + $statusCode = $response->getStatusCode(); + $content = $response->getContent(false); + + if ($statusCode >= 200 && $statusCode < 300) { + return [ + 'success' => true, + 'response' => json_decode($content, true) ?: $content, + 'status_code' => $statusCode + ]; + } else { + return [ + 'success' => false, + 'error' => "HTTP Error: {$statusCode}", + 'response' => $content, + 'status_code' => $statusCode + ]; + } + } catch (\Throwable $e) { + return [ + 'success' => false, + 'error' => $e->getMessage(), + 'status_code' => 0 + ]; + } + } + + /** + * ارسال اعلان تغییر شخص + */ + public function sendPersonChange(Business $business, array $personData, string $action = 'update'): array + { + $data = [ + 'action' => $action, + 'person' => $personData, + 'business_id' => $business->getId(), + 'business_name' => $business->getName() + ]; + + return $this->sendToHooks($business, $data, 'person_change'); + } + + /** + * ارسال اعلان تغییر کالا + */ + public function sendCommodityChange(Business $business, array $commodityData, string $action = 'update'): array + { + $data = [ + 'action' => $action, + 'commodity' => $commodityData, + 'business_id' => $business->getId(), + 'business_name' => $business->getName() + ]; + + return $this->sendToHooks($business, $data, 'commodity_change'); + } + + /** + * ارسال اعلان تغییر فاکتور + */ + public function sendInvoiceChange(Business $business, array $invoiceData, string $action = 'update'): array + { + $data = [ + 'action' => $action, + 'invoice' => $invoiceData, + 'business_id' => $business->getId(), + 'business_name' => $business->getName() + ]; + + return $this->sendToHooks($business, $data, 'invoice_change'); + } + + /** + * ارسال اعلان مالیاتی + */ + public function sendTaxNotification(Business $business, array $taxData, string $action = 'send'): array + { + $data = [ + 'action' => $action, + 'tax_invoice' => $taxData, + 'business_id' => $business->getId(), + 'business_name' => $business->getName() + ]; + + return $this->sendToHooks($business, $data, 'tax_notification'); + } + + /** + * تست اتصال به هوک + */ + public function testHook(Hook $hook): array + { + $testData = [ + 'test' => true, + 'message' => 'تست اتصال هوک', + 'timestamp' => time() + ]; + + return $this->sendToHook($hook, $testData, 'test'); + } +} \ No newline at end of file diff --git a/hesabixCore/src/Controller/BusinessController.php b/hesabixCore/src/Controller/BusinessController.php index 01ff268..698f066 100644 --- a/hesabixCore/src/Controller/BusinessController.php +++ b/hesabixCore/src/Controller/BusinessController.php @@ -545,6 +545,7 @@ class BusinessController extends AbstractController 'plugHrmDocs' => true, 'plugGhestaManager' => true, 'plugTaxSettings' => true, + 'plugWarranty' => true, 'inquiry' => true, 'ai' => true, ]; @@ -591,6 +592,7 @@ class BusinessController extends AbstractController 'plugHrmDocs' => $perm->isPlugHrmDocs(), 'plugGhestaManager' => $perm->isPlugGhestaManager(), 'plugTaxSettings' => $perm->isPlugTaxSettings(), + 'plugWarranty' => $perm->isPlugWarrantyManager(), 'inquiry' => $perm->isInquiry(), 'ai' => $perm->isAi(), ]; @@ -662,6 +664,7 @@ class BusinessController extends AbstractController $perm->setPlugRepservice($params['plugRepservice']); $perm->setPlugHrmDocs($params['plugHrmDocs']); $perm->setPlugGhestaManager($params['plugGhestaManager']); + $perm->setPlugWarrantyManager($params['plugWarranty'] ?? false); $perm->setPlugTaxSettings($params['plugTaxSettings']); $perm->setInquiry($params['inquiry']); $perm->setAi($params['ai']); diff --git a/hesabixCore/src/Controller/CommodityController.php b/hesabixCore/src/Controller/CommodityController.php index 4ade305..54d47ff 100644 --- a/hesabixCore/src/Controller/CommodityController.php +++ b/hesabixCore/src/Controller/CommodityController.php @@ -182,7 +182,23 @@ class CommodityController extends AbstractController ]); $res = []; foreach ($items as $item) { - $res[] = Explore::ExploreCommodity($item); + $temp = Explore::ExploreCommodity($item); + if (!$item->isKhadamat()) { + $rows = $entityManager->getRepository('App\Entity\HesabdariRow')->findBy([ + 'bid' => $acc['bid'], + 'commodity' => $item + ]); + $count = 0; + foreach ($rows as $row) { + if ($row->getDoc()->getType() === 'buy' || $row->getDoc()->getType() === 'open_balance') { + $count += $row->getCommdityCount(); + } else { + $count -= $row->getCommdityCount(); + } + } + $temp['count'] = $count; + } + $res[] = $temp; } return $this->json($extractor->operationSuccess([ 'List' => $res, diff --git a/hesabixCore/src/Controller/PluginController.php b/hesabixCore/src/Controller/PluginController.php index dc73354..4163b4b 100644 --- a/hesabixCore/src/Controller/PluginController.php +++ b/hesabixCore/src/Controller/PluginController.php @@ -470,6 +470,15 @@ class PluginController extends AbstractController 'icon' => ' taxplugin.jpg', 'defaultOn' => null, ], + // [ + // 'name' => 'مدیریت گارانتی', + // 'code' => 'warranty', + // 'timestamp' => '32104000', + // 'timelabel' => 'یک سال', + // 'price' => '200000', + // 'icon' => 'warranty.png', + // 'defaultOn' => null, + // ], ]; $repo = $entityManager->getRepository(PluginProdect::class); diff --git a/hesabixCore/src/Controller/Plugins/PlugWarrantyController.php b/hesabixCore/src/Controller/Plugins/PlugWarrantyController.php new file mode 100644 index 0000000..4e8c334 --- /dev/null +++ b/hesabixCore/src/Controller/Plugins/PlugWarrantyController.php @@ -0,0 +1,556 @@ +entityManager = $entityManager; + } + + private function updateExpiredSerials(EntityManagerInterface $entityManager, $businessId): void + { + $repository = $entityManager->getRepository(PlugWarrantySerial::class); + $jdate = new Jdate(); + $today = $jdate->GetTodayDate(); + + $expiredSerials = $repository->createQueryBuilder('s') + ->where('s.bid = :businessId') + ->andWhere('s.status = :status') + ->andWhere('s.warrantyEndDate IS NOT NULL') + ->andWhere('s.warrantyEndDate < :today') + ->setParameter('businessId', $businessId) + ->setParameter('status', 'active') + ->setParameter('today', $today) + ->getQuery() + ->getResult(); + + foreach ($expiredSerials as $serial) { + $serial->setStatus('expired'); + } + + if (!empty($expiredSerials)) { + $entityManager->flush(); + } + } + + private function checkAndUpdateSerialStatus($serial, EntityManagerInterface $entityManager): void + { + $jdate = new Jdate(); + $today = $jdate->GetTodayDate(); + $warrantyEndDate = $serial->getWarrantyEndDate(); + + if ($serial->getStatus() === 'active' && + $warrantyEndDate && + $warrantyEndDate < $today) { + $serial->setStatus('expired'); + $entityManager->flush(); + } + } + + #[Route('/api/plugins/warranty/serials', name: 'plugin_warranty_serials', methods: ['GET'])] + public function plugin_warranty_serials(EntityManagerInterface $entityManager, Access $access, Request $request): JsonResponse + { + try { + $acc = $access->hasRole('plugWarrantyManager'); + if(!$acc) + throw $this->createAccessDeniedException(); + + $this->updateExpiredSerials($entityManager, $acc['bid']); + + $page = $request->query->get('page', 1); + $limit = $request->query->get('limit', 20); + $status = $request->query->get('status'); + $commodityId = $request->query->get('commodity_id'); + $search = $request->query->get('search'); + + $repository = $entityManager->getRepository(PlugWarrantySerial::class); + + if ($search) { + $serials = $repository->searchSerials($acc['bid'], $search); + } elseif ($status) { + $serials = $repository->findByStatus($acc['bid'], $status); + } elseif ($commodityId) { + $serials = $repository->findByCommodity($acc['bid'], $commodityId); + } else { + $serials = $repository->findByBusiness($acc['bid']); + } + + $data = []; + foreach($serials as $serial){ + $commodity = $serial->getCommodity(); + $submitter = $serial->getSubmitter(); + + $data[] = [ + 'id' => $serial->getId(), + 'serialNumber' => $serial->getSerialNumber(), + 'commodity' => $commodity ? [ + 'id' => $commodity->getId(), + 'name' => $commodity->getName(), + 'code' => $commodity->getCode() + ] : null, + 'dateSubmit' => $serial->getDateSubmit(), + 'description' => $serial->getDescription(), + 'warrantyStartDate' => $serial->getWarrantyStartDate(), + 'warrantyEndDate' => $serial->getWarrantyEndDate(), + 'status' => $serial->getStatus(), + 'notes' => $serial->getNotes(), + 'submitter' => $submitter ? [ + 'id' => $submitter->getId(), + 'name' => $submitter->getFullName() + ] : null + ]; + } + + return $this->json($data); + } catch (\Exception $e) { + return $this->json([ + 'error' => $e->getMessage() + ], 500); + } + } + + #[Route('/api/plugins/warranty/serials/{id}', name: 'plugin_warranty_serial', methods: ['GET'])] + public function plugin_warranty_serial(EntityManagerInterface $entityManager, Access $access, $id): JsonResponse + { + try { + $acc = $access->hasRole('plugWarrantyManager'); + if(!$acc) + throw $this->createAccessDeniedException(); + + $serial = $entityManager->getRepository(PlugWarrantySerial::class)->findOneBy([ + 'id' => $id, + 'bid' => $acc['bid'] + ]); + + if(!$serial) + throw $this->createNotFoundException(); + + $this->checkAndUpdateSerialStatus($serial, $entityManager); + + $data = [ + 'id' => $serial->getId(), + 'serialNumber' => $serial->getSerialNumber(), + 'commodity' => [ + 'id' => $serial->getCommodity()->getId(), + 'name' => $serial->getCommodity()->getName(), + 'code' => $serial->getCommodity()->getCode() + ], + 'dateSubmit' => $serial->getDateSubmit(), + 'description' => $serial->getDescription(), + 'warrantyStartDate' => $serial->getWarrantyStartDate(), + 'warrantyEndDate' => $serial->getWarrantyEndDate(), + 'status' => $serial->getStatus(), + 'notes' => $serial->getNotes(), + 'submitter' => [ + 'id' => $serial->getSubmitter()->getId(), + 'name' => $serial->getSubmitter()->getFullName() + ] + ]; + + return $this->json($data); + } catch (\Exception $e) { + return $this->json([ + 'error' => $e->getMessage() + ], 500); + } + } + + #[Route('/api/plugins/warranty/serials/add', name: 'plugin_warranty_serial_add', methods: ['POST'])] + public function plugin_warranty_serial_add(Request $request, EntityManagerInterface $entityManager, Access $access, Log $log): JsonResponse + { + try { + $acc = $access->hasRole('plugWarrantyManager'); + if(!$acc) + throw $this->createAccessDeniedException(); + + $params = []; + if ($content = $request->getContent()) { + $params = json_decode($content, true); + } + + if(!array_key_exists('serialNumber', $params) || !array_key_exists('commodity_id', $params)) + throw $this->createAccessDeniedException('پارامترهای ناقص'); + + $repository = $entityManager->getRepository(PlugWarrantySerial::class); + + if($repository->isSerialNumberExists($params['serialNumber'], $acc['bid'])) { + return $this->json(['error' => 'شماره سریال تکراری است'], 400); + } + + $commodity = $entityManager->getRepository(Commodity::class)->findOneBy([ + 'id' => $params['commodity_id'], + 'bid' => $acc['bid'] + ]); + + if(!$commodity) { + return $this->json(['error' => 'محصول یافت نشد'], 400); + } + + $serial = new PlugWarrantySerial(); + $serial->setSerialNumber($params['serialNumber']); + $serial->setCommodity($commodity); + $serial->setBid($acc['bid']); + $serial->setSubmitter($this->getUser()); + $serial->setDescription($params['description'] ?? null); + $serial->setWarrantyStartDate($params['warrantyStartDate'] ?? null); + $serial->setWarrantyEndDate($params['warrantyEndDate'] ?? null); + $serial->setStatus($params['status'] ?? 'active'); + $serial->setNotes($params['notes'] ?? null); + + $entityManager->persist($serial); + $entityManager->flush(); + + $log->insert( + 'گارانتی', + 'افزودن سریال جدید: ' . $params['serialNumber'], + $this->getUser(), + $acc['bid'] + ); + + return $this->json([ + 'success' => true, + 'message' => 'سریال با موفقیت افزوده شد', + 'id' => $serial->getId() + ]); + } catch (\Exception $e) { + return $this->json([ + 'error' => $e->getMessage() + ], 500); + } + } + + #[Route('/api/plugins/warranty/serials/edit/{id}', name: 'plugin_warranty_serial_edit', methods: ['POST'])] + public function plugin_warranty_serial_edit(Request $request, EntityManagerInterface $entityManager, Access $access, $id, Log $log): JsonResponse + { + try { + $acc = $access->hasRole('plugWarrantyManager'); + if(!$acc) + throw $this->createAccessDeniedException(); + + $serial = $entityManager->getRepository(PlugWarrantySerial::class)->findOneBy([ + 'id' => $id, + 'bid' => $acc['bid'] + ]); + + if(!$serial) + throw $this->createNotFoundException(); + + $params = []; + if ($content = $request->getContent()) { + $params = json_decode($content, true); + } + + if(array_key_exists('serialNumber', $params)) { + $repository = $entityManager->getRepository(PlugWarrantySerial::class); + $existingSerial = $repository->createQueryBuilder('p') + ->andWhere('p.serialNumber = :serialNumber') + ->andWhere('p.bid = :bid') + ->andWhere('p.id != :id') + ->setParameter('serialNumber', $params['serialNumber']) + ->setParameter('bid', $acc['bid']) + ->setParameter('id', $id) + ->getQuery() + ->getOneOrNullResult(); + + if($existingSerial) { + return $this->json(['error' => 'شماره سریال تکراری است'], 400); + } + + $serial->setSerialNumber($params['serialNumber']); + } + + if(array_key_exists('commodity_id', $params)) { + $commodity = $entityManager->getRepository(Commodity::class)->findOneBy([ + 'id' => $params['commodity_id'], + 'bid' => $acc['bid'] + ]); + + if(!$commodity) { + return $this->json(['error' => 'محصول یافت نشد'], 400); + } + + $serial->setCommodity($commodity); + } + + if(array_key_exists('description', $params)) { + $serial->setDescription($params['description']); + } + + if(array_key_exists('warrantyStartDate', $params)) { + $serial->setWarrantyStartDate($params['warrantyStartDate']); + } + + if(array_key_exists('warrantyEndDate', $params)) { + $serial->setWarrantyEndDate($params['warrantyEndDate']); + } + + if(array_key_exists('status', $params)) { + $serial->setStatus($params['status']); + } + + if(array_key_exists('notes', $params)) { + $serial->setNotes($params['notes']); + } + + $entityManager->flush(); + + $log->insert( + 'گارانتی', + 'ویرایش سریال: ' . $serial->getSerialNumber(), + $this->getUser(), + $acc['bid'] + ); + + return $this->json([ + 'success' => true, + 'message' => 'سریال با موفقیت ویرایش شد' + ]); + } catch (\Exception $e) { + return $this->json([ + 'error' => $e->getMessage() + ], 500); + } + } + + #[Route('/api/plugins/warranty/serials/{id}', name: 'plugin_warranty_serial_delete', methods: ['DELETE'])] + public function plugin_warranty_serial_delete(EntityManagerInterface $entityManager, Access $access, $id, Log $log): JsonResponse + { + try { + $acc = $access->hasRole('plugWarrantyManager'); + if(!$acc) + throw $this->createAccessDeniedException(); + + $serial = $entityManager->getRepository(PlugWarrantySerial::class)->findOneBy([ + 'id' => $id, + 'bid' => $acc['bid'] + ]); + + if(!$serial) + throw $this->createNotFoundException(); + + $serialNumber = $serial->getSerialNumber(); + $entityManager->remove($serial); + $entityManager->flush(); + + $log->insert( + 'گارانتی', + 'حذف سریال: ' . $serialNumber, + $this->getUser(), + $acc['bid'] + ); + + return $this->json([ + 'success' => true, + 'message' => 'سریال با موفقیت حذف شد' + ]); + } catch (\Exception $e) { + return $this->json([ + 'error' => $e->getMessage() + ], 500); + } + } + + #[Route('/api/plugins/warranty/serials/bulk-import', name: 'plugin_warranty_serial_bulk_import', methods: ['POST'])] + public function plugin_warranty_serial_bulk_import(Request $request, EntityManagerInterface $entityManager, Access $access, Log $log): JsonResponse + { + try { + $acc = $access->hasRole('plugWarrantyManager'); + if(!$acc) + throw $this->createAccessDeniedException(); + + $params = []; + if ($content = $request->getContent()) { + $params = json_decode($content, true); + } + + if(!array_key_exists('serials', $params) || !is_array($params['serials'])) + throw $this->createAccessDeniedException('داده‌های نامعتبر'); + + $repository = $entityManager->getRepository(PlugWarrantySerial::class); + $commodityRepo = $entityManager->getRepository(Commodity::class); + + $successCount = 0; + $errorCount = 0; + $errors = []; + + foreach($params['serials'] as $index => $serialData) { + try { + if(!array_key_exists('serialNumber', $serialData) || !array_key_exists('commodity_id', $serialData)) { + $errors[] = "ردیف " . ($index + 1) . ": پارامترهای ناقص"; + $errorCount++; + continue; + } + + if($repository->isSerialNumberExists($serialData['serialNumber'], $acc['bid'])) { + $errors[] = "ردیف " . ($index + 1) . ": شماره سریال تکراری است"; + $errorCount++; + continue; + } + + $commodity = $commodityRepo->findOneBy([ + 'id' => $serialData['commodity_id'], + 'bid' => $acc['bid'] + ]); + + if(!$commodity) { + $errors[] = "ردیف " . ($index + 1) . ": محصول یافت نشد"; + $errorCount++; + continue; + } + + $serial = new PlugWarrantySerial(); + $serial->setSerialNumber($serialData['serialNumber']); + $serial->setCommodity($commodity); + $serial->setBid($acc['bid']); + $serial->setSubmitter($this->getUser()); + $serial->setDescription($serialData['description'] ?? null); + $serial->setWarrantyStartDate($serialData['warrantyStartDate'] ?? null); + $serial->setWarrantyEndDate($serialData['warrantyEndDate'] ?? null); + $serial->setStatus($serialData['status'] ?? 'active'); + $serial->setNotes($serialData['notes'] ?? null); + + $entityManager->persist($serial); + $successCount++; + + } catch (\Exception $e) { + $errors[] = "ردیف " . ($index + 1) . ": " . $e->getMessage(); + $errorCount++; + } + } + + $entityManager->flush(); + + $log->insert( + 'گارانتی', + 'وارد کردن انبوه سریال‌های گارانتی: ' . $successCount . ' موفق، ' . $errorCount . ' ناموفق', + $this->getUser(), + $acc['bid'] + ); + + return $this->json([ + 'success' => true, + 'message' => 'عملیات وارد کردن انبوه تکمیل شد', + 'successCount' => $successCount, + 'errorCount' => $errorCount, + 'errors' => $errors + ]); + } catch (\Exception $e) { + return $this->json([ + 'error' => $e->getMessage() + ], 500); + } + } + + #[Route('/api/plugins/warranty/stats', name: 'plugin_warranty_stats', methods: ['GET'])] + public function plugin_warranty_stats(EntityManagerInterface $entityManager, Access $access): JsonResponse + { + try { + $acc = $access->hasRole('plugWarrantyManager'); + if(!$acc) + throw $this->createAccessDeniedException(); + + $this->updateExpiredSerials($entityManager, $acc['bid']); + + $repository = $entityManager->getRepository(PlugWarrantySerial::class); + + $allSerials = $repository->createQueryBuilder('p') + ->andWhere('p.bid = :bid') + ->setParameter('bid', $acc['bid']) + ->getQuery() + ->getResult(); + + $totalSerials = count($allSerials); + $activeSerials = 0; + $inactiveSerials = 0; + $expiredSerials = 0; + + foreach ($allSerials as $serial) { + $status = $serial->getStatus(); + switch ($status) { + case 'active': + $activeSerials++; + break; + case 'inactive': + $inactiveSerials++; + break; + case 'expired': + $expiredSerials++; + break; + } + } + + return $this->json([ + 'totalSerials' => $totalSerials, + 'activeSerials' => $activeSerials, + 'inactiveSerials' => $inactiveSerials, + 'expiredSerials' => $expiredSerials, + ]); + } catch (\Exception $e) { + return $this->json([ + 'error' => $e->getMessage() + ], 500); + } + } + + #[Route('/api/plugins/warranty/serials/update-expired', name: 'plugin_warranty_update_expired', methods: ['POST'])] + public function plugin_warranty_update_expired(EntityManagerInterface $entityManager, Access $access): JsonResponse + { + try { + $acc = $access->hasRole('plugWarrantyManager'); + if(!$acc) + throw $this->createAccessDeniedException(); + + $repository = $entityManager->getRepository(PlugWarrantySerial::class); + $jdate = new Jdate(); + $today = $jdate->GetTodayDate(); + + $expiredSerials = $repository->createQueryBuilder('s') + ->where('s.bid = :businessId') + ->andWhere('s.status = :status') + ->andWhere('s.warrantyEndDate IS NOT NULL') + ->andWhere('s.warrantyEndDate < :today') + ->setParameter('businessId', $acc['bid']) + ->setParameter('status', 'active') + ->setParameter('today', $today) + ->getQuery() + ->getResult(); + + $updatedCount = 0; + + foreach ($expiredSerials as $serial) { + $serial->setStatus('expired'); + $updatedCount++; + } + + if ($updatedCount > 0) { + $entityManager->flush(); + } + + return $this->json([ + 'success' => true, + 'message' => 'به‌روزرسانی وضعیت سریال‌های منقضی شده تکمیل شد', + 'updatedCount' => $updatedCount + ]); + } catch (\Exception $e) { + return $this->json([ + 'error' => $e->getMessage() + ], 500); + } + } +} \ No newline at end of file diff --git a/hesabixCore/src/Entity/Business.php b/hesabixCore/src/Entity/Business.php index 8595231..3a78707 100644 --- a/hesabixCore/src/Entity/Business.php +++ b/hesabixCore/src/Entity/Business.php @@ -303,6 +303,10 @@ class Business #[ORM\OneToMany(mappedBy: 'business', targetEntity: AIConversation::class, orphanRemoval: true)] private Collection $aiConversations; + #[ORM\OneToMany(mappedBy: 'bid', targetEntity: PlugWarrantySerial::class, orphanRemoval: true)] + #[Ignore] + private Collection $plugWarrantySerials; + public function __construct() { $this->logs = new ArrayCollection(); @@ -347,6 +351,7 @@ class Business $this->PlugGhestaDocs = new ArrayCollection(); $this->plugHrmDocs = new ArrayCollection(); $this->aiConversations = new ArrayCollection(); + $this->plugWarrantySerials = new ArrayCollection(); } public function getId(): ?int @@ -2120,4 +2125,34 @@ class Business return $this; } + + /** + * @return Collection + */ + public function getPlugWarrantySerials(): Collection + { + return $this->plugWarrantySerials; + } + + public function addPlugWarrantySerial(PlugWarrantySerial $plugWarrantySerial): static + { + if (!$this->plugWarrantySerials->contains($plugWarrantySerial)) { + $this->plugWarrantySerials->add($plugWarrantySerial); + $plugWarrantySerial->setBid($this); + } + + return $this; + } + + public function removePlugWarrantySerial(PlugWarrantySerial $plugWarrantySerial): static + { + if ($this->plugWarrantySerials->removeElement($plugWarrantySerial)) { + // set the owning side to null (unless already changed) + if ($plugWarrantySerial->getBid() === $this) { + $plugWarrantySerial->setBid(null); + } + } + + return $this; + } } diff --git a/hesabixCore/src/Entity/Commodity.php b/hesabixCore/src/Entity/Commodity.php index 5f3f68e..06f5ae5 100644 --- a/hesabixCore/src/Entity/Commodity.php +++ b/hesabixCore/src/Entity/Commodity.php @@ -80,6 +80,10 @@ class Commodity #[ORM\OneToMany(mappedBy: 'commodity', targetEntity: PlugRepserviceOrder::class, orphanRemoval: true)] private Collection $plugRepserviceOrders; + #[ORM\OneToMany(mappedBy: 'commodity', targetEntity: PlugWarrantySerial::class, orphanRemoval: true)] + #[Ignore] + private Collection $plugWarrantySerials; + #[ORM\Column(nullable: true)] private ?bool $withoutTax = null; @@ -115,6 +119,7 @@ class Commodity $this->commodityDropLinks = new ArrayCollection(); $this->storeroomItems = new ArrayCollection(); $this->plugRepserviceOrders = new ArrayCollection(); + $this->plugWarrantySerials = new ArrayCollection(); $this->priceListDetails = new ArrayCollection(); $this->preInvoiceItems = new ArrayCollection(); } @@ -424,6 +429,36 @@ class Commodity return $this; } + /** + * @return Collection + */ + public function getPlugWarrantySerials(): Collection + { + return $this->plugWarrantySerials; + } + + public function addPlugWarrantySerial(PlugWarrantySerial $plugWarrantySerial): static + { + if (!$this->plugWarrantySerials->contains($plugWarrantySerial)) { + $this->plugWarrantySerials->add($plugWarrantySerial); + $plugWarrantySerial->setCommodity($this); + } + + return $this; + } + + public function removePlugWarrantySerial(PlugWarrantySerial $plugWarrantySerial): static + { + if ($this->plugWarrantySerials->removeElement($plugWarrantySerial)) { + // set the owning side to null (unless already changed) + if ($plugWarrantySerial->getCommodity() === $this) { + $plugWarrantySerial->setCommodity(null); + } + } + + return $this; + } + public function isWithoutTax(): ?bool { return $this->withoutTax; diff --git a/hesabixCore/src/Entity/Permission.php b/hesabixCore/src/Entity/Permission.php index 59550ab..233d9a7 100644 --- a/hesabixCore/src/Entity/Permission.php +++ b/hesabixCore/src/Entity/Permission.php @@ -129,6 +129,9 @@ class Permission #[ORM\Column(nullable: true)] private ?bool $plugGhestaManager = null; + #[ORM\Column(nullable: true)] + private ?bool $plugWarrantyManager = null; + #[ORM\Column(nullable: true)] private ?bool $plugTaxSettings = null; @@ -599,6 +602,18 @@ class Permission return $this; } + public function isPlugWarrantyManager(): ?bool + { + return $this->plugWarrantyManager; + } + + public function setPlugWarrantyManager(?bool $plugWarrantyManager): static + { + $this->plugWarrantyManager = $plugWarrantyManager; + + return $this; + } + public function isPlugTaxSettings(): ?bool { return $this->plugTaxSettings; diff --git a/hesabixCore/src/Entity/PlugWarrantySerial.php b/hesabixCore/src/Entity/PlugWarrantySerial.php new file mode 100644 index 0000000..8555311 --- /dev/null +++ b/hesabixCore/src/Entity/PlugWarrantySerial.php @@ -0,0 +1,171 @@ +dateSubmit = date('Y-m-d H:i:s'); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getBid(): ?Business + { + return $this->bid; + } + + public function setBid(?Business $bid): static + { + $this->bid = $bid; + return $this; + } + + public function getCommodity(): ?Commodity + { + return $this->commodity; + } + + public function setCommodity(?Commodity $commodity): static + { + $this->commodity = $commodity; + return $this; + } + + public function getSerialNumber(): ?string + { + return $this->serialNumber; + } + + public function setSerialNumber(string $serialNumber): static + { + $this->serialNumber = $serialNumber; + return $this; + } + + public function getDateSubmit(): ?string + { + return $this->dateSubmit; + } + + public function setDateSubmit(string $dateSubmit): static + { + $this->dateSubmit = $dateSubmit; + return $this; + } + + public function getSubmitter(): ?User + { + return $this->submitter; + } + + public function setSubmitter(?User $submitter): static + { + $this->submitter = $submitter; + return $this; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + return $this; + } + + public function getWarrantyStartDate(): ?string + { + return $this->warrantyStartDate; + } + + public function setWarrantyStartDate(?string $warrantyStartDate): static + { + $this->warrantyStartDate = $warrantyStartDate; + return $this; + } + + public function getWarrantyEndDate(): ?string + { + return $this->warrantyEndDate; + } + + public function setWarrantyEndDate(?string $warrantyEndDate): static + { + $this->warrantyEndDate = $warrantyEndDate; + return $this; + } + + public function getStatus(): ?string + { + return $this->status; + } + + public function setStatus(?string $status): static + { + $this->status = $status; + return $this; + } + + public function getNotes(): ?string + { + return $this->notes; + } + + public function setNotes(?string $notes): static + { + $this->notes = $notes; + return $this; + } +} \ No newline at end of file diff --git a/hesabixCore/src/Entity/User.php b/hesabixCore/src/Entity/User.php index 630f9ea..6c361e9 100644 --- a/hesabixCore/src/Entity/User.php +++ b/hesabixCore/src/Entity/User.php @@ -98,6 +98,10 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\OneToMany(mappedBy: 'submitter', targetEntity: PlugRepserviceOrder::class, orphanRemoval: true)] private Collection $plugRepserviceOrders; + #[ORM\OneToMany(mappedBy: 'submitter', targetEntity: PlugWarrantySerial::class, orphanRemoval: true)] + #[Ignore] + private Collection $plugWarrantySerials; + #[ORM\OneToMany(mappedBy: 'submitter', targetEntity: Note::class, orphanRemoval: true)] private Collection $notes; @@ -159,6 +163,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface $this->cheques = new ArrayCollection(); $this->mostDes = new ArrayCollection(); $this->plugRepserviceOrders = new ArrayCollection(); + $this->plugWarrantySerials = new ArrayCollection(); $this->notes = new ArrayCollection(); $this->preInvoiceDocs = new ArrayCollection(); $this->dashboardSettings = new ArrayCollection(); @@ -798,6 +803,36 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface return $this; } + /** + * @return Collection + */ + public function getPlugWarrantySerials(): Collection + { + return $this->plugWarrantySerials; + } + + public function addPlugWarrantySerial(PlugWarrantySerial $plugWarrantySerial): static + { + if (!$this->plugWarrantySerials->contains($plugWarrantySerial)) { + $this->plugWarrantySerials->add($plugWarrantySerial); + $plugWarrantySerial->setSubmitter($this); + } + + return $this; + } + + public function removePlugWarrantySerial(PlugWarrantySerial $plugWarrantySerial): static + { + if ($this->plugWarrantySerials->removeElement($plugWarrantySerial)) { + // set the owning side to null (unless already changed) + if ($plugWarrantySerial->getSubmitter() === $this) { + $plugWarrantySerial->setSubmitter(null); + } + } + + return $this; + } + /** * @return Collection */ diff --git a/hesabixCore/src/Repository/PlugWarrantySerialRepository.php b/hesabixCore/src/Repository/PlugWarrantySerialRepository.php new file mode 100644 index 0000000..63fa855 --- /dev/null +++ b/hesabixCore/src/Repository/PlugWarrantySerialRepository.php @@ -0,0 +1,98 @@ + + */ +class PlugWarrantySerialRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, PlugWarrantySerial::class); + } + + /** + * @return PlugWarrantySerial[] Returns an array of PlugWarrantySerial objects + */ + public function findByBusiness($bid): array + { + return $this->createQueryBuilder('p') + ->andWhere('p.bid = :val') + ->setParameter('val', $bid) + ->orderBy('p.dateSubmit', 'DESC') + ->getQuery() + ->getResult() + ; + } + + /** + * @return PlugWarrantySerial[] Returns an array of PlugWarrantySerial objects by commodity + */ + public function findByCommodity($bid, $commodityId): array + { + return $this->createQueryBuilder('p') + ->andWhere('p.bid = :bid') + ->andWhere('p.commodity = :commodityId') + ->setParameter('bid', $bid) + ->setParameter('commodityId', $commodityId) + ->orderBy('p.dateSubmit', 'DESC') + ->getQuery() + ->getResult() + ; + } + + /** + * @return PlugWarrantySerial[] Returns an array of PlugWarrantySerial objects by status + */ + public function findByStatus($bid, $status): array + { + return $this->createQueryBuilder('p') + ->andWhere('p.bid = :bid') + ->andWhere('p.status = :status') + ->setParameter('bid', $bid) + ->setParameter('status', $status) + ->orderBy('p.dateSubmit', 'DESC') + ->getQuery() + ->getResult() + ; + } + + /** + * Check if serial number exists + */ + public function isSerialNumberExists($serialNumber, $bid = null): bool + { + $qb = $this->createQueryBuilder('p') + ->andWhere('p.serialNumber = :serialNumber') + ->setParameter('serialNumber', $serialNumber); + + if ($bid) { + $qb->andWhere('p.bid = :bid') + ->setParameter('bid', $bid); + } + + return $qb->getQuery()->getOneOrNullResult() !== null; + } + + /** + * Search serials by keyword + */ + public function searchSerials($bid, $keyword): array + { + return $this->createQueryBuilder('p') + ->leftJoin('p.commodity', 'c') + ->andWhere('p.bid = :bid') + ->andWhere('p.serialNumber LIKE :keyword OR c.name LIKE :keyword OR p.description LIKE :keyword') + ->setParameter('bid', $bid) + ->setParameter('keyword', '%' . $keyword . '%') + ->orderBy('p.dateSubmit', 'DESC') + ->getQuery() + ->getResult() + ; + } +} \ No newline at end of file diff --git a/webUI/src/components/plugins/warranty/BulkImportDialog.vue b/webUI/src/components/plugins/warranty/BulkImportDialog.vue new file mode 100644 index 0000000..ab0cd28 --- /dev/null +++ b/webUI/src/components/plugins/warranty/BulkImportDialog.vue @@ -0,0 +1,532 @@ + + + + + \ No newline at end of file diff --git a/webUI/src/components/plugins/warranty/SerialDialog.vue b/webUI/src/components/plugins/warranty/SerialDialog.vue new file mode 100644 index 0000000..1d5ef89 --- /dev/null +++ b/webUI/src/components/plugins/warranty/SerialDialog.vue @@ -0,0 +1,288 @@ + + + + + \ No newline at end of file diff --git a/webUI/src/components/plugins/warranty/SerialViewDialog.vue b/webUI/src/components/plugins/warranty/SerialViewDialog.vue new file mode 100644 index 0000000..267575e --- /dev/null +++ b/webUI/src/components/plugins/warranty/SerialViewDialog.vue @@ -0,0 +1,183 @@ + + + + + \ No newline at end of file diff --git a/webUI/src/i18n/en_lang.ts b/webUI/src/i18n/en_lang.ts index e087b45..ab7c4ba 100755 --- a/webUI/src/i18n/en_lang.ts +++ b/webUI/src/i18n/en_lang.ts @@ -89,6 +89,8 @@ const en_lang = { inquiry: "Inquiries", hrm: 'HR & Payroll', hrm_docs: 'Payroll Document', + warranty_system: 'Warranty System', + warranty_serials: 'Warranty Serials', }, }; export default en_lang diff --git a/webUI/src/i18n/fa_lang.ts b/webUI/src/i18n/fa_lang.ts index af7e8ee..5507a8b 100755 --- a/webUI/src/i18n/fa_lang.ts +++ b/webUI/src/i18n/fa_lang.ts @@ -197,6 +197,8 @@ const fa_lang = { inquiry: "استعلامات", hrm: 'منابع انسانی', hrm_docs: 'سند حقوق', + warranty_system: 'مدیریت گارانتی', + warranty_serials: 'سریال‌های گارانتی', buysellByPerson: "گزارش خرید و فروش های اشخاص", tax_system: "سامانه مودیان مالیاتی", tax_invoices: "صورتحساب‌ ها", diff --git a/webUI/src/router/index.ts b/webUI/src/router/index.ts index 0c1b629..0a0fba6 100755 --- a/webUI/src/router/index.ts +++ b/webUI/src/router/index.ts @@ -864,6 +864,16 @@ const router = createRouter({ component: () => import('../views/acc/plugins/onlinestore/intro.vue'), }, + { + path: 'plugins/warranty', + name: 'plugin_warranty', + component: () => + import('../views/acc/plugins/warranty/WarrantyPlugin.vue'), + meta: { + 'title': 'مدیریت گارانتی', + 'login': true + } + }, { path: 'notifications/list', name: 'notification_list', diff --git a/webUI/src/views/acc/App.vue b/webUI/src/views/acc/App.vue index cb496bd..9faf739 100755 --- a/webUI/src/views/acc/App.vue +++ b/webUI/src/views/acc/App.vue @@ -193,6 +193,7 @@ export default { { path: '/acc/plugin-center/invoice', key: '`', label: this.$t('drawer.plugins_invoices'), ctrl: true, shift: true, permission: () => this.permissions.owner }, { path: '/acc/hrm/docs/list', key: 'H', label: this.$t('drawer.hrm_docs'), ctrl: true, shift: true, permission: () => this.isPluginActive('hrm') && this.permissions.plugHrmDocs }, { path: '/acc/plugins/ghesta/list', key: 'G', label: this.$t('drawer.ghesta_invoices'), ctrl: true, shift: true, permission: () => this.isPluginActive('ghesta') && this.permissions.plugGhestaManager }, + { path: '/acc/plugins/warranty', key: 'W', label: this.$t('drawer.warranty_serials'), ctrl: true, shift: true, permission: () => this.isPluginActive('warranty') && this.permissions.plugWarranty }, { path: '/acc/plugins/tax/invoices/list', key: 'L', label: this.$t('drawer.tax_invoices'), ctrl: true, shift: true, permission: () => this.permissions.settings && this.isPluginActive('taxsettings') }, { path: '/acc/plugins/tax/settings', key: 'T', label: this.$t('drawer.tax_settings'), ctrl: true, shift: true, permission: () => this.permissions.settings && this.isPluginActive('taxsettings') }, ]; @@ -859,6 +860,26 @@ export default { + + + + + {{ $t('drawer.warranty_serials') }} + {{ getShortcutKey('/acc/plugins/warranty') }} + + + +