You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ChartOfAccountsService.php 4.0KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. <?php
  2. namespace App\Services;
  3. use App\Enums\Accounting\AccountType;
  4. use App\Enums\Banking\BankAccountType;
  5. use App\Models\Accounting\AccountSubtype;
  6. use App\Models\Banking\BankAccount;
  7. use App\Models\Company;
  8. use App\Utilities\Currency\CurrencyAccessor;
  9. use Exception;
  10. class ChartOfAccountsService
  11. {
  12. public function createChartOfAccounts(Company $company): void
  13. {
  14. $chartOfAccounts = config('chart-of-accounts.default');
  15. foreach ($chartOfAccounts as $type => $subtypes) {
  16. foreach ($subtypes as $subtypeName => $subtypeConfig) {
  17. $subtype = $company->accountSubtypes()
  18. ->createQuietly([
  19. 'multi_currency' => $subtypeConfig['multi_currency'] ?? false,
  20. 'inverse_cash_flow' => $subtypeConfig['inverse_cash_flow'] ?? false,
  21. 'category' => AccountType::from($type)->getCategory()->value,
  22. 'type' => $type,
  23. 'name' => $subtypeName,
  24. 'description' => $subtypeConfig['description'] ?? 'No description available.',
  25. ]);
  26. try {
  27. $this->createDefaultAccounts($company, $subtype, $subtypeConfig);
  28. } catch (Exception $e) {
  29. // Log the error
  30. logger()->alert('Failed to create a company with its defaults, blocking critical business functionality.', [
  31. 'error' => $e->getMessage(),
  32. 'userId' => $company->owner->id,
  33. 'companyId' => $company->id,
  34. ]);
  35. throw $e;
  36. }
  37. }
  38. }
  39. }
  40. private function createDefaultAccounts(Company $company, AccountSubtype $subtype, array $subtypeConfig): void
  41. {
  42. if (isset($subtypeConfig['accounts']) && is_array($subtypeConfig['accounts'])) {
  43. $baseCode = $subtypeConfig['base_code'];
  44. $defaultCurrencyCode = CurrencyAccessor::getDefaultCurrency();
  45. if (empty($defaultCurrencyCode)) {
  46. throw new Exception('No default currency available for creating accounts.');
  47. }
  48. foreach ($subtypeConfig['accounts'] as $accountName => $accountDetails) {
  49. // Create the Account without directly setting bank_account_id
  50. $account = $company->accounts()->createQuietly([
  51. 'subtype_id' => $subtype->id,
  52. 'category' => $subtype->type->getCategory()->value,
  53. 'type' => $subtype->type->value,
  54. 'code' => $baseCode++,
  55. 'name' => $accountName,
  56. 'currency_code' => $defaultCurrencyCode,
  57. 'description' => $accountDetails['description'] ?? 'No description available.',
  58. 'default' => true,
  59. 'created_by' => $company->owner->id,
  60. 'updated_by' => $company->owner->id,
  61. ]);
  62. // Check if we need to create a BankAccount for this Account
  63. if ($subtypeConfig['multi_currency'] && isset($subtypeConfig['bank_account_type'])) {
  64. $bankAccount = $this->createBankAccountForMultiCurrency($company, $subtypeConfig['bank_account_type']);
  65. // Associate the BankAccount with the Account
  66. $bankAccount->account()->associate($account);
  67. $bankAccount->saveQuietly();
  68. }
  69. }
  70. }
  71. }
  72. private function createBankAccountForMultiCurrency(Company $company, string $bankAccountType): BankAccount
  73. {
  74. $noDefaultBankAccount = $company->bankAccounts()->where('enabled', true)->doesntExist();
  75. return $company->bankAccounts()->createQuietly([
  76. 'type' => BankAccountType::from($bankAccountType) ?? BankAccountType::Other,
  77. 'enabled' => $noDefaultBankAccount,
  78. 'created_by' => $company->owner->id,
  79. 'updated_by' => $company->owner->id,
  80. ]);
  81. }
  82. }