123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- <?php
-
- namespace App\Concerns;
-
- use App\Enums\Accounting\JournalEntryType;
- use App\Utilities\Currency\CurrencyAccessor;
-
- trait HasJournalEntryActions
- {
- public int $debitAmount = 0;
-
- public int $creditAmount = 0;
-
- private function formatMoney(int $amount): string
- {
- return money($amount, CurrencyAccessor::getDefaultCurrency())->format();
- }
-
- /**
- * Expects formatted simple amount: e.g. 1,000.00 or 1.000,00
- *
- * Sets debit amount in cents as integer: e.g. 100000
- */
- public function setDebitAmount(int $amount): void
- {
- $this->debitAmount = $amount;
- }
-
- /**
- * Expects formatted simple amount: e.g. 1,000.00 or 1.000,00
- *
- * Sets credit amount in cents as integer: e.g. 100000
- */
- public function setCreditAmount(int $amount): void
- {
- $this->creditAmount = $amount;
- }
-
- /**
- * Returns debit amount in cents as integer: e.g. 100000
- */
- public function getDebitAmount(): int
- {
- return $this->debitAmount;
- }
-
- /**
- * Returns credit amount in cents as integer: e.g. 100000
- */
- public function getCreditAmount(): int
- {
- return $this->creditAmount;
- }
-
- /**
- * Expects debit amount in cents as string integer: e.g. 100000
- *
- * Returns formatted amount: e.g. $1,000.00 or €1.000,00
- */
- public function getFormattedDebitAmount(): string
- {
- return $this->formatMoney($this->getDebitAmount());
- }
-
- /**
- * Expects credit amount in cents as integer: e.g. 100000
- *
- * Returns formatted amount: e.g. $1,000.00 or €1.000,00
- */
- public function getFormattedCreditAmount(): string
- {
- return $this->formatMoney($this->getCreditAmount());
- }
-
- /**
- * Returns balance difference in cents as integer: e.g. 100000
- */
- public function getBalanceDifference(): int
- {
- return $this->getDebitAmount() - $this->getCreditAmount();
- }
-
- /**
- * Returns formatted balance difference: e.g. $1,000.00 or €1.000,00
- */
- public function getFormattedBalanceDifference(): string
- {
- $absoluteDifference = abs($this->getBalanceDifference());
-
- return $this->formatMoney($absoluteDifference);
- }
-
- /**
- * Returns boolean indicating whether the journal entry is balanced
- * using the debit and credit integer amounts
- */
- public function isJournalEntryBalanced(): bool
- {
- return $this->getDebitAmount() === $this->getCreditAmount();
- }
-
- /**
- * Resets debit and credit amounts to '0.00'
- */
- public function resetJournalEntryAmounts(): void
- {
- $this->reset(['debitAmount', 'creditAmount']);
- }
-
- public function adjustJournalEntryAmountsForTypeChange(JournalEntryType $newType, JournalEntryType $oldType, ?string $amount): void
- {
- if ($newType === $oldType) {
- return;
- }
-
- $amountComplete = $this->ensureCompleteDecimal($amount);
- $normalizedAmount = $this->convertAmountToCents($amountComplete);
-
- if ($normalizedAmount === 0) {
- return;
- }
-
- if ($oldType->isDebit() && $newType->isCredit()) {
- $this->debitAmount -= $normalizedAmount;
- $this->creditAmount += $normalizedAmount;
- } elseif ($oldType->isCredit() && $newType->isDebit()) {
- $this->debitAmount += $normalizedAmount;
- $this->creditAmount -= $normalizedAmount;
- }
- }
-
- /**
- * Expects the journal entry type,
- * the new amount and the old amount as formatted simple amounts: e.g. 1,000.00 or 1.000,00
- * It can expect the amounts as partial amounts: e.g. 1,000. or 1.000, (this needs to be handled by this method)
- */
- public function updateJournalEntryAmount(JournalEntryType $journalEntryType, ?string $newAmount, ?string $oldAmount): void
- {
- if ($newAmount === $oldAmount) {
- return;
- }
-
- $newAmountComplete = $this->ensureCompleteDecimal($newAmount);
- $oldAmountComplete = $this->ensureCompleteDecimal($oldAmount);
-
- $formattedNewAmount = $this->convertAmountToCents($newAmountComplete);
- $formattedOldAmount = $this->convertAmountToCents($oldAmountComplete);
-
- $difference = $formattedNewAmount - $formattedOldAmount;
-
- if ($journalEntryType->isDebit()) {
- $this->debitAmount += $difference;
- } else {
- $this->creditAmount += $difference;
- }
- }
-
- private function ensureCompleteDecimal(?string $amount): string
- {
- if ($amount === null) {
- return '0';
- }
-
- $currency = currency(CurrencyAccessor::getDefaultCurrency());
- $decimal = $currency->getDecimalMark();
-
- if (substr($amount, -1) === $decimal) {
- return '0';
- }
-
- return $amount;
- }
-
- /**
- * Expects formatted simple amount: e.g. 1,000.00 or 1.000,00
- *
- * Returns sanitized amount in cents as integer: e.g. 100000
- */
- protected function convertAmountToCents(string $amount): int
- {
- return money($amount, CurrencyAccessor::getDefaultCurrency(), true)->getAmount();
- }
- }
|