Andrew Wallo hace 1 año
padre
commit
f59d40d88d

+ 4
- 0
app/Filament/Company/Pages/Reports/IncomeStatement.php Ver fichero

@@ -11,6 +11,7 @@ use App\Transformers\IncomeStatementReportTransformer;
11 11
 use Filament\Forms\Form;
12 12
 use Filament\Support\Enums\Alignment;
13 13
 use Guava\FilamentClusters\Forms\Cluster;
14
+use Livewire\Attributes\Url;
14 15
 use Symfony\Component\HttpFoundation\StreamedResponse;
15 16
 
16 17
 class IncomeStatement extends BaseReportPage
@@ -25,6 +26,9 @@ class IncomeStatement extends BaseReportPage
25 26
 
26 27
     protected ExportService $exportService;
27 28
 
29
+    #[Url]
30
+    public ?string $activeTab = 'summary';
31
+
28 32
     public function boot(ReportService $reportService, ExportService $exportService): void
29 33
     {
30 34
         $this->reportService = $reportService;

+ 90
- 3
app/Transformers/IncomeStatementReportTransformer.php Ver fichero

@@ -5,14 +5,15 @@ namespace App\Transformers;
5 5
 use App\DTO\AccountDTO;
6 6
 use App\DTO\ReportCategoryDTO;
7 7
 use App\Support\Column;
8
+use App\Utilities\Currency\CurrencyAccessor;
8 9
 
9 10
 class IncomeStatementReportTransformer extends BaseReportTransformer
10 11
 {
11
-    protected string $totalRevenue = '$0.00';
12
+    protected string $totalRevenue = '0';
12 13
 
13
-    protected string $totalCogs = '$0.00';
14
+    protected string $totalCogs = '0';
14 15
 
15
-    protected string $totalExpenses = '$0.00';
16
+    protected string $totalExpenses = '0';
16 17
 
17 18
     public function getTitle(): string
18 19
     {
@@ -91,6 +92,92 @@ class IncomeStatementReportTransformer extends BaseReportTransformer
91 92
         return $categories;
92 93
     }
93 94
 
95
+    public function getSummaryCategories(): array
96
+    {
97
+        $summaryCategories = [];
98
+
99
+        $columns = [
100
+            'account_name',
101
+            'net_movement',
102
+        ];
103
+
104
+        foreach ($this->report->categories as $accountCategoryName => $accountCategory) {
105
+            // Header for the main category
106
+            $categoryHeader = [];
107
+
108
+            foreach ($columns as $index => $column) {
109
+                $categoryHeader[$index] = $column === 'account_name' ? $accountCategoryName : '';
110
+            }
111
+
112
+            // Category-level summary
113
+            $categorySummary = [];
114
+            foreach ($columns as $column) {
115
+                $categorySummary[] = match ($column) {
116
+                    'account_name' => $accountCategoryName,
117
+                    'net_movement' => $accountCategory->summary->netMovement ?? '',
118
+                    default => '',
119
+                };
120
+            }
121
+
122
+            // Add the category summary to the final array
123
+            $summaryCategories[$accountCategoryName] = new ReportCategoryDTO(
124
+                header: $categoryHeader,
125
+                data: [], // No direct accounts are needed here, only summaries
126
+                summary: $categorySummary,
127
+                types: [] // No types for the income statement
128
+            );
129
+        }
130
+
131
+        return $summaryCategories;
132
+    }
133
+
134
+    public function getGrossProfit(): array
135
+    {
136
+        $this->calculateTotals();
137
+
138
+        $grossProfit = [];
139
+
140
+        $columns = [
141
+            'account_name',
142
+            'net_movement',
143
+        ];
144
+
145
+        $revenue = money($this->totalRevenue, CurrencyAccessor::getDefaultCurrency())->getAmount();
146
+        $cogs = money($this->totalCogs, CurrencyAccessor::getDefaultCurrency())->getAmount();
147
+
148
+        $grossProfitAmount = $revenue - $cogs;
149
+        $grossProfitFormatted = money($grossProfitAmount, CurrencyAccessor::getDefaultCurrency(), true)->format();
150
+
151
+        foreach ($columns as $column) {
152
+            $grossProfit[] = match ($column) {
153
+                'account_name' => 'Gross Profit',
154
+                'net_movement' => $grossProfitFormatted,
155
+                default => '',
156
+            };
157
+        }
158
+
159
+        return $grossProfit;
160
+    }
161
+
162
+    public function getSummaryTotals(): array
163
+    {
164
+        $totals = [];
165
+        $columns = [
166
+            'account_name',
167
+            'net_movement',
168
+        ];
169
+
170
+        foreach ($columns as $column) {
171
+            $totals[] = match ($column) {
172
+                'account_name' => 'Net Earnings',
173
+                'net_movement' => $this->report->overallTotal->netMovement ?? '',
174
+                default => '',
175
+            };
176
+        }
177
+
178
+        return $totals;
179
+    }
180
+
94 181
     public function getOverallTotals(): array
95 182
     {
96 183
         $totals = [];

+ 30
- 30
composer.lock Ver fichero

@@ -497,16 +497,16 @@
497 497
         },
498 498
         {
499 499
             "name": "aws/aws-sdk-php",
500
-            "version": "3.324.5",
500
+            "version": "3.324.6",
501 501
             "source": {
502 502
                 "type": "git",
503 503
                 "url": "https://github.com/aws/aws-sdk-php.git",
504
-                "reference": "052c5d429ccd8775f7eed2855c2ca8cae2be52cb"
504
+                "reference": "7412a44da62fd607efbaac4084e69d6621f29de1"
505 505
             },
506 506
             "dist": {
507 507
                 "type": "zip",
508
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/052c5d429ccd8775f7eed2855c2ca8cae2be52cb",
509
-                "reference": "052c5d429ccd8775f7eed2855c2ca8cae2be52cb",
508
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7412a44da62fd607efbaac4084e69d6621f29de1",
509
+                "reference": "7412a44da62fd607efbaac4084e69d6621f29de1",
510 510
                 "shasum": ""
511 511
             },
512 512
             "require": {
@@ -589,9 +589,9 @@
589 589
             "support": {
590 590
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
591 591
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
592
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.324.5"
592
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.324.6"
593 593
             },
594
-            "time": "2024-10-17T18:12:04+00:00"
594
+            "time": "2024-10-18T18:06:33+00:00"
595 595
         },
596 596
         {
597 597
             "name": "aws/aws-sdk-php-laravel",
@@ -3627,16 +3627,16 @@
3627 3627
         },
3628 3628
         {
3629 3629
             "name": "league/csv",
3630
-            "version": "9.17.0",
3630
+            "version": "9.18.0",
3631 3631
             "source": {
3632 3632
                 "type": "git",
3633 3633
                 "url": "https://github.com/thephpleague/csv.git",
3634
-                "reference": "8cab815fb11ec93aa2f7b8a57b3daa1f1a364011"
3634
+                "reference": "b02d010e4055ae992247f6ffd1e7b103ef2a0790"
3635 3635
             },
3636 3636
             "dist": {
3637 3637
                 "type": "zip",
3638
-                "url": "https://api.github.com/repos/thephpleague/csv/zipball/8cab815fb11ec93aa2f7b8a57b3daa1f1a364011",
3639
-                "reference": "8cab815fb11ec93aa2f7b8a57b3daa1f1a364011",
3638
+                "url": "https://api.github.com/repos/thephpleague/csv/zipball/b02d010e4055ae992247f6ffd1e7b103ef2a0790",
3639
+                "reference": "b02d010e4055ae992247f6ffd1e7b103ef2a0790",
3640 3640
                 "shasum": ""
3641 3641
             },
3642 3642
             "require": {
@@ -3648,11 +3648,11 @@
3648 3648
                 "ext-xdebug": "*",
3649 3649
                 "friendsofphp/php-cs-fixer": "^3.64.0",
3650 3650
                 "phpbench/phpbench": "^1.3.1",
3651
-                "phpstan/phpstan": "^1.12.5",
3651
+                "phpstan/phpstan": "^1.12.6",
3652 3652
                 "phpstan/phpstan-deprecation-rules": "^1.2.1",
3653 3653
                 "phpstan/phpstan-phpunit": "^1.4.0",
3654 3654
                 "phpstan/phpstan-strict-rules": "^1.6.1",
3655
-                "phpunit/phpunit": "^10.5.16 || ^11.4.0",
3655
+                "phpunit/phpunit": "^10.5.16 || ^11.4.1",
3656 3656
                 "symfony/var-dumper": "^6.4.8 || ^7.1.5"
3657 3657
             },
3658 3658
             "suggest": {
@@ -3710,7 +3710,7 @@
3710 3710
                     "type": "github"
3711 3711
                 }
3712 3712
             ],
3713
-            "time": "2024-10-10T10:30:28+00:00"
3713
+            "time": "2024-10-18T08:14:48+00:00"
3714 3714
         },
3715 3715
         {
3716 3716
             "name": "league/flysystem",
@@ -10783,16 +10783,16 @@
10783 10783
         },
10784 10784
         {
10785 10785
             "name": "phpstan/phpstan",
10786
-            "version": "1.12.6",
10786
+            "version": "1.12.7",
10787 10787
             "source": {
10788 10788
                 "type": "git",
10789 10789
                 "url": "https://github.com/phpstan/phpstan.git",
10790
-                "reference": "dc4d2f145a88ea7141ae698effd64d9df46527ae"
10790
+                "reference": "dc2b9976bd8b0f84ec9b0e50cc35378551de7af0"
10791 10791
             },
10792 10792
             "dist": {
10793 10793
                 "type": "zip",
10794
-                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dc4d2f145a88ea7141ae698effd64d9df46527ae",
10795
-                "reference": "dc4d2f145a88ea7141ae698effd64d9df46527ae",
10794
+                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dc2b9976bd8b0f84ec9b0e50cc35378551de7af0",
10795
+                "reference": "dc2b9976bd8b0f84ec9b0e50cc35378551de7af0",
10796 10796
                 "shasum": ""
10797 10797
             },
10798 10798
             "require": {
@@ -10837,7 +10837,7 @@
10837 10837
                     "type": "github"
10838 10838
                 }
10839 10839
             ],
10840
-            "time": "2024-10-06T15:03:59+00:00"
10840
+            "time": "2024-10-18T11:12:07+00:00"
10841 10841
         },
10842 10842
         {
10843 10843
             "name": "phpunit/php-code-coverage",
@@ -11264,16 +11264,16 @@
11264 11264
         },
11265 11265
         {
11266 11266
             "name": "rector/rector",
11267
-            "version": "1.2.7",
11267
+            "version": "1.2.8",
11268 11268
             "source": {
11269 11269
                 "type": "git",
11270 11270
                 "url": "https://github.com/rectorphp/rector.git",
11271
-                "reference": "5b33bdd871895276e2c18e5410a4a57df9233ee0"
11271
+                "reference": "05755bf43617449c08ee8e50fb840c85ad3b1240"
11272 11272
             },
11273 11273
             "dist": {
11274 11274
                 "type": "zip",
11275
-                "url": "https://api.github.com/repos/rectorphp/rector/zipball/5b33bdd871895276e2c18e5410a4a57df9233ee0",
11276
-                "reference": "5b33bdd871895276e2c18e5410a4a57df9233ee0",
11275
+                "url": "https://api.github.com/repos/rectorphp/rector/zipball/05755bf43617449c08ee8e50fb840c85ad3b1240",
11276
+                "reference": "05755bf43617449c08ee8e50fb840c85ad3b1240",
11277 11277
                 "shasum": ""
11278 11278
             },
11279 11279
             "require": {
@@ -11311,7 +11311,7 @@
11311 11311
             ],
11312 11312
             "support": {
11313 11313
                 "issues": "https://github.com/rectorphp/rector/issues",
11314
-                "source": "https://github.com/rectorphp/rector/tree/1.2.7"
11314
+                "source": "https://github.com/rectorphp/rector/tree/1.2.8"
11315 11315
             },
11316 11316
             "funding": [
11317 11317
                 {
@@ -11319,7 +11319,7 @@
11319 11319
                     "type": "github"
11320 11320
                 }
11321 11321
             ],
11322
-            "time": "2024-10-12T11:12:46+00:00"
11322
+            "time": "2024-10-18T11:54:27+00:00"
11323 11323
         },
11324 11324
         {
11325 11325
             "name": "sebastian/cli-parser",
@@ -11493,16 +11493,16 @@
11493 11493
         },
11494 11494
         {
11495 11495
             "name": "sebastian/comparator",
11496
-            "version": "6.1.0",
11496
+            "version": "6.1.1",
11497 11497
             "source": {
11498 11498
                 "type": "git",
11499 11499
                 "url": "https://github.com/sebastianbergmann/comparator.git",
11500
-                "reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d"
11500
+                "reference": "5ef523a49ae7a302b87b2102b72b1eda8918d686"
11501 11501
             },
11502 11502
             "dist": {
11503 11503
                 "type": "zip",
11504
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa37b9e2ca618cb051d71b60120952ee8ca8b03d",
11505
-                "reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d",
11504
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5ef523a49ae7a302b87b2102b72b1eda8918d686",
11505
+                "reference": "5ef523a49ae7a302b87b2102b72b1eda8918d686",
11506 11506
                 "shasum": ""
11507 11507
             },
11508 11508
             "require": {
@@ -11558,7 +11558,7 @@
11558 11558
             "support": {
11559 11559
                 "issues": "https://github.com/sebastianbergmann/comparator/issues",
11560 11560
                 "security": "https://github.com/sebastianbergmann/comparator/security/policy",
11561
-                "source": "https://github.com/sebastianbergmann/comparator/tree/6.1.0"
11561
+                "source": "https://github.com/sebastianbergmann/comparator/tree/6.1.1"
11562 11562
             },
11563 11563
             "funding": [
11564 11564
                 {
@@ -11566,7 +11566,7 @@
11566 11566
                     "type": "github"
11567 11567
                 }
11568 11568
             ],
11569
-            "time": "2024-09-11T15:42:56+00:00"
11569
+            "time": "2024-10-18T15:00:48+00:00"
11570 11570
         },
11571 11571
         {
11572 11572
             "name": "sebastian/complexity",

+ 1
- 1
resources/views/components/company/tables/reports/balance-sheet-summary.blade.php Ver fichero

@@ -18,7 +18,7 @@
18 18
         <tr class="bg-gray-50 dark:bg-white/5">
19 19
             @foreach($accountCategory->header as $accountCategoryHeaderIndex => $accountCategoryHeaderCell)
20 20
                 <x-filament-tables::cell class="{{ $accountCategoryHeaderIndex === 0 ? 'text-left' : 'text-right' }}">
21
-                    <div class="px-3 py-2 text-sm font-semibold text-gray-950 dark:text-white">
21
+                    <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
22 22
                         {{ $accountCategoryHeaderCell }}
23 23
                     </div>
24 24
                 </x-filament-tables::cell>

+ 2
- 2
resources/views/components/company/tables/reports/balance-sheet.blade.php Ver fichero

@@ -5,7 +5,7 @@
5 5
         <tr class="bg-gray-50 dark:bg-white/5">
6 6
             @foreach($accountCategory->header as $accountCategoryHeaderIndex => $accountCategoryHeaderCell)
7 7
                 <x-filament-tables::cell class="{{ $report->getAlignmentClass($accountCategoryHeaderIndex) }}">
8
-                    <div class="px-3 py-3 leading-6 text-sm font-semibold text-gray-950 dark:text-white">
8
+                    <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
9 9
                         {{ $accountCategoryHeaderCell }}
10 10
                     </div>
11 11
                 </x-filament-tables::cell>
@@ -63,7 +63,7 @@
63 63
                 @foreach($accountType->header as $accountTypeHeaderIndex => $accountTypeHeaderCell)
64 64
                     <x-filament-tables::cell class="{{ $report->getAlignmentClass($accountTypeHeaderIndex) }}"
65 65
                                              style="padding-left: 1.5rem;">
66
-                        <div class="px-3 py-3 leading-6 text-sm font-semibold text-gray-950 dark:text-white">
66
+                        <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
67 67
                             {{ $accountTypeHeaderCell }}
68 68
                         </div>
69 69
                     </x-filament-tables::cell>

+ 1
- 1
resources/views/components/company/tables/reports/detailed-report.blade.php Ver fichero

@@ -15,7 +15,7 @@
15 15
         <tr class="bg-gray-50 dark:bg-white/5">
16 16
             @foreach($category->header as $headerIndex => $header)
17 17
                 <x-filament-tables::cell class="{{ $report->getAlignmentClass($headerIndex) }}">
18
-                    <div class="px-3 py-2 text-sm font-semibold text-gray-950 dark:text-white">
18
+                    <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
19 19
                         {{ $header }}
20 20
                     </div>
21 21
                 </x-filament-tables::cell>

+ 54
- 0
resources/views/components/company/tables/reports/income-statement-summary.blade.php Ver fichero

@@ -0,0 +1,54 @@
1
+<table class="w-full table-auto divide-y divide-gray-200 dark:divide-white/5">
2
+    <thead class="divide-y divide-gray-200 dark:divide-white/5">
3
+    <tr class="bg-gray-50 dark:bg-white/5">
4
+        <th class="px-3 py-3.5 sm:first-of-type:ps-6 sm:last-of-type:pe-6 text-left">
5
+            <span class="text-sm font-semibold text-gray-950 dark:text-white">
6
+                Accounts
7
+            </span>
8
+        </th>
9
+        <th class="px-3 py-3.5 sm:first-of-type:ps-6 sm:last-of-type:pe-6 text-right">
10
+            <span class="text-sm font-semibold text-gray-950 dark:text-white">
11
+                Amount
12
+            </span>
13
+        </th>
14
+    </tr>
15
+    </thead>
16
+    @foreach($report->getSummaryCategories() as $accountCategory)
17
+        <tbody class="divide-y divide-gray-200 whitespace-nowrap dark:divide-white/5">
18
+        <tr>
19
+            @foreach($accountCategory->summary as $accountCategorySummaryIndex => $accountCategorySummaryCell)
20
+                <x-filament-tables::cell class="{{ $accountCategorySummaryIndex === 0 ? 'text-left' : 'text-right' }}">
21
+                    <div class="px-3 py-2 text-sm leading-6 font-normal text-gray-950 dark:text-white">
22
+                        {{ $accountCategorySummaryCell }}
23
+                    </div>
24
+                </x-filament-tables::cell>
25
+            @endforeach
26
+        </tr>
27
+
28
+        @if($accountCategory->header[0] === 'Cost of Goods Sold')
29
+            <tr class="bg-gray-50 dark:bg-white/5">
30
+                @foreach($report->getGrossProfit() as $grossProfitIndex => $grossProfitCell)
31
+                    <x-filament-tables::cell class="{{ $grossProfitIndex === 0 ? 'text-left' : 'text-right' }}">
32
+                        <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
33
+                            {{ $grossProfitCell }}
34
+                        </div>
35
+                    </x-filament-tables::cell>
36
+                @endforeach
37
+            </tr>
38
+        @endif
39
+        </tbody>
40
+    @endforeach
41
+    @if(! empty($report->getOverallTotals()))
42
+        <tfoot>
43
+        <tr class="bg-gray-50 dark:bg-white/5">
44
+            @foreach($report->getSummaryTotals() as $index => $total)
45
+                <x-filament-tables::cell class="{{ $index === 0 ? 'text-left' : 'text-right' }}">
46
+                    <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
47
+                        {{ $total }}
48
+                    </div>
49
+                </x-filament-tables::cell>
50
+            @endforeach
51
+        </tr>
52
+        </tfoot>
53
+    @endif
54
+</table>

+ 21
- 1
resources/views/filament/company/pages/reports/income-statement.blade.php Ver fichero

@@ -58,9 +58,29 @@
58 58
         @endif
59 59
     </x-filament::section>
60 60
 
61
+    <x-filament::tabs>
62
+        <x-filament::tabs.item
63
+            :active="$activeTab === 'summary'"
64
+            wire:click="$set('activeTab', 'summary')"
65
+        >
66
+            Summary
67
+        </x-filament::tabs.item>
68
+
69
+        <x-filament::tabs.item
70
+            :active="$activeTab === 'details'"
71
+            wire:click="$set('activeTab', 'details')"
72
+        >
73
+            Details
74
+        </x-filament::tabs.item>
75
+    </x-filament::tabs>
76
+
61 77
     <x-company.tables.container :report-loaded="$this->reportLoaded">
62 78
         @if($this->report)
63
-            <x-company.tables.reports.detailed-report :report="$this->report"/>
79
+            @if($activeTab === 'summary')
80
+                <x-company.tables.reports.income-statement-summary :report="$this->report"/>
81
+            @elseif($activeTab === 'details')
82
+                <x-company.tables.reports.detailed-report :report="$this->report"/>
83
+            @endif
64 84
         @endif
65 85
     </x-company.tables.container>
66 86
 </x-filament-panels::page>

Loading…
Cancelar
Guardar