109 lines
4.3 KiB
PHP
109 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace App\Billing\Command;
|
|
|
|
use App\Billing\Entity\Invoice;
|
|
use App\Billing\Repository\InvoiceRepository;
|
|
use App\Billing\Service\InvoiceService;
|
|
use App\Patient\Repository\PatientSessionRepository;
|
|
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\Input\InputOption;
|
|
use Symfony\Component\Console\Output\OutputInterface;
|
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
|
|
|
/**
|
|
* صورتحسابهایی که با مراجعهٔ خودشان همتراز نیستند را دوباره میسازد.
|
|
*
|
|
* صورتحساب عکسِ لحظهٔ ساخت بود و ویرایشِ بعدیِ مراجعه به آن نمیرسید؛ نتیجهاش
|
|
* صورتحسابی با مبلغِ قدیمی بود که چون پرداختیها از آن بیشتر بودند «پرداختشده» دیده
|
|
* میشد، و آمار فهرست پرداختها (مجموع/تسویهنشده) هم از همان ستونها غلط درمیآمد.
|
|
* از این پس هر ویرایشِ مراجعه صورتحسابش را همتراز میکند؛ این دستور فقط برای جبرانِ
|
|
* انحرافِ گذشته است.
|
|
*
|
|
* ddev exec php bin/console app:billing:resync-invoices --dry-run
|
|
*/
|
|
#[AsCommand(
|
|
name: 'app:billing:resync-invoices',
|
|
description: 'Rebuild invoices whose totals drifted from their patient session',
|
|
)]
|
|
class ResyncSessionInvoicesCommand extends Command
|
|
{
|
|
public function __construct(
|
|
private readonly InvoiceRepository $invoiceRepo,
|
|
private readonly PatientSessionRepository $sessionRepo,
|
|
private readonly InvoiceService $invoiceService,
|
|
private readonly EntityManagerInterface $em,
|
|
) {
|
|
parent::__construct();
|
|
}
|
|
|
|
protected function configure(): void
|
|
{
|
|
$this->addOption('dry-run', null, InputOption::VALUE_NONE, 'فقط گزارش بده، چیزی ننویس');
|
|
}
|
|
|
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
|
{
|
|
$io = new SymfonyStyle($input, $output);
|
|
$dryRun = (bool) $input->getOption('dry-run');
|
|
|
|
$drifted = 0;
|
|
$rows = [];
|
|
|
|
foreach ($this->invoiceRepo->findAll() as $invoice) {
|
|
if ($invoice->getStatus() === Invoice::STATUS_VOID || $invoice->getPatientSessionId() === null) {
|
|
continue;
|
|
}
|
|
|
|
$session = $this->sessionRepo->find($invoice->getPatientSessionId());
|
|
if ($session === null) {
|
|
continue;
|
|
}
|
|
|
|
$before = $invoice->getTotalRials();
|
|
// مبلغِ درست از خودِ منطقِ ساخت میآید، نه از یک محاسبهٔ موازی در این دستور.
|
|
$after = $dryRun
|
|
? $this->previewTotal($session, $invoice)
|
|
: $this->invoiceService->syncFromSession($session, $invoice->getEntityType(), $invoice->getEntityId())?->getTotalRials() ?? $before;
|
|
|
|
if ($before === $after) {
|
|
continue;
|
|
}
|
|
|
|
$drifted++;
|
|
$rows[] = [$invoice->getUuid(), $before, $after];
|
|
}
|
|
|
|
if ($rows !== []) {
|
|
$io->table(['invoice', 'before (rials)', 'after (rials)'], $rows);
|
|
}
|
|
|
|
$io->success(sprintf(
|
|
$dryRun ? '%d صورتحساب منحرف است (چیزی نوشته نشد)' : '%d صورتحساب همتراز شد',
|
|
$drifted,
|
|
));
|
|
|
|
return Command::SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* مبلغِ درستِ همین صورتحساب بدون ذخیره — برای `--dry-run`.
|
|
* روی همان entity کار میکند و در پایان چیزی flush نمیشود.
|
|
*/
|
|
private function previewTotal(\App\Patient\Entity\PatientSession $session, Invoice $invoice): int
|
|
{
|
|
$this->em->beginTransaction();
|
|
|
|
try {
|
|
$synced = $this->invoiceService->syncFromSession($session, $invoice->getEntityType(), $invoice->getEntityId());
|
|
|
|
return $synced?->getTotalRials() ?? $invoice->getTotalRials();
|
|
} finally {
|
|
$this->em->rollback();
|
|
}
|
|
}
|
|
}
|