Compare commits

...

16 Commits

Author SHA1 Message Date
hackerESQ 307f74b1d9 Merge pull request #14 from investbrainapp/dev
fix: adds validation for transaction date
2024-11-07 20:46:03 -06:00
hackerESQ 0c29393f3b fix: skip dividend sync if most recent dividend was less than 24 hours ago 2024-11-07 20:40:55 -06:00
hackerESQ af3726cb91 fix: sales quantity should use rounded float numbers 2024-11-07 18:20:53 -06:00
hackerESQ 0d40fd92f0 fix: adds validation for transaction date (no post-dated transactions) 2024-11-07 18:06:27 -06:00
hackerESQ 0f55d84355 Merge pull request #13 from eltociear/patch-1
docs: update README.md
2024-11-07 17:42:31 -06:00
Ikko Eltociear Ashimine eafa889827 docs: update README.md
assstant -> assistant
2024-11-08 08:39:39 +09:00
hackerESQ 60cd880c2e docs: fix formatting for TOC 2024-11-07 17:31:50 -06:00
hackerESQ ea8de69863 docs: adds table of contents to docs 2024-11-07 17:31:17 -06:00
hackerESQ 11ef26e878 docs: add troubleshooting section 2024-11-07 17:05:25 -06:00
hackerESQ 2770ebf958 Merge pull request #12 from investbrainapp/dev
fix:ensure portfolio is available on transactions page
2024-11-07 16:23:03 -06:00
hackerESQ 536ca56c24 fix:ensure portfolio is available on transactions page 2024-11-07 16:18:29 -06:00
hackerESQ d4407d3492 Merge pull request #10 from investbrainapp/dev
Make ASSET_URL optional in env
2024-11-07 12:20:08 -06:00
hackerESQ 81766b4aba fix:don't force set asset_url
related to discussion #7
2024-11-07 12:16:49 -06:00
hackerESQ e1cc040984 Merge pull request #6 from investbrainapp/dev
chore: minor updates for landing page
2024-11-06 23:07:40 -06:00
hackerESQ cdda9d7ff7 chore:maintain lock file 2024-11-06 23:02:31 -06:00
hackerESQ 9b6afe180d fix:logic for selfhosted landing page 2024-11-06 23:01:56 -06:00
8 changed files with 110 additions and 72 deletions
+2 -2
View File
@@ -5,10 +5,11 @@ APP_DEBUG=false
APP_TIMEZONE=UTC APP_TIMEZONE=UTC
APP_PORT=8000 APP_PORT=8000
APP_URL="http://localhost:${APP_PORT}" APP_URL="http://localhost:${APP_PORT}"
ASSET_URL="${APP_URL}"
SELF_HOSTED=true SELF_HOSTED=true
REGISTRATION_ENABLED=true REGISTRATION_ENABLED=true
# ASSET_URL="http://localhost:8000" # (optional) webroot for static assets (css, js, images, etc)
AI_CHAT_ENABLED=false AI_CHAT_ENABLED=false
OPENAI_API_KEY= OPENAI_API_KEY=
OPENAI_ORGANIZATION= OPENAI_ORGANIZATION=
@@ -32,7 +33,6 @@ APP_LOCALE=en
APP_FALLBACK_LOCALE=en APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US APP_FAKER_LOCALE=en_US
DB_CONNECTION=mysql DB_CONNECTION=mysql
DB_HOST=investbrain-mysql DB_HOST=investbrain-mysql
DB_PORT=3306 DB_PORT=3306
+37 -1
View File
@@ -6,6 +6,17 @@ Investbrain is a smart open-source investment tracker that helps you manage, tra
<p align="center"><a href="https://investbra.in" target="_blank"><img src="https://raw.githubusercontent.com/investbrainapp/investbrain/main/screenshot.png" width="100%" alt="Investbrain Screenshot"></a></p> <p align="center"><a href="https://investbra.in" target="_blank"><img src="https://raw.githubusercontent.com/investbrainapp/investbrain/main/screenshot.png" width="100%" alt="Investbrain Screenshot"></a></p>
## Table of contents
- [Under the hood](#under-the-hood)
- [Install (self hosting)](#self-hosting)
- [Chat with your holdings](#chat-with-your-holdings)
- [Market data providers](#market-data-providers)
- [Configuration](#configuration)
- [Updating](#updating)
- [Command line utilities](#command-line-utilities)
- [Troubleshooting](#troubleshooting)
- [Testing](#testing)
## Under the hood ## Under the hood
Investbrain is a Laravel PHP web application that leverages Livewire and Tailwind for its frontend. Most databases should work, including MySQL and SQLite. Out of the box, we feature three market data providers: [Yahoo Finance](https://finance.yahoo.com/), [Finnhub](https://finnhub.io/pricing-stock-api-market-data), and [Alpha Vantage](https://www.alphavantage.co/support/). But we also offer an extensible market data provider interface for intrepid developers to create their own! We also offer an integration with OpenAI's LLMs for our ["chat with your holdings"](#chat-with-your-holdings) capability. Finally, of course we have robust support for i18n, a11y, and dark mode. Investbrain is a Laravel PHP web application that leverages Livewire and Tailwind for its frontend. Most databases should work, including MySQL and SQLite. Out of the box, we feature three market data providers: [Yahoo Finance](https://finance.yahoo.com/), [Finnhub](https://finnhub.io/pricing-stock-api-market-data), and [Alpha Vantage](https://www.alphavantage.co/support/). But we also offer an extensible market data provider interface for intrepid developers to create their own! We also offer an integration with OpenAI's LLMs for our ["chat with your holdings"](#chat-with-your-holdings) capability. Finally, of course we have robust support for i18n, a11y, and dark mode.
@@ -44,7 +55,7 @@ Congrats! You've just installed Investbrain!
Investbrain offers an AI powered chat assistant that is grounded on *your* investments. This enables you to use AI as a thought partner when making investment decisions. Investbrain offers an AI powered chat assistant that is grounded on *your* investments. This enables you to use AI as a thought partner when making investment decisions.
When self-hosting, you can enable the chat assstant by configuring your OpenAI Secret Key and Organization ID in your [.env](https://github.com/investbrainapp/investbrain/blob/main/.env.example) file. Navigate to OpenAI to [create your keys](https://platform.openai.com/api-keys). When self-hosting, you can enable the chat assistant by configuring your OpenAI Secret Key and Organization ID in your [.env](https://github.com/investbrainapp/investbrain/blob/main/.env.example) file. Navigate to OpenAI to [create your keys](https://platform.openai.com/api-keys).
Always keep in mind the limitations of large language models. When in doubt, consult a licensed investment advisor. Always keep in mind the limitations of large language models. When in doubt, consult a licensed investment advisor.
@@ -159,6 +170,31 @@ Just to be safe, we recommend backing up your portfolios before using these comm
| sync:daily-change | Re-calculates daily snapshots of your portfolio's daily performance. Useful to fill in gaps in your portfolio charts. (Note: this is an extremely resource intensive query.) | | sync:daily-change | Re-calculates daily snapshots of your portfolio's daily performance. Useful to fill in gaps in your portfolio charts. (Note: this is an extremely resource intensive query.) |
| sync:holdings | Re-calculates performance of holdings with related transactions (i.e. dividends, realized gains, etc). | | sync:holdings | Re-calculates performance of holdings with related transactions (i.e. dividends, realized gains, etc). |
## Troubleshooting
If you are facing issues with Investbrain, it can be handy to monitor the application's logs:
```bash
docker exec -it investbrain-app cat storage/logs/laravel.log
```
or you can live monitor logs using `tail`:
```bash
docker exec -it investbrain-app tail -f storage/logs/laravel.log
```
### Common issues
<details>
**<summary>Market data not refreshing on fresh install</summary>**
If you're unable to refresh market data out of the box (i.e. your market data provider is set to Yahoo), there is a chance Yahoo is being blocked by a firewall or adblocker. Pihole is known to block `fc.yahoo.com` which is the domain used to query Yahoo.
Once you whitelist `fc.yahoo.com` in pihole, your market data should begin populating!
</details>
## Testing ## Testing
Investbrain has a robus PHPUnit test suite that creates an in-memory SQLite database and runs any queued jobs synchronously using Laravel's array driver. You can run the entire Investbrain test suite from within the Docker container by running: Investbrain has a robus PHPUnit test suite that creates an in-memory SQLite database and runs any queued jobs synchronously using Laravel's array driver. You can run the entire Investbrain test suite from within the Docker container by running:
+8 -6
View File
@@ -50,10 +50,8 @@ class Dividend extends Model
/** /**
* Grab new dividend data * Grab new dividend data
* *
* @param string $symbol
* @return void
*/ */
public static function refreshDividendData(string $symbol) public static function refreshDividendData(string $symbol): void
{ {
$dividends_meta = self::where(['symbol' => $symbol]) $dividends_meta = self::where(['symbol' => $symbol])
->selectRaw('COUNT(symbol) as total_dividends') ->selectRaw('COUNT(symbol) as total_dividends')
@@ -68,7 +66,13 @@ class Dividend extends Model
// nope, refresh forward looking only // nope, refresh forward looking only
if ( $dividends_meta->total_dividends ) { if ( $dividends_meta->total_dividends ) {
$start_date = $dividends_meta->last_date->addHours(48); $start_date = $dividends_meta->last_date->addHours(24);
}
// skip refresh if there's already recent data
if ($start_date >= $end_date) {
return;
} }
// get some data // get some data
@@ -99,8 +103,6 @@ class Dividend extends Model
$market_data->last_dividend_amount = $dividend_data->sortByDesc('date')->first()['dividend_amount']; $market_data->last_dividend_amount = $dividend_data->sortByDesc('date')->first()['dividend_amount'];
$market_data->save(); $market_data->save();
} }
return $dividend_data;
} }
public static function syncHoldings(string $symbol): void public static function syncHoldings(string $symbol): void
+1 -1
View File
@@ -125,7 +125,7 @@ class Transaction extends Model
public function scopeBeforeDate($query, $date) public function scopeBeforeDate($query, $date)
{ {
return $query->whereDate('date', '<', $date); return $query->whereDate('date', '<=', $date);
} }
public function scopeMyTransactions() public function scopeMyTransactions()
+1 -1
View File
@@ -50,7 +50,7 @@ class QuantityValidationRule implements ValidationRule
$maxQuantity = $purchase_qty - $sales_qty; $maxQuantity = $purchase_qty - $sales_qty;
if ($value > $maxQuantity) { if (round($value, 3) > round($maxQuantity, 3)) {
$fail(__('The quantity must not be greater than the available quantity.')); $fail(__('The quantity must not be greater than the available quantity.'));
} }
} }
Generated
+55 -55
View File
@@ -62,16 +62,16 @@
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.325.0", "version": "3.325.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "ea36e53745cff21519c2dadd808e2482f0bfadf5" "reference": "de0b289c7260fb19301ffa2eb724de2076daad74"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ea36e53745cff21519c2dadd808e2482f0bfadf5", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/de0b289c7260fb19301ffa2eb724de2076daad74",
"reference": "ea36e53745cff21519c2dadd808e2482f0bfadf5", "reference": "de0b289c7260fb19301ffa2eb724de2076daad74",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -154,9 +154,9 @@
"support": { "support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues", "issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.325.0" "source": "https://github.com/aws/aws-sdk-php/tree/3.325.3"
}, },
"time": "2024-10-30T18:11:21+00:00" "time": "2024-11-06T19:05:22+00:00"
}, },
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@@ -999,20 +999,20 @@
}, },
{ {
"name": "ezyang/htmlpurifier", "name": "ezyang/htmlpurifier",
"version": "v4.17.0", "version": "v4.18.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git", "url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c" "reference": "cb56001e54359df7ae76dc522d08845dc741621b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/bbc513d79acf6691fa9cf10f192c90dd2957f18c", "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b",
"reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c", "reference": "cb56001e54359df7ae76dc522d08845dc741621b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
}, },
"require-dev": { "require-dev": {
"cerdic/css-tidy": "^1.7 || ^2.0", "cerdic/css-tidy": "^1.7 || ^2.0",
@@ -1054,9 +1054,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues", "issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.17.0" "source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0"
}, },
"time": "2023-11-17T15:01:25+00:00" "time": "2024-11-01T03:51:45+00:00"
}, },
{ {
"name": "finnhub/client", "name": "finnhub/client",
@@ -3780,20 +3780,20 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "3.8.0", "version": "3.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/briannesbitt/Carbon.git", "url": "https://github.com/briannesbitt/Carbon.git",
"reference": "bbd3eef89af8ba66a3aa7952b5439168fbcc529f" "reference": "10ac0aa86b8062219ce21e8189123d611ca3ecd9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bbd3eef89af8ba66a3aa7952b5439168fbcc529f", "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/10ac0aa86b8062219ce21e8189123d611ca3ecd9",
"reference": "bbd3eef89af8ba66a3aa7952b5439168fbcc529f", "reference": "10ac0aa86b8062219ce21e8189123d611ca3ecd9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"carbonphp/carbon-doctrine-types": "*", "carbonphp/carbon-doctrine-types": "<100.0",
"ext-json": "*", "ext-json": "*",
"php": "^8.1", "php": "^8.1",
"psr/clock": "^1.0", "psr/clock": "^1.0",
@@ -3882,7 +3882,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-08-19T06:22:39+00:00" "time": "2024-11-03T16:02:24+00:00"
}, },
{ {
"name": "nette/schema", "name": "nette/schema",
@@ -6115,16 +6115,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v7.1.6", "version": "v7.1.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "bb5192af6edc797cbab5c8e8ecfea2fe5f421e57" "reference": "3284aafcac338b6e86fd955ee4d794cbe434151a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/bb5192af6edc797cbab5c8e8ecfea2fe5f421e57", "url": "https://api.github.com/repos/symfony/console/zipball/3284aafcac338b6e86fd955ee4d794cbe434151a",
"reference": "bb5192af6edc797cbab5c8e8ecfea2fe5f421e57", "reference": "3284aafcac338b6e86fd955ee4d794cbe434151a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -6188,7 +6188,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v7.1.6" "source": "https://github.com/symfony/console/tree/v7.1.7"
}, },
"funding": [ "funding": [
{ {
@@ -6204,7 +6204,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-10-09T08:46:59+00:00" "time": "2024-11-05T15:34:55+00:00"
}, },
{ {
"name": "symfony/css-selector", "name": "symfony/css-selector",
@@ -6340,16 +6340,16 @@
}, },
{ {
"name": "symfony/error-handler", "name": "symfony/error-handler",
"version": "v7.1.6", "version": "v7.1.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/error-handler.git", "url": "https://github.com/symfony/error-handler.git",
"reference": "d60117093c2a9fe667baa8fedf84e8a09b9c592f" "reference": "010e44661f4c6babaf8c4862fe68c24a53903342"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/d60117093c2a9fe667baa8fedf84e8a09b9c592f", "url": "https://api.github.com/repos/symfony/error-handler/zipball/010e44661f4c6babaf8c4862fe68c24a53903342",
"reference": "d60117093c2a9fe667baa8fedf84e8a09b9c592f", "reference": "010e44661f4c6babaf8c4862fe68c24a53903342",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -6395,7 +6395,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code", "description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/error-handler/tree/v7.1.6" "source": "https://github.com/symfony/error-handler/tree/v7.1.7"
}, },
"funding": [ "funding": [
{ {
@@ -6411,7 +6411,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-09-25T14:20:29+00:00" "time": "2024-11-05T15:34:55+00:00"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
@@ -6635,16 +6635,16 @@
}, },
{ {
"name": "symfony/http-foundation", "name": "symfony/http-foundation",
"version": "v7.1.6", "version": "v7.1.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-foundation.git", "url": "https://github.com/symfony/http-foundation.git",
"reference": "3d7bbf071b25f802f7d55524d408bed414ea71e2" "reference": "5183b61657807099d98f3367bcccb850238b17a9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/3d7bbf071b25f802f7d55524d408bed414ea71e2", "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5183b61657807099d98f3367bcccb850238b17a9",
"reference": "3d7bbf071b25f802f7d55524d408bed414ea71e2", "reference": "5183b61657807099d98f3367bcccb850238b17a9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -6692,7 +6692,7 @@
"description": "Defines an object-oriented layer for the HTTP specification", "description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/http-foundation/tree/v7.1.6" "source": "https://github.com/symfony/http-foundation/tree/v7.1.7"
}, },
"funding": [ "funding": [
{ {
@@ -6708,20 +6708,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-10-11T19:23:14+00:00" "time": "2024-11-06T09:02:46+00:00"
}, },
{ {
"name": "symfony/http-kernel", "name": "symfony/http-kernel",
"version": "v7.1.6", "version": "v7.1.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-kernel.git", "url": "https://github.com/symfony/http-kernel.git",
"reference": "5d8315899cd76b2e7e29179bf5fea103e41bdf03" "reference": "7f137cda31fd41e422edcdc01915f2c095b84399"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/5d8315899cd76b2e7e29179bf5fea103e41bdf03", "url": "https://api.github.com/repos/symfony/http-kernel/zipball/7f137cda31fd41e422edcdc01915f2c095b84399",
"reference": "5d8315899cd76b2e7e29179bf5fea103e41bdf03", "reference": "7f137cda31fd41e422edcdc01915f2c095b84399",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -6806,7 +6806,7 @@
"description": "Provides a structured process for converting a Request into a Response", "description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/http-kernel/tree/v7.1.6" "source": "https://github.com/symfony/http-kernel/tree/v7.1.7"
}, },
"funding": [ "funding": [
{ {
@@ -6822,7 +6822,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-10-27T13:54:21+00:00" "time": "2024-11-06T09:54:34+00:00"
}, },
{ {
"name": "symfony/mailer", "name": "symfony/mailer",
@@ -7626,16 +7626,16 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v7.1.6", "version": "v7.1.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "6aaa189ddb4ff6b5de8fa3210f2fb42c87b4d12e" "reference": "9b8a40b7289767aa7117e957573c2a535efe6585"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/6aaa189ddb4ff6b5de8fa3210f2fb42c87b4d12e", "url": "https://api.github.com/repos/symfony/process/zipball/9b8a40b7289767aa7117e957573c2a535efe6585",
"reference": "6aaa189ddb4ff6b5de8fa3210f2fb42c87b4d12e", "reference": "9b8a40b7289767aa7117e957573c2a535efe6585",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -7667,7 +7667,7 @@
"description": "Executes commands in sub-processes", "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/process/tree/v7.1.6" "source": "https://github.com/symfony/process/tree/v7.1.7"
}, },
"funding": [ "funding": [
{ {
@@ -7683,7 +7683,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-09-25T14:20:29+00:00" "time": "2024-11-06T09:25:12+00:00"
}, },
{ {
"name": "symfony/routing", "name": "symfony/routing",
@@ -8184,16 +8184,16 @@
}, },
{ {
"name": "symfony/var-dumper", "name": "symfony/var-dumper",
"version": "v7.1.6", "version": "v7.1.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/var-dumper.git",
"reference": "cb5bd55a6b8c2c1c7fb68b0aeae0e257948a720c" "reference": "f6ea51f669760cacd7464bf7eaa0be87b8072db1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/cb5bd55a6b8c2c1c7fb68b0aeae0e257948a720c", "url": "https://api.github.com/repos/symfony/var-dumper/zipball/f6ea51f669760cacd7464bf7eaa0be87b8072db1",
"reference": "cb5bd55a6b8c2c1c7fb68b0aeae0e257948a720c", "reference": "f6ea51f669760cacd7464bf7eaa0be87b8072db1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -8247,7 +8247,7 @@
"dump" "dump"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.1.6" "source": "https://github.com/symfony/var-dumper/tree/v7.1.7"
}, },
"funding": [ "funding": [
{ {
@@ -8263,7 +8263,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-09-25T14:20:29+00:00" "time": "2024-11-05T15:34:55+00:00"
}, },
{ {
"name": "tijsverkoyen/css-to-inline-styles", "name": "tijsverkoyen/css-to-inline-styles",
@@ -36,7 +36,7 @@ new class extends Component {
'symbol' => ['required', 'string', new SymbolValidationRule], 'symbol' => ['required', 'string', new SymbolValidationRule],
'transaction_type' => 'required|string|in:BUY,SELL', 'transaction_type' => 'required|string|in:BUY,SELL',
'portfolio_id' => 'required|exists:portfolios,id', 'portfolio_id' => 'required|exists:portfolios,id',
'date' => 'required|date_format:Y-m-d', 'date' => ['required', 'date_format:Y-m-d', 'before_or_equal:' . now()->format('Y-m-d')],
'quantity' => [ 'quantity' => [
'required', 'required',
'numeric', 'numeric',
@@ -83,14 +83,14 @@ new class extends Component {
public function save() public function save()
{ {
$this->authorize('fullAccess', $this->portfolio);
$validated = $this->validate();
if (!isset($this->portfolio)) { if (!isset($this->portfolio)) {
$this->portfolio = Portfolio::find($this->portfolio_id); $this->portfolio = Portfolio::find($this->portfolio_id);
} }
$this->authorize('fullAccess', $this->portfolio);
$validated = $this->validate();
$transaction = $this->portfolio->transactions()->create($validated); $transaction = $this->portfolio->transactions()->create($validated);
$transaction->save(); $transaction->save();
+1 -1
View File
@@ -12,7 +12,7 @@ use Laravel\Jetstream\Http\Controllers\Livewire\PrivacyPolicyController;
use Laravel\Jetstream\Http\Controllers\Livewire\TermsOfServiceController; use Laravel\Jetstream\Http\Controllers\Livewire\TermsOfServiceController;
Route::get('/', function () { Route::get('/', function () {
if (config('investbrain.self_hosted', false) && View::exists('landing-page::index')) { if (!config('investbrain.self_hosted', true) && View::exists('landing-page::index')) {
return view('landing-page::index'); return view('landing-page::index');
} }