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.

CashFlowStatementReportTransformer.php 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?php
  2. namespace App\Transformers;
  3. use App\DTO\AccountDTO;
  4. use App\DTO\ReportCategoryDTO;
  5. use App\DTO\ReportDTO;
  6. use App\DTO\ReportTypeDTO;
  7. use App\Utilities\Currency\CurrencyAccessor;
  8. class CashFlowStatementReportTransformer extends SummaryReportTransformer
  9. {
  10. protected string $totalOperatingActivities;
  11. protected string $totalInvestingActivities;
  12. protected string $totalFinancingActivities;
  13. protected string $grossCashInflow;
  14. protected string $grossCashOutflow;
  15. public function __construct(ReportDTO $report)
  16. {
  17. parent::__construct($report);
  18. $this->calculateTotals();
  19. }
  20. public function getTitle(): string
  21. {
  22. return 'Cash Flow Statement';
  23. }
  24. public function calculateTotals(): void
  25. {
  26. $cashInflow = 0;
  27. $cashOutflow = 0;
  28. foreach ($this->report->categories as $categoryName => $category) {
  29. $netMovement = (float) money($category->summary->netMovement, CurrencyAccessor::getDefaultCurrency())->getAmount();
  30. match ($categoryName) {
  31. 'Operating Activities' => $this->totalOperatingActivities = $netMovement,
  32. 'Investing Activities' => $this->totalInvestingActivities = $netMovement,
  33. 'Financing Activities' => $this->totalFinancingActivities = $netMovement,
  34. };
  35. // Sum inflows and outflows separately
  36. if ($netMovement > 0) {
  37. $cashInflow += $netMovement;
  38. } else {
  39. $cashOutflow += $netMovement;
  40. }
  41. }
  42. // Store gross totals
  43. $this->grossCashInflow = money($cashInflow, CurrencyAccessor::getDefaultCurrency())->format();
  44. $this->grossCashOutflow = money($cashOutflow, CurrencyAccessor::getDefaultCurrency())->format();
  45. }
  46. public function getCategories(): array
  47. {
  48. $categories = [];
  49. foreach ($this->report->categories as $accountCategoryName => $accountCategory) {
  50. // Header for the main category
  51. $header = [];
  52. foreach ($this->getColumns() as $column) {
  53. $header[$column->getName()] = $column->getName() === 'account_name' ? $accountCategoryName : '';
  54. }
  55. // Category-level summary
  56. $categorySummary = [];
  57. foreach ($this->getColumns() as $column) {
  58. $categorySummary[$column->getName()] = match ($column->getName()) {
  59. 'account_name' => 'Total ' . $accountCategoryName,
  60. 'net_movement' => $accountCategory->summary->netMovement ?? '',
  61. default => '',
  62. };
  63. }
  64. // Accounts directly under the main category
  65. $data = array_map(function (AccountDTO $account) {
  66. $row = [];
  67. foreach ($this->getColumns() as $column) {
  68. $row[$column->getName()] = match ($column->getName()) {
  69. 'account_code' => $account->accountCode,
  70. 'account_name' => [
  71. 'name' => $account->accountName,
  72. 'id' => $account->accountId ?? null,
  73. 'start_date' => $account->startDate,
  74. 'end_date' => $account->endDate,
  75. ],
  76. 'net_movement' => $account->balance->netMovement ?? '',
  77. default => '',
  78. };
  79. }
  80. return $row;
  81. }, $accountCategory->accounts ?? []);
  82. // Subcategories (types) under the main category
  83. $types = [];
  84. ray($accountCategory->types);
  85. foreach ($accountCategory->types as $typeName => $type) {
  86. // Header for subcategory (type)
  87. $typeHeader = [];
  88. foreach ($this->getColumns() as $column) {
  89. $typeHeader[$column->getName()] = $column->getName() === 'account_name' ? $typeName : '';
  90. }
  91. ray($typeHeader);
  92. // Account data for the subcategory
  93. $typeData = array_map(function (AccountDTO $account) {
  94. $row = [];
  95. foreach ($this->getColumns() as $column) {
  96. $row[$column->getName()] = match ($column->getName()) {
  97. 'account_code' => $account->accountCode,
  98. 'account_name' => [
  99. 'name' => $account->accountName,
  100. 'id' => $account->accountId ?? null,
  101. 'start_date' => $account->startDate,
  102. 'end_date' => $account->endDate,
  103. ],
  104. 'net_movement' => $account->balance->netMovement ?? '',
  105. default => '',
  106. };
  107. }
  108. return $row;
  109. }, $type->accounts ?? []);
  110. ray($typeData);
  111. // Subcategory (type) summary
  112. $typeSummary = [];
  113. foreach ($this->getColumns() as $column) {
  114. $typeSummary[$column->getName()] = match ($column->getName()) {
  115. 'account_name' => 'Total ' . $typeName,
  116. 'net_movement' => $type->summary->netMovement ?? '',
  117. default => '',
  118. };
  119. }
  120. // Add subcategory (type) to the list
  121. $types[$typeName] = new ReportTypeDTO(
  122. header: $typeHeader,
  123. data: $typeData,
  124. summary: $typeSummary,
  125. );
  126. }
  127. // Add the category to the final array with its direct accounts and subcategories (types)
  128. $categories[$accountCategoryName] = new ReportCategoryDTO(
  129. header: $header,
  130. data: $data, // Direct accounts under the category
  131. summary: $categorySummary,
  132. types: $types, // Subcategories (types) under the category
  133. );
  134. }
  135. return $categories;
  136. }
  137. public function getSummaryCategories(): array
  138. {
  139. $summaryCategories = [];
  140. $columns = $this->getSummaryColumns();
  141. foreach ($this->report->categories as $accountCategoryName => $accountCategory) {
  142. $categoryHeader = [];
  143. foreach ($columns as $column) {
  144. $categoryHeader[$column->getName()] = $column->getName() === 'account_name' ? $accountCategoryName : '';
  145. }
  146. $categorySummary = [];
  147. foreach ($columns as $column) {
  148. $categorySummary[$column->getName()] = match ($column->getName()) {
  149. 'account_name' => 'Total ' . $accountCategoryName,
  150. 'net_movement' => $accountCategory->summary->netMovement ?? '',
  151. default => '',
  152. };
  153. }
  154. $types = [];
  155. // Iterate through each account type and calculate type summaries
  156. foreach ($accountCategory->types as $typeName => $type) {
  157. $typeSummary = [];
  158. foreach ($columns as $column) {
  159. $typeSummary[$column->getName()] = match ($column->getName()) {
  160. 'account_name' => 'Total ' . $typeName,
  161. 'net_movement' => $type->summary->netMovement ?? '',
  162. default => '',
  163. };
  164. }
  165. $types[$typeName] = new ReportTypeDTO(
  166. header: [],
  167. data: [],
  168. summary: $typeSummary,
  169. );
  170. }
  171. // Add the category with its types and summary to the final array
  172. $summaryCategories[$accountCategoryName] = new ReportCategoryDTO(
  173. header: $categoryHeader,
  174. data: [],
  175. summary: $categorySummary,
  176. types: $types,
  177. );
  178. }
  179. return $summaryCategories;
  180. }
  181. public function getOverallTotals(): array
  182. {
  183. return [];
  184. }
  185. public function getSummaryOverallTotals(): array
  186. {
  187. return [];
  188. }
  189. public function getSummary(): array
  190. {
  191. return [
  192. [
  193. 'label' => 'Gross Cash Inflow',
  194. 'value' => $this->grossCashInflow,
  195. ],
  196. [
  197. 'label' => 'Gross Cash Outflow',
  198. 'value' => $this->grossCashOutflow,
  199. ],
  200. [
  201. 'label' => 'Net Cash Flow',
  202. 'value' => $this->report->overallTotal->netMovement ?? '',
  203. ],
  204. ];
  205. }
  206. }