fix dubkucate codes in bank account
This commit is contained in:
parent
55cf1e5d6d
commit
8ead39e274
|
@ -61,6 +61,13 @@ services:
|
|||
tags:
|
||||
- { 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:
|
||||
arguments:
|
||||
$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)
|
||||
return $this->json(['result' => 3]);
|
||||
if ($code == 0) {
|
||||
// بررسی وجود حساب با نام یکسان
|
||||
$data = $entityManager->getRepository(BankAccount::class)->findOneBy([
|
||||
'name' => $params['name'],
|
||||
'bid' => $acc['bid']
|
||||
|
@ -147,8 +148,35 @@ class BankController extends AbstractController
|
|||
//check exist before
|
||||
if ($data)
|
||||
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->setCode($provider->getAccountingCode($request->headers->get('activeBid'), 'bank'));
|
||||
$data->setCode($newCode);
|
||||
$data->setMoney($acc['money']);
|
||||
} else {
|
||||
$data = $entityManager->getRepository(BankAccount::class)->findOneBy([
|
||||
|
|
|
@ -9,6 +9,7 @@ use Doctrine\ORM\Mapping as ORM;
|
|||
use Symfony\Component\Serializer\Annotation\Ignore;
|
||||
|
||||
#[ORM\Entity(repositoryClass: BankAccountRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class BankAccount
|
||||
{
|
||||
#[ORM\Id]
|
||||
|
@ -290,4 +291,31 @@ class BankAccount
|
|||
|
||||
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