feat: Add online share functionality for secretaries

- Introduced `online_share_enabled` and `online_share_percent` fields in the `doctor_secretaries` table to manage secretary shares from online appointments.
- Added `bank_account` field in the `profiles` table to store user-level IBANs for settlements.
- Created `secretary_earnings` table to track earnings per secretary from online appointments, including a foreign key relationship with `financial_breakdowns`.
- Implemented `SecretaryEarning` entity and repository for managing secretary earnings.
- Developed `SecretaryShareResolver` service to determine which secretaries earn from online payments.
- Added `UserIbanResolver` service to handle user IBAN retrieval and management.
- Created `HasIbansTrait` for entities to manage IBANs in a JSON format.
- Implemented tests for secretary earnings and API endpoints for managing secretary shares and IBANs.
This commit is contained in:
hamed
2026-07-25 18:34:18 +03:30
parent 73a608c3dd
commit 8d2b0d908a
33 changed files with 2564 additions and 76 deletions
+3 -47
View File
@@ -8,12 +8,15 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Representation\Repository\RepresentationRepository;
use App\Shared\Entity\HasIbansTrait;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: RepresentationRepository::class)]
#[ORM\Table(name: 'representations')]
class Representation
{
use HasIbansTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
@@ -124,53 +127,6 @@ class Representation
public function setBankAccount(?array $v): self { $this->bankAccount = $v; $this->touch(); return $this; }
public function setActive(bool $v): self { $this->active = $v; $this->touch(); return $this; }
/** @return array<int,array<string,mixed>> */
public function getIbans(): array { return $this->bankAccount ?? []; }
/**
* افزودن یک شبا (حداکثر ۲). id خودکار تولید می‌شود.
* @param array{iban:string,bank_name:?string,owner_name:?string,verified?:bool} $iban
*/
public function addIban(array $iban): self
{
$ibans = $this->getIbans();
if (count($ibans) >= 2) {
throw new \DomainException('iban_limit');
}
$ibans[] = [
'id' => Uuid::v4()->toRfc4122(),
'iban' => $iban['iban'],
'bank_name' => $iban['bank_name'] ?? null,
'owner_name' => $iban['owner_name'] ?? null,
'verified' => $iban['verified'] ?? false,
'created_at' => time(),
];
$this->bankAccount = $ibans;
$this->touch();
return $this;
}
public function removeIban(string $id): self
{
$this->bankAccount = array_values(array_filter(
$this->getIbans(),
fn(array $i) => ($i['id'] ?? null) !== $id
));
$this->touch();
return $this;
}
/** @return array<string,mixed>|null یک شبای تأییدشده با این id */
public function findVerifiedIban(string $id): ?array
{
foreach ($this->getIbans() as $iban) {
if (($iban['id'] ?? null) === $id && ($iban['verified'] ?? false)) {
return $iban;
}
}
return null;
}
private function touch(): void { $this->updatedAt = time(); }
public function toArray(): array