Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

HasJournalEntryActions.php 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <?php
  2. namespace App\Concerns;
  3. use App\Enums\Accounting\JournalEntryType;
  4. use App\Utilities\Currency\CurrencyAccessor;
  5. trait HasJournalEntryActions
  6. {
  7. public int $debitAmount = 0;
  8. public int $creditAmount = 0;
  9. private function formatMoney(int $amount): string
  10. {
  11. return money($amount, CurrencyAccessor::getDefaultCurrency())->format();
  12. }
  13. /**
  14. * Expects formatted simple amount: e.g. 1,000.00 or 1.000,00
  15. *
  16. * Sets debit amount in cents as integer: e.g. 100000
  17. */
  18. public function setDebitAmount(int $amount): void
  19. {
  20. $this->debitAmount = $amount;
  21. }
  22. /**
  23. * Expects formatted simple amount: e.g. 1,000.00 or 1.000,00
  24. *
  25. * Sets credit amount in cents as integer: e.g. 100000
  26. */
  27. public function setCreditAmount(int $amount): void
  28. {
  29. $this->creditAmount = $amount;
  30. }
  31. /**
  32. * Returns debit amount in cents as integer: e.g. 100000
  33. */
  34. public function getDebitAmount(): int
  35. {
  36. return $this->debitAmount;
  37. }
  38. /**
  39. * Returns credit amount in cents as integer: e.g. 100000
  40. */
  41. public function getCreditAmount(): int
  42. {
  43. return $this->creditAmount;
  44. }
  45. /**
  46. * Expects debit amount in cents as string integer: e.g. 100000
  47. *
  48. * Returns formatted amount: e.g. $1,000.00 or €1.000,00
  49. */
  50. public function getFormattedDebitAmount(): string
  51. {
  52. return $this->formatMoney($this->getDebitAmount());
  53. }
  54. /**
  55. * Expects credit amount in cents as integer: e.g. 100000
  56. *
  57. * Returns formatted amount: e.g. $1,000.00 or €1.000,00
  58. */
  59. public function getFormattedCreditAmount(): string
  60. {
  61. return $this->formatMoney($this->getCreditAmount());
  62. }
  63. /**
  64. * Returns balance difference in cents as integer: e.g. 100000
  65. */
  66. public function getBalanceDifference(): int
  67. {
  68. return $this->getDebitAmount() - $this->getCreditAmount();
  69. }
  70. /**
  71. * Returns formatted balance difference: e.g. $1,000.00 or €1.000,00
  72. */
  73. public function getFormattedBalanceDifference(): string
  74. {
  75. $absoluteDifference = abs($this->getBalanceDifference());
  76. return $this->formatMoney($absoluteDifference);
  77. }
  78. /**
  79. * Returns boolean indicating whether the journal entry is balanced
  80. * using the debit and credit integer amounts
  81. */
  82. public function isJournalEntryBalanced(): bool
  83. {
  84. return $this->getDebitAmount() === $this->getCreditAmount();
  85. }
  86. /**
  87. * Resets debit and credit amounts to '0.00'
  88. */
  89. public function resetJournalEntryAmounts(): void
  90. {
  91. $this->reset(['debitAmount', 'creditAmount']);
  92. }
  93. public function adjustJournalEntryAmountsForTypeChange(JournalEntryType $newType, JournalEntryType $oldType, ?string $amount): void
  94. {
  95. if ($newType === $oldType) {
  96. return;
  97. }
  98. $amountComplete = $this->ensureCompleteDecimal($amount);
  99. $normalizedAmount = $this->convertAmountToCents($amountComplete);
  100. if ($normalizedAmount === 0) {
  101. return;
  102. }
  103. if ($oldType->isDebit() && $newType->isCredit()) {
  104. $this->debitAmount -= $normalizedAmount;
  105. $this->creditAmount += $normalizedAmount;
  106. } elseif ($oldType->isCredit() && $newType->isDebit()) {
  107. $this->debitAmount += $normalizedAmount;
  108. $this->creditAmount -= $normalizedAmount;
  109. }
  110. }
  111. /**
  112. * Expects the journal entry type,
  113. * the new amount and the old amount as formatted simple amounts: e.g. 1,000.00 or 1.000,00
  114. * It can expect the amounts as partial amounts: e.g. 1,000. or 1.000, (this needs to be handled by this method)
  115. */
  116. public function updateJournalEntryAmount(JournalEntryType $journalEntryType, ?string $newAmount, ?string $oldAmount): void
  117. {
  118. if ($newAmount === $oldAmount) {
  119. return;
  120. }
  121. $newAmountComplete = $this->ensureCompleteDecimal($newAmount);
  122. $oldAmountComplete = $this->ensureCompleteDecimal($oldAmount);
  123. $formattedNewAmount = $this->convertAmountToCents($newAmountComplete);
  124. $formattedOldAmount = $this->convertAmountToCents($oldAmountComplete);
  125. $difference = $formattedNewAmount - $formattedOldAmount;
  126. if ($journalEntryType->isDebit()) {
  127. $this->debitAmount += $difference;
  128. } else {
  129. $this->creditAmount += $difference;
  130. }
  131. }
  132. private function ensureCompleteDecimal(?string $amount): string
  133. {
  134. if ($amount === null) {
  135. return '0';
  136. }
  137. $currency = currency(CurrencyAccessor::getDefaultCurrency());
  138. $decimal = $currency->getDecimalMark();
  139. if (substr($amount, -1) === $decimal) {
  140. return '0';
  141. }
  142. return $amount;
  143. }
  144. /**
  145. * Expects formatted simple amount: e.g. 1,000.00 or 1.000,00
  146. *
  147. * Returns sanitized amount in cents as integer: e.g. 100000
  148. */
  149. protected function convertAmountToCents(string $amount): int
  150. {
  151. return money($amount, CurrencyAccessor::getDefaultCurrency(), true)->getAmount();
  152. }
  153. }