Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

HasJournalEntryActions.php 5.9KB

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