| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 05:42:41 +02:00
										 |  |  | declare(strict_types=1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  | namespace FireflyIII\Support\JsonApi\Enrichments; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use Carbon\Carbon; | 
					
						
							|  |  |  | use FireflyIII\Models\AutoBudget; | 
					
						
							|  |  |  | use FireflyIII\Models\Budget; | 
					
						
							|  |  |  | use FireflyIII\Models\Note; | 
					
						
							| 
									
										
										
										
											2025-08-07 07:46:49 +02:00
										 |  |  | use FireflyIII\Models\ObjectGroup; | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  | use FireflyIII\Models\TransactionCurrency; | 
					
						
							|  |  |  | use FireflyIII\Models\UserGroup; | 
					
						
							|  |  |  | use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; | 
					
						
							|  |  |  | use FireflyIII\Support\Facades\Amount; | 
					
						
							|  |  |  | use FireflyIII\User; | 
					
						
							|  |  |  | use Illuminate\Database\Eloquent\Model; | 
					
						
							|  |  |  | use Illuminate\Support\Collection; | 
					
						
							| 
									
										
										
										
											2025-08-07 07:46:49 +02:00
										 |  |  | use Illuminate\Support\Facades\DB; | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  | use Illuminate\Support\Facades\Log; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BudgetEnrichment implements EnrichmentInterface | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     private Collection          $collection; | 
					
						
							| 
									
										
										
										
											2025-08-07 19:09:25 +02:00
										 |  |  |     private bool                $convertToPrimary; | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |     private TransactionCurrency $primaryCurrency; | 
					
						
							|  |  |  |     private User                $user; | 
					
						
							|  |  |  |     private UserGroup           $userGroup; | 
					
						
							| 
									
										
										
										
											2025-08-07 20:04:36 +02:00
										 |  |  |     private array               $ids           = []; | 
					
						
							|  |  |  |     private array               $notes         = []; | 
					
						
							|  |  |  |     private array               $autoBudgets   = []; | 
					
						
							|  |  |  |     private array               $currencies    = []; | 
					
						
							|  |  |  |     private ?Carbon             $start         = null; | 
					
						
							|  |  |  |     private ?Carbon             $end           = null; | 
					
						
							|  |  |  |     private array               $spent         = []; | 
					
						
							|  |  |  |     private array               $pcSpent       = []; | 
					
						
							|  |  |  |     private array               $objectGroups  = []; | 
					
						
							|  |  |  |     private array               $mappedObjects = []; | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     public function __construct() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->convertToPrimary = Amount::convertToPrimary(); | 
					
						
							|  |  |  |         $this->primaryCurrency  = Amount::getPrimaryCurrency(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function enrich(Collection $collection): Collection | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->collection = $collection; | 
					
						
							|  |  |  |         $this->collectIds(); | 
					
						
							|  |  |  |         $this->collectNotes(); | 
					
						
							|  |  |  |         $this->collectAutoBudgets(); | 
					
						
							|  |  |  |         $this->collectExpenses(); | 
					
						
							| 
									
										
										
										
											2025-08-07 07:46:49 +02:00
										 |  |  |         $this->collectObjectGroups(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |         $this->appendCollectedData(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this->collection; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 05:42:41 +02:00
										 |  |  |     public function enrichSingle(array|Model $model): array|Model | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         Log::debug(__METHOD__); | 
					
						
							|  |  |  |         $collection = new Collection([$model]); | 
					
						
							|  |  |  |         $collection = $this->enrich($collection); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $collection->first(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setUser(User $user): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->user = $user; | 
					
						
							|  |  |  |         $this->setUserGroup($user->userGroup); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setUserGroup(UserGroup $userGroup): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->userGroup = $userGroup; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private function collectIds(): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /** @var Budget $budget */ | 
					
						
							|  |  |  |         foreach ($this->collection as $budget) { | 
					
						
							|  |  |  |             $this->ids[] = (int)$budget->id; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-08-04 20:55:31 +02:00
										 |  |  |         $this->ids = array_unique($this->ids); | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private function collectNotes(): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $notes = Note::query()->whereIn('noteable_id', $this->ids) | 
					
						
							| 
									
										
										
										
											2025-08-07 20:04:36 +02:00
										 |  |  |             ->whereNotNull('notes.text') | 
					
						
							|  |  |  |             ->where('notes.text', '!=', '') | 
					
						
							|  |  |  |             ->where('noteable_type', Budget::class)->get(['notes.noteable_id', 'notes.text'])->toArray() | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |         foreach ($notes as $note) { | 
					
						
							|  |  |  |             $this->notes[(int)$note['noteable_id']] = (string)$note['text']; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         Log::debug(sprintf('Enrich with %d note(s)', count($this->notes))); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private function appendCollectedData(): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->collection = $this->collection->map(function (Budget $item) { | 
					
						
							| 
									
										
										
										
											2025-08-07 20:04:36 +02:00
										 |  |  |             $id         = (int)$item->id; | 
					
						
							|  |  |  |             $meta       = [ | 
					
						
							| 
									
										
										
										
											2025-08-07 07:46:49 +02:00
										 |  |  |                 'object_group_id'    => null, | 
					
						
							|  |  |  |                 'object_group_order' => null, | 
					
						
							|  |  |  |                 'object_group_title' => null, | 
					
						
							|  |  |  |                 'notes'              => $this->notes[$id] ?? null, | 
					
						
							|  |  |  |                 'currency'           => $this->currencies[$id] ?? null, | 
					
						
							|  |  |  |                 'auto_budget'        => $this->autoBudgets[$id] ?? null, | 
					
						
							|  |  |  |                 'spent'              => $this->spent[$id] ?? null, | 
					
						
							|  |  |  |                 'pc_spent'           => $this->pcSpent[$id] ?? null, | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |             ]; | 
					
						
							| 
									
										
										
										
											2025-08-07 07:46:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // add object group if available
 | 
					
						
							|  |  |  |             if (array_key_exists($id, $this->mappedObjects)) { | 
					
						
							|  |  |  |                 $key                        = $this->mappedObjects[$id]; | 
					
						
							|  |  |  |                 $meta['object_group_id']    = $this->objectGroups[$key]['id']; | 
					
						
							|  |  |  |                 $meta['object_group_title'] = $this->objectGroups[$key]['title']; | 
					
						
							|  |  |  |                 $meta['object_group_order'] = $this->objectGroups[$key]['order']; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |             $item->meta = $meta; | 
					
						
							| 
									
										
										
										
											2025-08-04 05:42:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |             return $item; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private function collectAutoBudgets(): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $set = AutoBudget::whereIn('budget_id', $this->ids)->with(['transactionCurrency'])->get(); | 
					
						
							| 
									
										
										
										
											2025-08-04 05:42:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |         /** @var AutoBudget $autoBudget */ | 
					
						
							|  |  |  |         foreach ($set as $autoBudget) { | 
					
						
							|  |  |  |             $budgetId                     = (int)$autoBudget->budget_id; | 
					
						
							|  |  |  |             $this->currencies[$budgetId]  = $autoBudget->transactionCurrency; | 
					
						
							|  |  |  |             $this->autoBudgets[$budgetId] = [ | 
					
						
							|  |  |  |                 'type'      => (int)$autoBudget->auto_budget_type, | 
					
						
							|  |  |  |                 'period'    => $autoBudget->period, | 
					
						
							|  |  |  |                 'amount'    => $autoBudget->amount, | 
					
						
							|  |  |  |                 'pc_amount' => $autoBudget->native_amount, | 
					
						
							|  |  |  |             ]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private function collectExpenses(): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (null !== $this->start && null !== $this->end) { | 
					
						
							|  |  |  |             /** @var OperationsRepositoryInterface $opsRepository */ | 
					
						
							|  |  |  |             $opsRepository = app(OperationsRepositoryInterface::class); | 
					
						
							|  |  |  |             $opsRepository->setUser($this->user); | 
					
						
							|  |  |  |             $opsRepository->setUserGroup($this->userGroup); | 
					
						
							|  |  |  |             // $spent = $this->beautify();
 | 
					
						
							|  |  |  |             // $set = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$budget]))
 | 
					
						
							| 
									
										
										
										
											2025-08-07 20:04:36 +02:00
										 |  |  |             $expenses      = $opsRepository->collectExpenses($this->start, $this->end, null, $this->collection, null); | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  |             foreach ($this->collection as $item) { | 
					
						
							|  |  |  |                 $id                 = (int)$item->id; | 
					
						
							|  |  |  |                 $this->spent[$id]   = array_values($opsRepository->sumCollectedExpensesByBudget($expenses, $item, false)); | 
					
						
							|  |  |  |                 $this->pcSpent[$id] = array_values($opsRepository->sumCollectedExpensesByBudget($expenses, $item, true)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setEnd(?Carbon $end): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->end = $end; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setStart(?Carbon $start): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->start = $start; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-08-07 07:46:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private function collectObjectGroups(): void | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-08-07 20:04:36 +02:00
										 |  |  |         $set    = DB::table('object_groupables') | 
					
						
							|  |  |  |             ->whereIn('object_groupable_id', $this->ids) | 
					
						
							|  |  |  |             ->where('object_groupable_type', Budget::class) | 
					
						
							|  |  |  |             ->get(['object_groupable_id', 'object_group_id']) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2025-08-07 07:46:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-07 20:04:36 +02:00
										 |  |  |         $ids    = array_unique($set->pluck('object_group_id')->toArray()); | 
					
						
							| 
									
										
										
										
											2025-08-07 07:46:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         foreach ($set as $entry) { | 
					
						
							|  |  |  |             $this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $groups = ObjectGroup::whereIn('id', $ids)->get(['id', 'title', 'order'])->toArray(); | 
					
						
							|  |  |  |         foreach ($groups as $group) { | 
					
						
							|  |  |  |             $group['id']                           = (int)$group['id']; | 
					
						
							|  |  |  |             $group['order']                        = (int)$group['order']; | 
					
						
							|  |  |  |             $this->objectGroups[(int)$group['id']] = $group; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-08-03 20:17:50 +02:00
										 |  |  | } |