fix dubkucate codes in bank account
This commit is contained in:
parent
55cf1e5d6d
commit
8ead39e274
|
@ -61,6 +61,13 @@ services:
|
||||||
tags:
|
tags:
|
||||||
- { name: kernel.event_listener, event: kernel.exception }
|
- { name: kernel.event_listener, event: kernel.exception }
|
||||||
|
|
||||||
|
App\EventListener\BankAccountListener:
|
||||||
|
arguments:
|
||||||
|
$bankAccountService: '@App\Service\BankAccountService'
|
||||||
|
$entityManager: '@doctrine.orm.default_entity_manager'
|
||||||
|
tags:
|
||||||
|
- { name: doctrine.event_listener, event: postLoad, priority: 100 }
|
||||||
|
|
||||||
App\Security\AuthenticationFailureHandler:
|
App\Security\AuthenticationFailureHandler:
|
||||||
arguments:
|
arguments:
|
||||||
$captchaService: '@App\Service\CaptchaService'
|
$captchaService: '@App\Service\CaptchaService'
|
||||||
|
|
87
hesabixCore/src/Command/FixBankDuplicateCodesCommand.php
Normal file
87
hesabixCore/src/Command/FixBankDuplicateCodesCommand.php
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Entity\Business;
|
||||||
|
use App\Service\BankAccountService;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
#[AsCommand(
|
||||||
|
name: 'app:fix-bank-duplicate-codes',
|
||||||
|
description: 'اصلاح کدهای تکراری حسابهای بانکی در تمام کسب و کارها'
|
||||||
|
)]
|
||||||
|
class FixBankDuplicateCodesCommand extends Command
|
||||||
|
{
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
private BankAccountService $bankAccountService;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $entityManager, BankAccountService $bankAccountService)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->bankAccountService = $bankAccountService;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
|
||||||
|
$io->title('اصلاح کدهای تکراری حسابهای بانکی');
|
||||||
|
|
||||||
|
// دریافت تمام کسب و کارها
|
||||||
|
$businesses = $this->entityManager->getRepository(Business::class)->findAll();
|
||||||
|
|
||||||
|
$totalFixed = 0;
|
||||||
|
$totalErrors = 0;
|
||||||
|
|
||||||
|
foreach ($businesses as $business) {
|
||||||
|
$io->section("بررسی کسب و کار: {$business->getName()} (ID: {$business->getId()})");
|
||||||
|
|
||||||
|
// بررسی کدهای تکراری
|
||||||
|
$duplicates = $this->bankAccountService->checkDuplicateCodes($business);
|
||||||
|
|
||||||
|
if (empty($duplicates)) {
|
||||||
|
$io->info('هیچ کد تکراری یافت نشد');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->warning("تعداد کدهای تکراری یافت شده: " . count($duplicates));
|
||||||
|
|
||||||
|
foreach ($duplicates as $duplicate) {
|
||||||
|
$io->text("کد تکراری: {$duplicate['code']} - تعداد: {$duplicate['count']}");
|
||||||
|
foreach ($duplicate['accounts'] as $account) {
|
||||||
|
$io->text(" - حساب: {$account['name']} (ID: {$account['id']})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// اصلاح کدهای تکراری
|
||||||
|
$fixResult = $this->bankAccountService->fixDuplicateCodes($business);
|
||||||
|
|
||||||
|
if ($fixResult['success']) {
|
||||||
|
$io->success("تعداد اصلاح شده: {$fixResult['fixed_count']}");
|
||||||
|
$totalFixed += $fixResult['fixed_count'];
|
||||||
|
} else {
|
||||||
|
$io->error("خطا در اصلاح کدهای تکراری:");
|
||||||
|
foreach ($fixResult['errors'] as $error) {
|
||||||
|
$io->text(" - {$error}");
|
||||||
|
}
|
||||||
|
$totalErrors += count($fixResult['errors']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->newLine();
|
||||||
|
$io->title('نتیجه نهایی');
|
||||||
|
$io->success("کل تعداد اصلاح شده: {$totalFixed}");
|
||||||
|
|
||||||
|
if ($totalErrors > 0) {
|
||||||
|
$io->error("کل تعداد خطاها: {$totalErrors}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
|
@ -140,6 +140,7 @@ class BankController extends AbstractController
|
||||||
if (count_chars(trim($params['name'])) == 0)
|
if (count_chars(trim($params['name'])) == 0)
|
||||||
return $this->json(['result' => 3]);
|
return $this->json(['result' => 3]);
|
||||||
if ($code == 0) {
|
if ($code == 0) {
|
||||||
|
// بررسی وجود حساب با نام یکسان
|
||||||
$data = $entityManager->getRepository(BankAccount::class)->findOneBy([
|
$data = $entityManager->getRepository(BankAccount::class)->findOneBy([
|
||||||
'name' => $params['name'],
|
'name' => $params['name'],
|
||||||
'bid' => $acc['bid']
|
'bid' => $acc['bid']
|
||||||
|
@ -147,8 +148,35 @@ class BankController extends AbstractController
|
||||||
//check exist before
|
//check exist before
|
||||||
if ($data)
|
if ($data)
|
||||||
return $this->json(['result' => 2]);
|
return $this->json(['result' => 2]);
|
||||||
|
|
||||||
|
// تولید کد یکتا
|
||||||
|
$newCode = $provider->getAccountingCode($request->headers->get('activeBid'), 'bank');
|
||||||
|
|
||||||
|
// بررسی وجود حساب با کد یکسان در همان کسب و کار
|
||||||
|
$existingBankWithCode = $entityManager->getRepository(BankAccount::class)->findOneBy([
|
||||||
|
'code' => $newCode,
|
||||||
|
'bid' => $acc['bid']
|
||||||
|
]);
|
||||||
|
|
||||||
|
// اگر کد تکراری باشد، کد جدید تولید میکنیم
|
||||||
|
if ($existingBankWithCode) {
|
||||||
|
// تولید کد جدید
|
||||||
|
$newCode = $provider->getAccountingCode($request->headers->get('activeBid'), 'bank');
|
||||||
|
|
||||||
|
// بررسی مجدد
|
||||||
|
$existingBankWithCode = $entityManager->getRepository(BankAccount::class)->findOneBy([
|
||||||
|
'code' => $newCode,
|
||||||
|
'bid' => $acc['bid']
|
||||||
|
]);
|
||||||
|
|
||||||
|
// اگر هنوز تکراری باشد، خطا برگردان
|
||||||
|
if ($existingBankWithCode) {
|
||||||
|
return $this->json(['result' => 4, 'message' => 'خطا در تولید کد یکتا برای حساب بانکی']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$data = new BankAccount();
|
$data = new BankAccount();
|
||||||
$data->setCode($provider->getAccountingCode($request->headers->get('activeBid'), 'bank'));
|
$data->setCode($newCode);
|
||||||
$data->setMoney($acc['money']);
|
$data->setMoney($acc['money']);
|
||||||
} else {
|
} else {
|
||||||
$data = $entityManager->getRepository(BankAccount::class)->findOneBy([
|
$data = $entityManager->getRepository(BankAccount::class)->findOneBy([
|
||||||
|
|
|
@ -9,6 +9,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Serializer\Annotation\Ignore;
|
use Symfony\Component\Serializer\Annotation\Ignore;
|
||||||
|
|
||||||
#[ORM\Entity(repositoryClass: BankAccountRepository::class)]
|
#[ORM\Entity(repositoryClass: BankAccountRepository::class)]
|
||||||
|
#[ORM\HasLifecycleCallbacks]
|
||||||
class BankAccount
|
class BankAccount
|
||||||
{
|
{
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
|
@ -290,4 +291,31 @@ class BankAccount
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* قبل از ذخیره حساب بانکی
|
||||||
|
*/
|
||||||
|
#[ORM\PrePersist]
|
||||||
|
public function prePersist(): void
|
||||||
|
{
|
||||||
|
// این متد توسط Event Listener فراخوانی میشود
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* قبل از بهروزرسانی حساب بانکی
|
||||||
|
*/
|
||||||
|
#[ORM\PreUpdate]
|
||||||
|
public function preUpdate(): void
|
||||||
|
{
|
||||||
|
// این متد توسط Event Listener فراخوانی میشود
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* بعد از بارگذاری حساب بانکی
|
||||||
|
*/
|
||||||
|
#[ORM\PostLoad]
|
||||||
|
public function postLoad(): void
|
||||||
|
{
|
||||||
|
// این متد توسط Event Listener فراخوانی میشود
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
75
hesabixCore/src/EventListener/BankAccountListener.php
Normal file
75
hesabixCore/src/EventListener/BankAccountListener.php
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\EventListener;
|
||||||
|
|
||||||
|
use App\Entity\BankAccount;
|
||||||
|
use App\Service\BankAccountService;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\Event\PostLoadEventArgs;
|
||||||
|
|
||||||
|
class BankAccountListener
|
||||||
|
{
|
||||||
|
private BankAccountService $bankAccountService;
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
private static array $processedBusinesses = [];
|
||||||
|
|
||||||
|
public function __construct(BankAccountService $bankAccountService, EntityManagerInterface $entityManager)
|
||||||
|
{
|
||||||
|
$this->bankAccountService = $bankAccountService;
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* بعد از بارگذاری حساب بانکی
|
||||||
|
*/
|
||||||
|
public function postLoad(PostLoadEventArgs $event): void
|
||||||
|
{
|
||||||
|
$entity = $event->getObject();
|
||||||
|
if ($entity instanceof BankAccount && $entity->getBid()) {
|
||||||
|
$this->fixDuplicateCodesInBusiness($entity->getBid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* بررسی و اصلاح کدهای تکراری در یک کسب و کار
|
||||||
|
*/
|
||||||
|
private function fixDuplicateCodesInBusiness($business): void
|
||||||
|
{
|
||||||
|
$businessId = $business->getId();
|
||||||
|
|
||||||
|
// اگر این کسب و کار قبلاً پردازش شده، از پردازش مجدد جلوگیری کنیم
|
||||||
|
if (isset(self::$processedBusinesses[$businessId])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// بررسی کدهای تکراری
|
||||||
|
$duplicates = $this->bankAccountService->checkDuplicateCodes($business);
|
||||||
|
|
||||||
|
if (!empty($duplicates)) {
|
||||||
|
// اصلاح کدهای تکراری
|
||||||
|
$fixResult = $this->bankAccountService->fixDuplicateCodes($business);
|
||||||
|
|
||||||
|
if ($fixResult['success'] && $fixResult['fixed_count'] > 0) {
|
||||||
|
// اگر تغییراتی اعمال شده، EntityManager را flush کنیم
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// علامتگذاری که این کسب و کار پردازش شده است
|
||||||
|
self::$processedBusinesses[$businessId] = true;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// در صورت خطا، فقط log کنیم و ادامه دهیم
|
||||||
|
error_log("خطا در بررسی کدهای تکراری حساب بانکی: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* پاک کردن cache پردازش شدهها
|
||||||
|
*/
|
||||||
|
public static function clearProcessedCache(): void
|
||||||
|
{
|
||||||
|
self::$processedBusinesses = [];
|
||||||
|
}
|
||||||
|
}
|
150
hesabixCore/src/Service/BankAccountService.php
Normal file
150
hesabixCore/src/Service/BankAccountService.php
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\BankAccount;
|
||||||
|
use App\Entity\Business;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
class BankAccountService
|
||||||
|
{
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
private Provider $provider;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $entityManager, Provider $provider)
|
||||||
|
{
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->provider = $provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* بررسی و اصلاح کدهای تکراری حسابهای بانکی در یک کسب و کار
|
||||||
|
* @param Business $business
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function fixDuplicateCodes(Business $business): array
|
||||||
|
{
|
||||||
|
$fixedCount = 0;
|
||||||
|
$errors = [];
|
||||||
|
$maxAttempts = 10; // حداکثر تعداد تلاش برای حل کدهای تکراری متوالی
|
||||||
|
|
||||||
|
for ($attempt = 0; $attempt < $maxAttempts; $attempt++) {
|
||||||
|
// دریافت تمام حسابهای بانکی این کسب و کار
|
||||||
|
$bankAccounts = $this->entityManager->getRepository(BankAccount::class)->findBy([
|
||||||
|
'bid' => $business
|
||||||
|
]);
|
||||||
|
|
||||||
|
// گروهبندی بر اساس کد
|
||||||
|
$codeGroups = [];
|
||||||
|
foreach ($bankAccounts as $bankAccount) {
|
||||||
|
$code = $bankAccount->getCode();
|
||||||
|
if (!isset($codeGroups[$code])) {
|
||||||
|
$codeGroups[$code] = [];
|
||||||
|
}
|
||||||
|
$codeGroups[$code][] = $bankAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hasDuplicates = false;
|
||||||
|
|
||||||
|
// بررسی کدهای تکراری و اصلاح آنها
|
||||||
|
foreach ($codeGroups as $code => $accounts) {
|
||||||
|
if (count($accounts) > 1) {
|
||||||
|
$hasDuplicates = true;
|
||||||
|
// کد تکراری پیدا شده، اصلاح میکنیم
|
||||||
|
for ($i = 1; $i < count($accounts); $i++) {
|
||||||
|
$account = $accounts[$i];
|
||||||
|
|
||||||
|
// تولید کد جدید
|
||||||
|
$newCode = $this->provider->getAccountingCode($business->getId(), 'bank');
|
||||||
|
|
||||||
|
// بررسی اینکه کد جدید تکراری نباشد
|
||||||
|
$existingAccount = $this->entityManager->getRepository(BankAccount::class)->findOneBy([
|
||||||
|
'code' => $newCode,
|
||||||
|
'bid' => $business
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($existingAccount) {
|
||||||
|
// اگر کد جدید هم تکراری باشد، یک بار دیگر تلاش میکنیم
|
||||||
|
$newCode = $this->provider->getAccountingCode($business->getId(), 'bank');
|
||||||
|
|
||||||
|
$existingAccount = $this->entityManager->getRepository(BankAccount::class)->findOneBy([
|
||||||
|
'code' => $newCode,
|
||||||
|
'bid' => $business
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($existingAccount) {
|
||||||
|
$errors[] = "نمیتوان کد یکتا برای حساب بانکی {$account->getName()} تولید کرد";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// تنظیم کد جدید
|
||||||
|
$account->setCode($newCode);
|
||||||
|
$this->entityManager->persist($account);
|
||||||
|
$fixedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// اگر هیچ کد تکراری وجود نداشت، حلقه را متوقف کنیم
|
||||||
|
if (!$hasDuplicates) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ذخیره تغییرات
|
||||||
|
if ($fixedCount > 0) {
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'fixed_count' => $fixedCount,
|
||||||
|
'errors' => $errors,
|
||||||
|
'success' => count($errors) === 0,
|
||||||
|
'attempts' => $attempt + 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* بررسی وجود کدهای تکراری در یک کسب و کار
|
||||||
|
* @param Business $business
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function checkDuplicateCodes(Business $business): array
|
||||||
|
{
|
||||||
|
$duplicates = [];
|
||||||
|
|
||||||
|
// دریافت تمام حسابهای بانکی این کسب و کار
|
||||||
|
$bankAccounts = $this->entityManager->getRepository(BankAccount::class)->findBy([
|
||||||
|
'bid' => $business
|
||||||
|
]);
|
||||||
|
|
||||||
|
// گروهبندی بر اساس کد
|
||||||
|
$codeGroups = [];
|
||||||
|
foreach ($bankAccounts as $bankAccount) {
|
||||||
|
$code = $bankAccount->getCode();
|
||||||
|
if (!isset($codeGroups[$code])) {
|
||||||
|
$codeGroups[$code] = [];
|
||||||
|
}
|
||||||
|
$codeGroups[$code][] = $bankAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// بررسی کدهای تکراری
|
||||||
|
foreach ($codeGroups as $code => $accounts) {
|
||||||
|
if (count($accounts) > 1) {
|
||||||
|
$duplicates[] = [
|
||||||
|
'code' => $code,
|
||||||
|
'count' => count($accounts),
|
||||||
|
'accounts' => array_map(function($account) {
|
||||||
|
return [
|
||||||
|
'id' => $account->getId(),
|
||||||
|
'name' => $account->getName()
|
||||||
|
];
|
||||||
|
}, $accounts)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $duplicates;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue