feat: Implement financial engine for commission and tax calculations
- Added new configuration keys for appointment and upgrade commissions, tax settings, and SMS panel fee in SiteConfigController and SiteConfigRepository. - Introduced CommissionService to handle commission calculations for appointments and subscriptions, including tax deductions and SMS fees. - Created FinancialBreakdown entity and repository to log financial transactions. - Updated PaymentController to process commissions upon successful payments for appointments and subscriptions. - Developed FinancialReportPage in the admin panel to display financial breakdowns and summaries. - Added database migration for the new financial_breakdowns table.
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace App\Settlement\Entity;
|
||||
|
||||
use App\Auth\Entity\User;
|
||||
use App\Payment\Entity\Payment;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'financial_breakdowns')]
|
||||
#[ORM\Index(columns: ['representation_id', 'created_at'], name: 'idx_breakdown_rep_date')]
|
||||
#[ORM\Index(columns: ['source', 'created_at'], name: 'idx_breakdown_source_date')]
|
||||
class FinancialBreakdown
|
||||
{
|
||||
public const SOURCE_APPOINTMENT = 'appointment';
|
||||
public const SOURCE_SUBSCRIPTION = 'subscription';
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 36, unique: true)]
|
||||
private string $uuid;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Payment::class)]
|
||||
#[ORM\JoinColumn(name: 'payment_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
|
||||
private Payment $payment;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 20)]
|
||||
private string $source;
|
||||
|
||||
#[ORM\Column(name: 'gross_rials', type: 'integer')]
|
||||
private int $grossRials;
|
||||
|
||||
#[ORM\Column(name: 'sms_fee_rials', type: 'integer')]
|
||||
private int $smsFeeRials;
|
||||
|
||||
#[ORM\Column(name: 'tax_percent', type: 'decimal', precision: 5, scale: 2)]
|
||||
private string $taxPercent;
|
||||
|
||||
#[ORM\Column(name: 'tax_rials', type: 'integer')]
|
||||
private int $taxRials;
|
||||
|
||||
#[ORM\Column(name: 'net_after_tax_rials', type: 'integer')]
|
||||
private int $netAfterTaxRials;
|
||||
|
||||
#[ORM\Column(name: 'commission_percent', type: 'decimal', precision: 5, scale: 2)]
|
||||
private string $commissionPercent;
|
||||
|
||||
#[ORM\Column(name: 'representation_share_rials', type: 'integer')]
|
||||
private int $representationShareRials;
|
||||
|
||||
#[ORM\Column(name: 'system_share_rials', type: 'integer')]
|
||||
private int $systemShareRials;
|
||||
|
||||
#[ORM\Column(name: 'representation_id', type: 'integer', nullable: true)]
|
||||
private ?int $representationId = null;
|
||||
|
||||
#[ORM\Column(name: 'doctor_id', type: 'integer', nullable: true)]
|
||||
private ?int $doctorId = null;
|
||||
|
||||
#[ORM\Column(name: 'clinic_id', type: 'integer', nullable: true)]
|
||||
private ?int $clinicId = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: User::class)]
|
||||
#[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: false, onDelete: 'RESTRICT')]
|
||||
private User $user;
|
||||
|
||||
#[ORM\Column(name: 'created_at', type: 'integer')]
|
||||
private int $createdAt;
|
||||
|
||||
public function __construct(
|
||||
Payment $payment,
|
||||
string $source,
|
||||
User $user,
|
||||
int $grossRials,
|
||||
int $smsFeeRials,
|
||||
string $taxPercent,
|
||||
int $taxRials,
|
||||
int $netAfterTaxRials,
|
||||
string $commissionPercent,
|
||||
int $representationShareRials,
|
||||
int $systemShareRials,
|
||||
?int $representationId,
|
||||
?int $doctorId,
|
||||
?int $clinicId,
|
||||
) {
|
||||
$this->uuid = Uuid::v4()->toRfc4122();
|
||||
$this->payment = $payment;
|
||||
$this->source = $source;
|
||||
$this->user = $user;
|
||||
$this->grossRials = $grossRials;
|
||||
$this->smsFeeRials = $smsFeeRials;
|
||||
$this->taxPercent = $taxPercent;
|
||||
$this->taxRials = $taxRials;
|
||||
$this->netAfterTaxRials = $netAfterTaxRials;
|
||||
$this->commissionPercent = $commissionPercent;
|
||||
$this->representationShareRials = $representationShareRials;
|
||||
$this->systemShareRials = $systemShareRials;
|
||||
$this->representationId = $representationId;
|
||||
$this->doctorId = $doctorId;
|
||||
$this->clinicId = $clinicId;
|
||||
$this->createdAt = time();
|
||||
}
|
||||
|
||||
public function getId(): ?int { return $this->id; }
|
||||
public function getUuid(): string { return $this->uuid; }
|
||||
public function getPayment(): Payment { return $this->payment; }
|
||||
public function getSource(): string { return $this->source; }
|
||||
public function getRepresentationId(): ?int { return $this->representationId; }
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'uuid' => $this->uuid,
|
||||
'payment_uuid' => $this->payment->getUuid(),
|
||||
'order_id' => $this->payment->getOrderId(),
|
||||
'source' => $this->source,
|
||||
'gross_rials' => $this->grossRials,
|
||||
'sms_fee_rials' => $this->smsFeeRials,
|
||||
'tax_percent' => $this->taxPercent,
|
||||
'tax_rials' => $this->taxRials,
|
||||
'net_after_tax_rials' => $this->netAfterTaxRials,
|
||||
'commission_percent' => $this->commissionPercent,
|
||||
'representation_share_rials' => $this->representationShareRials,
|
||||
'system_share_rials' => $this->systemShareRials,
|
||||
'representation_id' => $this->representationId,
|
||||
'doctor_id' => $this->doctorId,
|
||||
'clinic_id' => $this->clinicId,
|
||||
'created_at' => $this->createdAt,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user