mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-18 18:44:16 +00:00
Compare commits
193 Commits
4.8.1.6
...
5.0.0-alph
Author | SHA1 | Date | |
---|---|---|---|
|
fb9ac50828 | ||
|
206ae5a3f3 | ||
|
1120fef4d6 | ||
|
8bcb4432c7 | ||
|
df01db1a51 | ||
|
72bf04fe54 | ||
|
d5416bad7c | ||
|
952c9aad23 | ||
|
1b1d510bc0 | ||
|
fc8400cdf9 | ||
|
c23f16739c | ||
|
ecdefab086 | ||
|
a416b682e0 | ||
|
dfca5b8722 | ||
|
4111973a06 | ||
|
af063191ab | ||
|
1a37d3735b | ||
|
01c3236fed | ||
|
dcd6a8d79f | ||
|
a4d3dba662 | ||
|
2a110185a1 | ||
|
be2794406c | ||
|
b4af70421d | ||
|
7431e18e4b | ||
|
cc936e68f2 | ||
|
18ed19c9d9 | ||
|
83dd170dcb | ||
|
adb32ceed8 | ||
|
91172611d4 | ||
|
e2a30b3cc1 | ||
|
689850c55c | ||
|
6ad2021739 | ||
|
e96e96e6c9 | ||
|
126dd5176e | ||
|
4abedb58aa | ||
|
94194d497f | ||
|
d29ec707b4 | ||
|
96e0357328 | ||
|
883acc698e | ||
|
0387d7c9a3 | ||
|
c5bed5e042 | ||
|
b6ec5073e0 | ||
|
969ae4c551 | ||
|
df649c5871 | ||
|
450433f12e | ||
|
4bab045d6f | ||
|
31744440e0 | ||
|
78ccca4f58 | ||
|
53d630ef91 | ||
|
670c4c6dc3 | ||
|
1e7de48f59 | ||
|
55175da316 | ||
|
916aff425a | ||
|
6a7a0e2b25 | ||
|
eeb68c1cf4 | ||
|
73d56c41d6 | ||
|
3a775627b5 | ||
|
702acafc59 | ||
|
11c04cb0d4 | ||
|
47a8e28948 | ||
|
c9702fe65c | ||
|
8ce3f8dc60 | ||
|
7daedc6c5a | ||
|
1ff855ce66 | ||
|
c3f721aa9f | ||
|
575b355837 | ||
|
813bb6a09b | ||
|
a4b1c9d8c5 | ||
|
98bd35e767 | ||
|
e485f8ca66 | ||
|
4551dfe0e5 | ||
|
709411e7b4 | ||
|
420b996870 | ||
|
4304c15ffe | ||
|
36e643e5b8 | ||
|
fcf3691b2b | ||
|
3ec15a3b7b | ||
|
4ae7501114 | ||
|
5e348e7a40 | ||
|
24fe611645 | ||
|
402a6fa4c7 | ||
|
308ce15fae | ||
|
9a639d41b4 | ||
|
fc7cb987ff | ||
|
ba5ac35330 | ||
|
e2e8ae5b28 | ||
|
4ad0e120bc | ||
|
cd2e74a476 | ||
|
07623335f7 | ||
|
6b2b2aa1e1 | ||
|
414c4a742d | ||
|
55e2f31531 | ||
|
99c9a0fec5 | ||
|
075c06fb86 | ||
|
9293674131 | ||
|
e9172033bb | ||
|
e54dc4c1b4 | ||
|
fcd6b89a43 | ||
|
67db25b2cf | ||
|
68863abbc7 | ||
|
26a4b6844e | ||
|
292fb3fbc8 | ||
|
501efe507f | ||
|
adc48ce094 | ||
|
2a934edf4f | ||
|
4b9d1d23ca | ||
|
8a9e12c2b9 | ||
|
88f1adf650 | ||
|
8ce156cf93 | ||
|
6843c81114 | ||
|
f82d0dda0a | ||
|
d2a8f969d9 | ||
|
c79ded2012 | ||
|
765e4e3c3b | ||
|
3c25148f3f | ||
|
dc0e8528c8 | ||
|
34e7455d67 | ||
|
9332808d7f | ||
|
16a4adcd07 | ||
|
140ccbce3f | ||
|
97c8594dc4 | ||
|
adc4b00f5d | ||
|
c1bdb629a8 | ||
|
d8807e6ab7 | ||
|
e3418b1bd2 | ||
|
a7a76e32d6 | ||
|
1294705809 | ||
|
bb449e1940 | ||
|
828b9d32aa | ||
|
a67b0f78a4 | ||
|
5177f2bc87 | ||
|
f06e947706 | ||
|
380f59dab2 | ||
|
c558bc3247 | ||
|
25378b3f9a | ||
|
abf84e94b1 | ||
|
8baf29b835 | ||
|
d709a9489d | ||
|
33ce7c0767 | ||
|
ec54ec22f6 | ||
|
706e722c6f | ||
|
58ec0c4add | ||
|
88692f0058 | ||
|
a8af0fa678 | ||
|
0bdd48ffec | ||
|
766a82a983 | ||
|
d749d550ee | ||
|
2ea1852a94 | ||
|
4f44a42655 | ||
|
26ed00e7b5 | ||
|
51f25b2dce | ||
|
3fc653687c | ||
|
4cd824f3b7 | ||
|
a6af263b50 | ||
|
0844278eca | ||
|
1b63bfc3db | ||
|
a4906a2d21 | ||
|
c4256dd25b | ||
|
091ab17fdb | ||
|
02ddb95cf2 | ||
|
f2d43d71ad | ||
|
af611b78de | ||
|
724a1b8b08 | ||
|
34e70c7446 | ||
|
01f869f1b6 | ||
|
73a6db8eda | ||
|
0bbc008848 | ||
|
5e61fa785e | ||
|
c131e6ad9b | ||
|
cbc92d89e1 | ||
|
9a028d5002 | ||
|
bed182cf13 | ||
|
d5afba6137 | ||
|
6b4b69b695 | ||
|
b528fa2e5d | ||
|
f4b9f81e71 | ||
|
ca37d782ed | ||
|
f7c34db39b | ||
|
0d072b4ed9 | ||
|
13a29a66c8 | ||
|
cfd9828438 | ||
|
b4d565400e | ||
|
be0e2bf6a7 | ||
|
64a2f22b13 | ||
|
778e0bcbae | ||
|
92a1f12f6c | ||
|
ea0a440de0 | ||
|
92271ffe66 | ||
|
0499433cea | ||
|
dcdecfbc64 | ||
|
8b11afb83f | ||
|
6823adc976 | ||
|
2cf000a9fd |
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# build image
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "develop" ]; then
|
||||
echo "Build develop amd64"
|
||||
docker build -t jc5x/firefly-iii:develop-amd64 -f Dockerfile.amd64 .
|
||||
docker tag jc5x/firefly-iii:develop-amd64 jc5x/firefly-iii:develop-$VERSION-amd64
|
||||
docker push jc5x/firefly-iii:develop-amd64
|
||||
docker push jc5x/firefly-iii:develop-$VERSION-amd64
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||
echo "Build master amd64"
|
||||
docker build -t jc5x/firefly-iii:latest-amd64 -f Dockerfile.amd64 .
|
||||
docker tag jc5x/firefly-iii:latest-amd64 jc5x/firefly-iii:release-$VERSION-amd64
|
||||
docker push jc5x/firefly-iii:latest-amd64
|
||||
docker push jc5x/firefly-iii:release-$VERSION-amd64
|
||||
fi
|
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
|
||||
# get qemu-arm-static binary
|
||||
mkdir tmp
|
||||
pushd tmp && \
|
||||
curl -L -o qemu-arm-static.tar.gz https://github.com/multiarch/qemu-user-static/releases/download/v2.6.0/qemu-arm-static.tar.gz && \
|
||||
tar xzf qemu-arm-static.tar.gz && \
|
||||
popd
|
||||
|
||||
# build image
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "develop" ]; then
|
||||
echo "Build develop arm"
|
||||
docker build --tag jc5x/firefly-iii:develop-arm --file Dockerfile.arm .
|
||||
docker tag jc5x/firefly-iii:develop-arm jc5x/firefly-iii:develop-$VERSION-arm
|
||||
docker push jc5x/firefly-iii:develop-arm
|
||||
docker push jc5x/firefly-iii:develop-$VERSION-arm
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||
echo "Build master arm"
|
||||
docker build --tag jc5x/firefly-iii:latest-arm --file Dockerfile.arm .
|
||||
docker tag jc5x/firefly-iii:latest-arm jc5x/firefly-iii:release-$VERSION-arm
|
||||
docker push jc5x/firefly-iii:latest-arm
|
||||
docker push jc5x/firefly-iii:release-$VERSION-arm
|
||||
fi
|
@@ -18,12 +18,12 @@ mkdir -p $FIREFLY_PATH/storage/framework/views/v2
|
||||
mkdir -p $FIREFLY_PATH/storage/logs
|
||||
mkdir -p $FIREFLY_PATH/storage/upload
|
||||
|
||||
|
||||
echo "Touch DB file (if SQLlite)..."
|
||||
if [[ $DB_CONNECTION == "sqlite" ]]
|
||||
then
|
||||
if [[ $DKR_CHECK_SQLITE != "false" ]]; then
|
||||
echo "Touch DB file (if SQLlite)..."
|
||||
if [[ $DB_CONNECTION == "sqlite" ]]; then
|
||||
touch $FIREFLY_PATH/storage/database/database.sqlite
|
||||
echo "Touched!"
|
||||
fi
|
||||
fi
|
||||
|
||||
# make sure we own the volumes:
|
||||
@@ -41,7 +41,7 @@ composer dump-autoload
|
||||
echo "Discover packages..."
|
||||
php artisan package:discover
|
||||
|
||||
echo "Run various artisan commands..."
|
||||
echo "Wait for the database."
|
||||
if [[ -z "$DB_PORT" ]]; then
|
||||
if [[ $DB_CONNECTION == "pgsql" ]]; then
|
||||
DB_PORT=5432
|
||||
@@ -50,54 +50,108 @@ if [[ -z "$DB_PORT" ]]; then
|
||||
fi
|
||||
fi
|
||||
if [[ ! -z "$DB_PORT" ]]; then
|
||||
$FIREFLY_PATH/.deploy/docker/wait-for-it.sh "${DB_HOST}:${DB_PORT}" -- echo "db is up. Time to execute artisan commands"
|
||||
$FIREFLY_PATH/.deploy/docker/wait-for-it.sh "${DB_HOST}:${DB_PORT}" -t 60 -- echo "DB is up. Time to execute artisan commands."
|
||||
fi
|
||||
#env $(grep -v "^\#" .env | xargs)
|
||||
|
||||
echo "Run various artisan commands..."
|
||||
|
||||
php artisan cache:clear
|
||||
php artisan migrate --seed
|
||||
php artisan firefly-iii:decrypt-all
|
||||
|
||||
if [[ $DKR_RUN_MIGRATION == "false" ]]; then
|
||||
echo "Will NOT run migration commands."
|
||||
fi
|
||||
|
||||
if [[ $DKR_RUN_MIGRATION != "false" ]]; then
|
||||
echo "Running migration commands..."
|
||||
php artisan firefly-iii:create-database
|
||||
php artisan migrate --seed --no-interaction --force
|
||||
php artisan firefly-iii:decrypt-all
|
||||
fi
|
||||
|
||||
# there are 13 upgrade commands
|
||||
php artisan firefly-iii:transaction-identifiers
|
||||
php artisan firefly-iii:migrate-to-groups
|
||||
php artisan firefly-iii:account-currencies
|
||||
php artisan firefly-iii:transfer-currencies
|
||||
php artisan firefly-iii:other-currencies
|
||||
php artisan firefly-iii:migrate-notes
|
||||
php artisan firefly-iii:migrate-attachments
|
||||
php artisan firefly-iii:bills-to-rules
|
||||
php artisan firefly-iii:bl-currency
|
||||
php artisan firefly-iii:cc-liabilities
|
||||
php artisan firefly-iii:back-to-journals
|
||||
php artisan firefly-iii:rename-account-meta
|
||||
php artisan firefly-iii:migrate-recurrence-meta
|
||||
if [[ $DKR_RUN_UPGRADE == "false" ]]; then
|
||||
echo 'Will NOT run upgrade commands.'
|
||||
fi
|
||||
|
||||
if [[ $DKR_RUN_UPGRADE != "false" ]]; then
|
||||
echo 'Running upgrade commands...'
|
||||
php artisan firefly-iii:transaction-identifiers
|
||||
php artisan firefly-iii:migrate-to-groups
|
||||
php artisan firefly-iii:account-currencies
|
||||
php artisan firefly-iii:transfer-currencies
|
||||
php artisan firefly-iii:other-currencies
|
||||
php artisan firefly-iii:migrate-notes
|
||||
php artisan firefly-iii:migrate-attachments
|
||||
php artisan firefly-iii:bills-to-rules
|
||||
php artisan firefly-iii:bl-currency
|
||||
php artisan firefly-iii:cc-liabilities
|
||||
php artisan firefly-iii:back-to-journals
|
||||
php artisan firefly-iii:rename-account-meta
|
||||
php artisan firefly-iii:migrate-recurrence-meta
|
||||
fi
|
||||
|
||||
# there are 15 verify commands
|
||||
php artisan firefly-iii:fix-piggies
|
||||
php artisan firefly-iii:create-link-types
|
||||
php artisan firefly-iii:create-access-tokens
|
||||
php artisan firefly-iii:remove-bills
|
||||
php artisan firefly-iii:enable-currencies
|
||||
php artisan firefly-iii:fix-transfer-budgets
|
||||
php artisan firefly-iii:fix-uneven-amount
|
||||
php artisan firefly-iii:delete-zero-amount
|
||||
php artisan firefly-iii:delete-orphaned-transactions
|
||||
php artisan firefly-iii:delete-empty-journals
|
||||
php artisan firefly-iii:delete-empty-groups
|
||||
php artisan firefly-iii:fix-account-types
|
||||
php artisan firefly-iii:rename-meta-fields
|
||||
php artisan firefly-iii:fix-ob-currencies
|
||||
php artisan firefly-iii:fix-long-descriptions
|
||||
if [[ $DKR_RUN_VERIFY == "false" ]]; then
|
||||
echo 'Will NOT run verification commands.'
|
||||
fi
|
||||
|
||||
if [[ $DKR_RUN_VERIFY != "false" ]]; then
|
||||
echo 'Running verification commands...'
|
||||
php artisan firefly-iii:fix-piggies
|
||||
php artisan firefly-iii:create-link-types
|
||||
php artisan firefly-iii:create-access-tokens
|
||||
php artisan firefly-iii:remove-bills
|
||||
php artisan firefly-iii:enable-currencies
|
||||
php artisan firefly-iii:fix-transfer-budgets
|
||||
php artisan firefly-iii:fix-uneven-amount
|
||||
php artisan firefly-iii:delete-zero-amount
|
||||
php artisan firefly-iii:delete-orphaned-transactions
|
||||
php artisan firefly-iii:delete-empty-journals
|
||||
php artisan firefly-iii:delete-empty-groups
|
||||
php artisan firefly-iii:fix-account-types
|
||||
php artisan firefly-iii:rename-meta-fields
|
||||
php artisan firefly-iii:fix-ob-currencies
|
||||
php artisan firefly-iii:fix-long-descriptions
|
||||
fi
|
||||
|
||||
# report commands
|
||||
php artisan firefly-iii:report-empty-objects
|
||||
php artisan firefly-iii:report-sum
|
||||
if [[ $DKR_RUN_REPORT == "false" ]]; then
|
||||
echo 'Will NOT run report commands.'
|
||||
fi
|
||||
|
||||
if [[ $DKR_RUN_REPORT != "false" ]]; then
|
||||
echo 'Running report commands...'
|
||||
php artisan firefly-iii:report-empty-objects
|
||||
php artisan firefly-iii:report-sum
|
||||
fi
|
||||
|
||||
|
||||
php artisan firefly-iii:restore-oauth-keys
|
||||
|
||||
php artisan passport:install
|
||||
if [[ $DKR_RUN_REPORT == "false" ]]; then
|
||||
echo 'Will NOT generate new OAuth keys.'
|
||||
fi
|
||||
|
||||
if [[ $DKR_RUN_PASSPORT_INSTALL != "false" ]]; then
|
||||
echo 'Generating new OAuth keys...'
|
||||
php artisan passport:install
|
||||
fi
|
||||
|
||||
php artisan firefly-iii:set-latest-version --james-is-cool
|
||||
php artisan cache:clear
|
||||
|
||||
# make sure we own everything
|
||||
echo "Run chown on ${FIREFLY_PATH}"
|
||||
chown -R www-data:www-data -R $FIREFLY_PATH
|
||||
|
||||
php artisan firefly:instructions install
|
||||
|
||||
echo "DKR_CHECK_SQLITE '$DKR_CHECK_SQLITE'"
|
||||
echo "DKR_RUN_MIGRATION '$DKR_RUN_MIGRATION'"
|
||||
echo "DKR_RUN_UPGRADE '$DKR_RUN_UPGRADE'"
|
||||
echo "DKR_RUN_VERIFY '$DKR_RUN_VERIFY'"
|
||||
echo "DKR_RUN_REPORT '$DKR_RUN_REPORT'"
|
||||
echo "DKR_RUN_PASSPORT_INSTALL '$DKR_RUN_PASSPORT_INSTALL'"
|
||||
|
||||
echo "Go!"
|
||||
exec apache2-foreground
|
||||
|
@@ -1,35 +1,162 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "develop" ]; then
|
||||
echo '{"experimental":true}' | sudo tee /etc/docker/daemon.json
|
||||
mkdir $HOME/.docker
|
||||
touch $HOME/.docker/config.json
|
||||
echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
|
||||
sudo service docker restart
|
||||
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
|
||||
VERSION_TARGET=jc5x/firefly-iii:release-$VERSION
|
||||
|
||||
# if the github branch is develop, only push the 'develop' tag
|
||||
if [ $TRAVIS_BRANCH == "develop" ]; then
|
||||
TARGET=jc5x/firefly-iii:develop
|
||||
ARM=jc5x/firefly-iii:develop-arm
|
||||
AMD=jc5x/firefly-iii:develop-amd64
|
||||
ARM32=jc5x/firefly-iii:develop-arm
|
||||
ARM64=jc5x/firefly-iii:develop-arm64
|
||||
AMD64=jc5x/firefly-iii:develop-amd64
|
||||
|
||||
docker manifest create $TARGET $AMD $ARM
|
||||
docker manifest annotate $TARGET $ARM --arch arm --os linux
|
||||
docker manifest annotate $TARGET $AMD --arch amd64 --os linux
|
||||
echo "GitHub branch is $TRAVIS_BRANCH."
|
||||
echo "Push develop-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
fi
|
||||
|
||||
echo "The version is $VERSION"
|
||||
# if branch = master AND channel = alpha, push 'alpha'
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "alpha" ]; then
|
||||
TARGET=jc5x/firefly-iii:alpha
|
||||
ARM32=jc5x/firefly-iii:alpha-arm
|
||||
ARM64=jc5x/firefly-iii:alpha-arm64
|
||||
AMD64=jc5x/firefly-iii:alpha-amd64
|
||||
|
||||
echo "GitHub branch is $TRAVIS_BRANCH."
|
||||
echo "Channel is $CHANNEL."
|
||||
echo "Push alpha-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
echo "Push alpha-* builds to $VERSION_TARGET"
|
||||
|
||||
docker manifest create $VERSION_TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $VERSION_TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $VERSION_TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $VERSION_TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $VERSION_TARGET
|
||||
|
||||
fi
|
||||
|
||||
# if branch is master and channel is alpha, push 'alpha' and 'beta'.
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "beta" ]; then
|
||||
TARGET=jc5x/firefly-iii:alpha
|
||||
ARM32=jc5x/firefly-iii:beta-arm
|
||||
ARM64=jc5x/firefly-iii:beta-arm64
|
||||
AMD64=jc5x/firefly-iii:beta-amd64
|
||||
|
||||
echo "GitHub branch is $TRAVIS_BRANCH."
|
||||
echo "Channel is $CHANNEL."
|
||||
echo "Push beta-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
TARGET=jc5x/firefly-iii:beta
|
||||
ARM32=jc5x/firefly-iii:beta-arm
|
||||
ARM64=jc5x/firefly-iii:beta-arm64
|
||||
AMD64=jc5x/firefly-iii:beta-amd64
|
||||
|
||||
echo "Push beta-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
echo "Push beta-* builds to $VERSION_TARGET"
|
||||
|
||||
docker manifest create $VERSION_TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $VERSION_TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $VERSION_TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $VERSION_TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $VERSION_TARGET
|
||||
fi
|
||||
|
||||
# if branch is master and channel is stable, push 'alpha' and 'beta' and 'stable'.
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "stable" ]; then
|
||||
TARGET=jc5x/firefly-iii:alpha
|
||||
ARM32=jc5x/firefly-iii:stable-arm
|
||||
ARM64=jc5x/firefly-iii:stable-arm64
|
||||
AMD64=jc5x/firefly-iii:stable-amd64
|
||||
|
||||
echo "GitHub branch is $TRAVIS_BRANCH."
|
||||
echo "Channel is $CHANNEL."
|
||||
echo "Push stable-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
TARGET=jc5x/firefly-iii:beta
|
||||
ARM32=jc5x/firefly-iii:stable-arm
|
||||
ARM64=jc5x/firefly-iii:stable-arm64
|
||||
AMD64=jc5x/firefly-iii:stable-amd64
|
||||
|
||||
echo "Push stable-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
TARGET=jc5x/firefly-iii:stable
|
||||
ARM32=jc5x/firefly-iii:stable-arm
|
||||
ARM64=jc5x/firefly-iii:stable-arm64
|
||||
AMD64=jc5x/firefly-iii:stable-amd64
|
||||
|
||||
echo "Push stable-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||
TARGET=jc5x/firefly-iii:latest
|
||||
ARM=jc5x/firefly-iii:latest-arm
|
||||
AMD=jc5x/firefly-iii:latest-amd64
|
||||
ARM32=jc5x/firefly-iii:stable-arm
|
||||
ARM64=jc5x/firefly-iii:stable-arm64
|
||||
AMD64=jc5x/firefly-iii:stable-amd64
|
||||
|
||||
docker manifest create $TARGET $AMD $ARM
|
||||
docker manifest annotate $TARGET $ARM --arch arm --os linux
|
||||
docker manifest annotate $TARGET $AMD --arch amd64 --os linux
|
||||
echo "Push stable-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
# and another one for version specific:
|
||||
TARGET=jc5x/firefly-iii:release-$VERSION
|
||||
ARM=jc5x/firefly-iii:release-$VERSION-arm
|
||||
AMD=jc5x/firefly-iii:release-$VERSION-amd64
|
||||
echo "Push stable-* builds to $VERSION_TARGET"
|
||||
|
||||
docker manifest create $TARGET $AMD $ARM
|
||||
docker manifest annotate $TARGET $ARM --arch arm --os linux
|
||||
docker manifest annotate $TARGET $AMD --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
docker manifest create $VERSION_TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $VERSION_TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $VERSION_TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $VERSION_TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $VERSION_TARGET
|
||||
fi
|
||||
|
||||
echo 'Done!'
|
||||
# done!
|
103
.deploy/docker/travis.sh
Executable file
103
.deploy/docker/travis.sh
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "travis.sh: I am building channel ${CHANNEL} for version ${VERSION} on architecture ${ARCH}, branch $TRAVIS_BRANCH."
|
||||
|
||||
echo '{"experimental":true}' | sudo tee /etc/docker/daemon.json
|
||||
mkdir $HOME/.docker
|
||||
touch $HOME/.docker/config.json
|
||||
echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
|
||||
sudo service docker restart
|
||||
|
||||
# First build amd64 image:
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
|
||||
if [ $ARCH == "arm" ]; then
|
||||
echo "Because architecture is $ARCH running some extra commands."
|
||||
docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
|
||||
# get qemu-arm-static binary
|
||||
mkdir tmp
|
||||
pushd tmp && \
|
||||
curl -L -o qemu-arm-static.tar.gz https://github.com/multiarch/qemu-user-static/releases/download/v2.6.0/qemu-arm-static.tar.gz && \
|
||||
tar xzf qemu-arm-static.tar.gz && \
|
||||
popd
|
||||
fi
|
||||
|
||||
# if the github branch is develop, build and push develop. Don't push a version tag anymore.
|
||||
if [ $TRAVIS_BRANCH == "develop" ]; then
|
||||
LABEL=jc5x/firefly-iii:develop-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH. Will build and push $LABEL"
|
||||
docker build -t $LABEL -f Dockerfile.$ARCH .
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
# if branch = master AND channel = alpha, build and push 'alpha'
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "alpha" ]; then
|
||||
LABEL=jc5x/firefly-iii:alpha-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will build and push $LABEL"
|
||||
docker build -t $LABEL -f Dockerfile.$ARCH .
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
# if branch is master and channel is alpha, build and push 'alpha' and 'beta'.
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "beta" ]; then
|
||||
LABEL=jc5x/firefly-iii:beta-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will build and push $LABEL"
|
||||
docker build -t $LABEL -f Dockerfile.$ARCH .
|
||||
docker push $LABEL
|
||||
|
||||
# then tag as alpha and push:
|
||||
docker tag $LABEL jc5x/firefly-iii:alpha-$ARCH
|
||||
docker push jc5x/firefly-iii:alpha-$ARCH
|
||||
echo "Also tagged $LABEL as jc5x/firefly-iii:alpha-$ARCH and pushed"
|
||||
fi
|
||||
|
||||
# if branch is master and channel is stable, push 'alpha' and 'beta' and 'stable'.
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "stable" ]; then
|
||||
# first build stable
|
||||
LABEL=jc5x/firefly-iii:stable-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will build and push $LABEL"
|
||||
docker build -t $LABEL -f Dockerfile.$ARCH .
|
||||
docker push $LABEL
|
||||
|
||||
# then tag as beta and push:
|
||||
docker tag $LABEL jc5x/firefly-iii:beta-$ARCH
|
||||
docker push jc5x/firefly-iii:beta-$ARCH
|
||||
echo "Also tagged $LABEL as jc5x/firefly-iii:beta-$ARCH and pushed"
|
||||
|
||||
# then tag as alpha and push:
|
||||
docker tag $LABEL jc5x/firefly-iii:alpha-$ARCH
|
||||
docker push jc5x/firefly-iii:alpha-$ARCH
|
||||
echo "Also tagged $LABEL as jc5x/firefly-iii:alpha-$ARCH and pushed"
|
||||
|
||||
# then tag as latest and push:
|
||||
docker tag $LABEL jc5x/firefly-iii:latest-$ARCH
|
||||
docker push jc5x/firefly-iii:latest-$ARCH
|
||||
echo "Also tagged $LABEL as jc5x/firefly-iii:latest-$ARCH and pushed"
|
||||
fi
|
||||
|
||||
# push to channel 'version' if master + alpha
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "alpha"]; then
|
||||
LABEL=jc5x/firefly-iii:version-$VERSION-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will also push alpha as $LABEL"
|
||||
docker tag jc5x/firefly-iii:alpha-$ARCH $LABEL
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
# push to channel 'version' if master + beta
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "beta"]; then
|
||||
LABEL=jc5x/firefly-iii:version-$VERSION-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will also push beta as $LABEL"
|
||||
docker tag jc5x/firefly-iii:beta-$ARCH $LABEL
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
# push to channel 'version' if master + stable
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "stable"]; then
|
||||
LABEL=jc5x/firefly-iii:version-$VERSION-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will also push beta as $LABEL"
|
||||
docker tag jc5x/firefly-iii:stable-$ARCH $LABEL
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
echo "Done!"
|
@@ -1,26 +0,0 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
|
||||
server_name _ *.vm docker;
|
||||
|
||||
root "/app/public";
|
||||
index index.php;
|
||||
|
||||
include /opt/docker/etc/nginx/vhost.common.d/*.conf;
|
||||
}
|
||||
|
||||
##############
|
||||
# SSL
|
||||
##############
|
||||
|
||||
server {
|
||||
listen 443 default_server;
|
||||
|
||||
server_name _ *.vm docker;
|
||||
|
||||
root "/app/public";
|
||||
index index.php;
|
||||
|
||||
include /opt/docker/etc/nginx/vhost.common.d/*.conf;
|
||||
include /opt/docker/etc/nginx/vhost.ssl.conf;
|
||||
}
|
@@ -11,4 +11,5 @@ pt_BR
|
||||
ro_RO
|
||||
ru_RU
|
||||
hu_HU
|
||||
el_GR
|
||||
el_GR
|
||||
sv_SE
|
||||
|
99
.deploy/kubernetes/firefly-iii.yaml
Normal file
99
.deploy/kubernetes/firefly-iii.yaml
Normal file
@@ -0,0 +1,99 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: firefly-iii
|
||||
labels:
|
||||
app: firefly-iii
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
selector:
|
||||
app: firefly-iii
|
||||
tier: frontend
|
||||
type: LoadBalancer
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: firefly-iii-export-claim
|
||||
labels:
|
||||
app: firefly-iii
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: firefly-iii-upload-claim
|
||||
labels:
|
||||
app: firefly-iii
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: firefly-iii
|
||||
labels:
|
||||
app: firefly-iii
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: firefly-iii
|
||||
tier: frontend
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: firefly-iii
|
||||
tier: frontend
|
||||
spec:
|
||||
containers:
|
||||
- image: jc5x/firefly-iii
|
||||
name: firefly-iii
|
||||
env:
|
||||
- name: APP_ENV
|
||||
value: "local"
|
||||
- name: APP_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: firefly-iii-secrets
|
||||
key: app_key
|
||||
- name: DB_HOST
|
||||
value: firefly-iii-mysql
|
||||
- name: DB_CONNECTION
|
||||
value: mysql
|
||||
- name: DB_DATABASE
|
||||
value: "fireflyiii"
|
||||
- name: DB_USERNAME
|
||||
value: "root"
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: firefly-iii-secrets
|
||||
key: db_password
|
||||
ports:
|
||||
- containerPort: 80
|
||||
name: firefly-iii
|
||||
volumeMounts:
|
||||
- mountPath: "/var/www/firefly-iii/storage/export"
|
||||
name: firefly-iii-export
|
||||
- mountPath: "/var/www/firefly-iii/storage/upload"
|
||||
name: firefly-iii-upload
|
||||
imagePullPolicy: Always
|
||||
volumes:
|
||||
- name: firefly-iii-export
|
||||
persistentVolumeClaim:
|
||||
claimName: firefly-iii-export-claim
|
||||
- name: firefly-iii-upload
|
||||
persistentVolumeClaim:
|
||||
claimName: firefly-iii-upload-claim
|
@@ -1,82 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: mysql-pv-export-claim
|
||||
labels:
|
||||
app: firefly-local
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: mysql-pv-upload-claim
|
||||
labels:
|
||||
app: firefly-local
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
---
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: firefly-local
|
||||
namespace: firefly
|
||||
labels:
|
||||
app: firefly-local
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: firefly-local
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: firefly-local
|
||||
spec:
|
||||
containers:
|
||||
- image: firefly-local
|
||||
name: firefly-local
|
||||
env:
|
||||
- name: APP_ENV
|
||||
value: "local"
|
||||
- name: APP_KEY
|
||||
value: "S0m3R@nd0mString0f32Ch@rsEx@ct1y"
|
||||
- name: DB_HOST
|
||||
value: "172.17.0.9"
|
||||
- name: DB_NAME
|
||||
value: "firefly_db"
|
||||
- name: DB_USER
|
||||
value: "firefly_db"
|
||||
- name: DB_PASSWORD
|
||||
value: "password"
|
||||
volumeMounts:
|
||||
- mountPath: "/var/www/firefly-iii/storage/export"
|
||||
name: mysql-persistent-export
|
||||
- mountPath: "/var/www/firefly-iii/storage/upload"
|
||||
name: mysql-persistent-upload
|
||||
imagePullPolicy: IfNotPresent
|
||||
volumes:
|
||||
- name: mysql-persistent-export
|
||||
persistentVolumeClaim:
|
||||
claimName: mysql-pv-export-claim
|
||||
- name: mysql-persistent-upload
|
||||
persistentVolumeClaim:
|
||||
claimName: mysql-pv-upload-claim
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: firefly-local
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
type: NodePort
|
||||
selector:
|
||||
app: firefly-local
|
8
.deploy/kubernetes/kustomization.yaml
Normal file
8
.deploy/kubernetes/kustomization.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
resources:
|
||||
- mysql.yaml
|
||||
- firefly-iii.yaml
|
||||
secretGenerator:
|
||||
- name: firefly-iii-secrets
|
||||
literals:
|
||||
- db_password=CHANGEMECHANGEME
|
||||
- app_key=CHANGEMECHANGEMECHANGEMECHANGEME
|
65
.deploy/kubernetes/mysql.yaml
Normal file
65
.deploy/kubernetes/mysql.yaml
Normal file
@@ -0,0 +1,65 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: firefly-iii-mysql
|
||||
labels:
|
||||
app: firefly-iii
|
||||
spec:
|
||||
ports:
|
||||
- port: 3306
|
||||
selector:
|
||||
app: firefly-iii
|
||||
tier: mysql
|
||||
clusterIP: None
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: mysql-pv-claim
|
||||
labels:
|
||||
app: firefly-iii
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: firefly-iii-mysql
|
||||
labels:
|
||||
app: firefly-iii
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: firefly-iii
|
||||
tier: mysql
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: firefly-iii
|
||||
tier: mysql
|
||||
spec:
|
||||
containers:
|
||||
- image: mysql:5.6
|
||||
name: mysql
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: firefly-iii-secrets
|
||||
key: db_password
|
||||
ports:
|
||||
- containerPort: 3306
|
||||
name: mysql
|
||||
volumeMounts:
|
||||
- name: mysql-persistent-storage
|
||||
mountPath: /var/lib/mysql
|
||||
volumes:
|
||||
- name: mysql-persistent-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: mysql-pv-claim
|
@@ -1,49 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: sql-pass
|
||||
type: Opaque
|
||||
data:
|
||||
password: cGFzc3dvcmQ=
|
||||
---
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mysql
|
||||
namespace: firefly
|
||||
labels:
|
||||
app: mysql
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: mysql
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: mysql
|
||||
spec:
|
||||
containers:
|
||||
- image: mysql
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: mysql
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: sql-pass
|
||||
key: password
|
||||
ports:
|
||||
- containerPort: 3306
|
||||
name: mysql
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mysql
|
||||
spec:
|
||||
ports:
|
||||
- port: 3306
|
||||
type: NodePort
|
||||
selector:
|
||||
app: mysql
|
||||
|
65
.env.example
65
.env.example
@@ -26,10 +26,13 @@ APP_URL=http://localhost
|
||||
TRUSTED_PROXIES=
|
||||
|
||||
# The log channel defines where your log entries go to.
|
||||
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
|
||||
# - Docker + versions <= 4.8.1.8 and before: use "stdout"
|
||||
# - Docker + versions > 4.8.1.8: use "docker_out"
|
||||
# - For everything else, use 'daily'
|
||||
|
||||
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
|
||||
# Also available are 'syslog', 'errorlog' and 'stdout' which will log to the system itself.
|
||||
LOG_CHANNEL=daily
|
||||
LOG_CHANNEL=stdout
|
||||
|
||||
# Log level. You can set this from least severe to most severe:
|
||||
# debug, info, notice, warning, error, critical, alert, emergency
|
||||
@@ -38,7 +41,7 @@ LOG_CHANNEL=daily
|
||||
APP_LOG_LEVEL=notice
|
||||
|
||||
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
|
||||
# For other database types, please see the FAQ: http://firefly-iii.readthedocs.io/en/latest/support/faq.html
|
||||
# For other database types, please see the FAQ: https://docs.firefly-iii.org/support/faq
|
||||
DB_CONNECTION=pgsql
|
||||
DB_HOST=firefly_iii_db
|
||||
DB_PORT=5432
|
||||
@@ -57,18 +60,12 @@ PGSQL_SSL_CRL_FILE=null
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
# You can configure another file storage backend if you cannot use the local storage option.
|
||||
# To set this up, fill in the following variables. The upload path is used to store uploaded
|
||||
# files and the export path is to store exported data (before download).
|
||||
SFTP_HOST=
|
||||
SFTP_PORT=
|
||||
SFTP_UPLOAD_PATH=
|
||||
SFTP_EXPORT_PATH=
|
||||
|
||||
# SFTP uses either the username/password combination or the private key to authenticate.
|
||||
SFTP_USERNAME=
|
||||
SFTP_PASSWORD=
|
||||
SFTP_PRIV_KEY=
|
||||
# If you set either of these to 'redis', you might want to update these settings too
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
REDIS_DB="0" # always use quotes
|
||||
REDIS_CACHE_DB="1"
|
||||
|
||||
# Cookie settings. Should not be necessary to change these.
|
||||
COOKIE_PATH="/"
|
||||
@@ -76,7 +73,7 @@ COOKIE_DOMAIN=
|
||||
COOKIE_SECURE=false
|
||||
|
||||
# If you want Firefly III to mail you, update these settings
|
||||
# For instructions, see: https://firefly-iii.readthedocs.io/en/latest/installation/mail.html
|
||||
# For instructions, see: https://docs.firefly-iii.org/advanced-installation/email
|
||||
MAIL_DRIVER=log
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
@@ -121,7 +118,7 @@ ANALYTICS_ID=
|
||||
# Firefly III has two options for user authentication. "eloquent" is the default,
|
||||
# and "ldap" for LDAP servers.
|
||||
# For full instructions on these settings please visit:
|
||||
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
|
||||
# https://docs.firefly-iii.org/advanced-installation/authentication
|
||||
LOGIN_PROVIDER=eloquent
|
||||
|
||||
# LDAP connection configuration
|
||||
@@ -162,15 +159,42 @@ ADLDAP_SYNC_FIELD=userprincipalname
|
||||
# Organizr. This is at your own risk.
|
||||
DISABLE_FRAME_HEADER=false
|
||||
|
||||
# You can fine tune the start-up of a Docker container by editing these environment variables.
|
||||
# Use this at your own risk. Disabling certain checks and features may result in lost of inconsistent data.
|
||||
# However if you know what you're doing you can significantly speed up container start times.
|
||||
# Set each value to true to enable, or false to disable.
|
||||
|
||||
# Check if the SQLite database exists. Can be skipped if you're not using SQLite.
|
||||
# Won't significantly speed up things.
|
||||
DKR_CHECK_SQLITE=true
|
||||
|
||||
# Run database creation and migration commands. Disable this only if you're 100% sure the DB exists
|
||||
# and is up to date.
|
||||
DKR_RUN_MIGRATION=true
|
||||
|
||||
# Run database upgrade commands. Disable this only when you're 100% sure your DB is up-to-date
|
||||
# with the latest fixes (outside of migrations!)
|
||||
DKR_RUN_UPGRADE=true
|
||||
|
||||
# Verify database integrity. Includes all data checks and verifications.
|
||||
# Disabling this makes Firefly III assume your DB is intact.
|
||||
DKR_RUN_VERIFY=true
|
||||
|
||||
# Run database reporting commands. When disabled, Firefly III won't go over your data to report current state.
|
||||
# Disabling this should have no impact on data integrity or safety but it won't warn you of possible issues.
|
||||
DKR_RUN_REPORT=true
|
||||
|
||||
# Generate OAuth2 keys.
|
||||
# When disabled, Firefly III won't attempt to generate OAuth2 Passport keys. This won't be an issue, IFF (if and only if)
|
||||
# you had previously generated keys already and they're stored in your database for restauration.
|
||||
DKR_RUN_PASSPORT_INSTALL=true
|
||||
|
||||
# Leave the following configuration vars as is.
|
||||
# Unless you like to tinker and know what you're doing.
|
||||
APP_NAME=FireflyIII
|
||||
ADLDAP_CONNECTION=default
|
||||
BROADCAST_DRIVER=log
|
||||
QUEUE_DRIVER=sync
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
CACHE_PREFIX=firefly
|
||||
SEARCH_RESULT_LIMIT=50
|
||||
PUSHER_KEY=
|
||||
@@ -180,6 +204,7 @@ DEMO_USERNAME=
|
||||
DEMO_PASSWORD=
|
||||
USE_ENCRYPTION=false
|
||||
IS_SANDSTORM=false
|
||||
IS_DOCKER=false
|
||||
IS_HEROKU=false
|
||||
BUNQ_USE_SANDBOX=false
|
||||
FFIII_LAYOUT=v1
|
||||
|
5
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
5
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -7,7 +7,7 @@ about: Create a report to help Firefly III improve
|
||||
**Bug description**
|
||||
I am running Firefly III version x.x.x, and my problem is:
|
||||
|
||||
<!-- Replace the version and describe your problem or your issue will be closed. -->
|
||||
<!-- Replace the version and describe your problem or your issue may be closed. -->
|
||||
|
||||
**Steps to reproduce**
|
||||
<!-- What do you need to do to trigger this bug? -->
|
||||
@@ -20,4 +20,7 @@ I am running Firefly III version x.x.x, and my problem is:
|
||||
|
||||
- Post a stacktrace from your log files
|
||||
- Add a screenshot
|
||||
- Make a drawing
|
||||
- Donate money (just kidding ;)
|
||||
- Replicate the problem on the demo site https://demo.firefly-iii.org/
|
||||
-->
|
1
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
1
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
@@ -28,5 +28,4 @@ Please describe your feature request:
|
||||
|
||||
- Make a drawing
|
||||
- Donate money (just kidding ;)
|
||||
- Remember the human
|
||||
-->
|
8
.github/ranger.yml
vendored
8
.github/ranger.yml
vendored
@@ -1,8 +0,0 @@
|
||||
# in .github/ranger.yml
|
||||
comments:
|
||||
-
|
||||
action: delete_comment
|
||||
pattern: 1
|
||||
-
|
||||
action: delete_comment
|
||||
pattern: ":+1:"
|
2
.github/stale.yml
vendored
2
.github/stale.yml
vendored
@@ -13,8 +13,6 @@ exemptLabels:
|
||||
- enhancement
|
||||
- feature
|
||||
- bug
|
||||
- possible-bug
|
||||
- "possible bug"
|
||||
- announcement
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
|
39
.travis.yml
39
.travis.yml
@@ -1,9 +1,5 @@
|
||||
sudo: required
|
||||
language: bash
|
||||
env:
|
||||
- VERSION=4.8.1.6
|
||||
|
||||
dist: xenial
|
||||
|
||||
# safelist
|
||||
branches:
|
||||
@@ -14,16 +10,25 @@ branches:
|
||||
services:
|
||||
- docker
|
||||
|
||||
script:
|
||||
# enable experimental features.
|
||||
- echo '{"experimental":true}' | sudo tee /etc/docker/daemon.json
|
||||
- mkdir $HOME/.docker
|
||||
- touch $HOME/.docker/config.json
|
||||
- echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
|
||||
- sudo service docker restart
|
||||
- docker version -f '{{.Server.Experimental}}'
|
||||
- docker version
|
||||
# build everything
|
||||
- .deploy/docker/build-amd64.sh
|
||||
- .deploy/docker/build-arm.sh
|
||||
- .deploy/docker/manifest.sh
|
||||
jobs:
|
||||
include:
|
||||
- dist: xenial
|
||||
arch: amd64
|
||||
env: ARCH=amd64 CHANNEL=alpha VERSION=5.0.0-alpha.1
|
||||
stage: build
|
||||
script: ./.deploy/docker/travis.sh
|
||||
- dist: xenial
|
||||
arch: amd64
|
||||
env: ARCH=arm CHANNEL=alpha VERSION=5.0.0-alpha.1
|
||||
stage: build
|
||||
script: ./.deploy/docker/travis.sh
|
||||
- dist: xenial
|
||||
arch: arm64
|
||||
env: ARCH=arm64 CHANNEL=alpha VERSION=5.0.0-alpha.1
|
||||
stage: build
|
||||
script: ./.deploy/docker/travis.sh
|
||||
- dist: xenial
|
||||
arch: amd64
|
||||
env: CHANNEL=alpha VERSION=5.0.0-alpha.1
|
||||
stage: manifest
|
||||
script: ./.deploy/docker/manifest.sh
|
@@ -3,7 +3,7 @@ FROM jc5x/firefly-iii-base-image:latest
|
||||
# See also: https://github.com/JC5/firefly-iii-base-image
|
||||
|
||||
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
|
||||
LABEL version="1.5" maintainer="thegrumpydictator@gmail.com"
|
||||
LABEL version="1.6" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
# Create volumes
|
||||
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
|
||||
|
@@ -3,7 +3,7 @@ FROM jc5x/firefly-iii-base-image:latest
|
||||
# See also: https://github.com/JC5/firefly-iii-base-image
|
||||
|
||||
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
|
||||
LABEL version="1.5" maintainer="thegrumpydictator@gmail.com"
|
||||
LABEL version="1.6" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
# Create volumes
|
||||
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
|
||||
|
@@ -3,7 +3,7 @@ FROM jc5x/firefly-iii-base-image:latest-arm
|
||||
# See also: https://github.com/JC5/firefly-iii-base-image
|
||||
|
||||
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
|
||||
LABEL version="1.5" maintainer="thegrumpydictator@gmail.com"
|
||||
LABEL version="1.6" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
# Create volumes
|
||||
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
|
||||
|
@@ -1,25 +1,13 @@
|
||||
FROM arm32v7/php:7.2-apache-stretch
|
||||
ARG ARCH
|
||||
COPY tmp/qemu-arm-static /usr/bin/qemu-arm-static
|
||||
FROM jc5x/firefly-iii-base-image:latest-arm
|
||||
|
||||
# See also: https://github.com/JC5/firefly-iii-base-image
|
||||
|
||||
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
|
||||
LABEL version="1.5" maintainer="thegrumpydictator@gmail.com"
|
||||
LABEL version="1.6" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
# Create volumes
|
||||
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
|
||||
|
||||
# Install stuff Firefly III runs with & depends on: php extensions, locales, dev headers and composer
|
||||
RUN apt-get update && apt-get install -y locales unzip && apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ADD https://raw.githubusercontent.com/mlocati/docker-php-extension-installer/master/install-php-extensions /usr/local/bin/
|
||||
|
||||
RUN chmod uga+x /usr/local/bin/install-php-extensions && sync && \
|
||||
install-php-extensions --cleanup bcmath ldap gd pdo_pgsql pdo_sqlite pdo_mysql intl opcache memcached
|
||||
|
||||
RUN a2enmod rewrite && a2enmod ssl
|
||||
RUN echo "hu_HU.UTF-8 UTF-8\nro_RO.UTF-8 UTF-8\nnb_NO.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8\ncs_CZ.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nes_ES.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\nzh_TW.UTF-8 UTF-8\nzh_CN.UTF-8 UTF-8\n\n" > /etc/locale.gen
|
||||
RUN locale-gen
|
||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
# Copy in Firefly III source
|
||||
WORKDIR $FIREFLY_PATH
|
||||
ADD . $FIREFLY_PATH
|
||||
@@ -29,15 +17,6 @@ RUN chown -R www-data:www-data /var/www && \
|
||||
chmod -R 775 $FIREFLY_PATH/storage && \
|
||||
composer install --prefer-dist --no-dev --no-scripts --no-suggest
|
||||
|
||||
# copy ca certs to correct location
|
||||
COPY ./.deploy/docker/cacert.pem /usr/local/ssl/cert.pem
|
||||
|
||||
# copy Apache config to correct spot.
|
||||
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
|
||||
|
||||
# Enable default site (Firefly III)
|
||||
COPY ./.deploy/docker/apache-firefly.conf /etc/apache2/sites-available/000-default.conf
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
|
@@ -98,15 +98,15 @@ class AttachmentController extends Controller
|
||||
public function download(Attachment $attachment): LaravelResponse
|
||||
{
|
||||
if (false === $attachment->uploaded) {
|
||||
throw new FireflyException('No file has been uploaded for this attachment (yet).');
|
||||
throw new FireflyException('200000: File has not been uploaded (yet).');
|
||||
}
|
||||
if (0 === $attachment->size) {
|
||||
throw new FireflyException('No file has been uploaded for this attachment (yet).');
|
||||
throw new FireflyException('200000: File has not been uploaded (yet).');
|
||||
}
|
||||
if ($this->repository->exists($attachment)) {
|
||||
$content = $this->repository->getContent($attachment);
|
||||
if ('' === $content) {
|
||||
throw new FireflyException('No file has been uploaded for this attachment (yet).');
|
||||
throw new FireflyException('200002: File is empty (zero bytes).');
|
||||
}
|
||||
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
|
||||
|
||||
@@ -125,7 +125,7 @@ class AttachmentController extends Controller
|
||||
|
||||
return $response;
|
||||
}
|
||||
throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');
|
||||
throw new FireflyException('200003: File does not exist.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -211,20 +211,16 @@ class BillController extends Controller
|
||||
*/
|
||||
public function store(BillRequest $request): JsonResponse
|
||||
{
|
||||
$bill = $this->repository->store($request->getAll());
|
||||
if (null !== $bill) {
|
||||
$manager = $this->getManager();
|
||||
$bill = $this->repository->store($request->getAll());
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($bill, $transformer, 'bills');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
throw new FireflyException('Could not store new bill.'); // @codeCoverageIgnore
|
||||
$resource = new Item($bill, $transformer, 'bills');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -187,19 +187,16 @@ class BudgetController extends Controller
|
||||
*/
|
||||
public function store(BudgetRequest $request): JsonResponse
|
||||
{
|
||||
$budget = $this->repository->store($request->getAll());
|
||||
if (null !== $budget) {
|
||||
$manager = $this->getManager();
|
||||
$budget = $this->repository->store($request->getAll());
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($budget, $transformer, 'budgets');
|
||||
$resource = new Item($budget, $transformer, 'budgets');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
throw new FireflyException('Could not store new budget.'); // @codeCoverageIgnore
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -165,7 +165,7 @@ class BudgetLimitController extends Controller
|
||||
$data = $request->getAll();
|
||||
$budget = $this->repository->findNull($data['budget_id']);
|
||||
if (null === $budget) {
|
||||
throw new FireflyException('Unknown budget.');
|
||||
throw new FireflyException('200004: Budget does not exist.');
|
||||
}
|
||||
$data['budget'] = $budget;
|
||||
$budgetLimit = $this->blRepository->storeBudgetLimit($data);
|
||||
|
@@ -152,18 +152,15 @@ class CategoryController extends Controller
|
||||
public function store(CategoryRequest $request): JsonResponse
|
||||
{
|
||||
$category = $this->repository->store($request->getAll());
|
||||
if (null !== $category) {
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var CategoryTransformer $transformer */
|
||||
$transformer = app(CategoryTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
/** @var CategoryTransformer $transformer */
|
||||
$transformer = app(CategoryTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($category, $transformer, 'categories');
|
||||
$resource = new Item($category, $transformer, 'categories');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
throw new FireflyException('Could not store new category.'); // @codeCoverageIgnore
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -57,7 +57,7 @@ class ConfigurationController extends Controller
|
||||
$admin = auth()->user();
|
||||
|
||||
if (!$this->repository->hasRole($admin, 'owner')) {
|
||||
throw new FireflyException('No access to method.'); // @codeCoverageIgnore
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
@@ -313,10 +313,10 @@ class CurrencyController extends Controller
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
// access denied:
|
||||
throw new FireflyException('No access to method, user is not owner.'); // @codeCoverageIgnore
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
|
||||
}
|
||||
if ($this->repository->currencyInUse($currency)) {
|
||||
throw new FireflyException('No access to method, currency is in use.'); // @codeCoverageIgnore
|
||||
throw new FireflyException('200006: Currency in use.'); // @codeCoverageIgnore
|
||||
}
|
||||
$this->repository->destroy($currency);
|
||||
|
||||
@@ -574,26 +574,21 @@ class CurrencyController extends Controller
|
||||
public function store(CurrencyRequest $request): JsonResponse
|
||||
{
|
||||
$currency = $this->repository->store($request->getAll());
|
||||
|
||||
if (null !== $currency) {
|
||||
if (true === $request->boolean('default')) {
|
||||
app('preferences')->set('currencyPreference', $currency->code);
|
||||
app('preferences')->mark();
|
||||
}
|
||||
$manager = $this->getManager();
|
||||
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
|
||||
$this->parameters->set('defaultCurrency', $defaultCurrency);
|
||||
|
||||
/** @var CurrencyTransformer $transformer */
|
||||
$transformer = app(CurrencyTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($currency, $transformer, 'currencies');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
if (true === $request->boolean('default')) {
|
||||
app('preferences')->set('currencyPreference', $currency->code);
|
||||
app('preferences')->mark();
|
||||
}
|
||||
throw new FireflyException('Could not store new currency.'); // @codeCoverageIgnore
|
||||
$manager = $this->getManager();
|
||||
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
|
||||
$this->parameters->set('defaultCurrency', $defaultCurrency);
|
||||
|
||||
/** @var CurrencyTransformer $transformer */
|
||||
$transformer = app(CurrencyTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($currency, $transformer, 'currencies');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -79,10 +79,10 @@ class CurrencyExchangeRateController extends Controller
|
||||
$toCurrency = $this->repository->findByCodeNull($request->get('to') ?? 'USD');
|
||||
|
||||
if (null === $fromCurrency) {
|
||||
throw new FireflyException('Unknown source currency.');
|
||||
throw new FireflyException('200007: Unknown source currency');
|
||||
}
|
||||
if (null === $toCurrency) {
|
||||
throw new FireflyException('Unknown destination currency.');
|
||||
throw new FireflyException('200007: Unknown destination currency');
|
||||
}
|
||||
|
||||
/** @var Carbon $dateObj */
|
||||
|
@@ -86,7 +86,7 @@ class LinkTypeController extends Controller
|
||||
public function delete(LinkType $linkType): JsonResponse
|
||||
{
|
||||
if (false === $linkType->editable) {
|
||||
throw new FireflyException(sprintf('You cannot delete this link type (#%d, "%s")', $linkType->id, $linkType->name));
|
||||
throw new FireflyException('200020: Link type cannot be changed.');
|
||||
}
|
||||
$this->repository->destroy($linkType);
|
||||
|
||||
@@ -160,7 +160,7 @@ class LinkTypeController extends Controller
|
||||
$admin = auth()->user();
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
throw new FireflyException('You need the "owner"-role to do this.');
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
|
||||
}
|
||||
$data = $request->getAll();
|
||||
// if currency ID is 0, find the currency by the code:
|
||||
@@ -247,14 +247,14 @@ class LinkTypeController extends Controller
|
||||
public function update(LinkTypeRequest $request, LinkType $linkType): JsonResponse
|
||||
{
|
||||
if (false === $linkType->editable) {
|
||||
throw new FireflyException(sprintf('You cannot edit this link type (#%d, "%s")', $linkType->id, $linkType->name));
|
||||
throw new FireflyException('200020: Link type cannot be changed.');
|
||||
}
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
throw new FireflyException('You need the "owner"-role to do this.');
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$data = $request->getAll();
|
||||
|
@@ -181,19 +181,15 @@ class PiggyBankController extends Controller
|
||||
public function store(PiggyBankRequest $request): JsonResponse
|
||||
{
|
||||
$piggyBank = $this->repository->store($request->getAll());
|
||||
if (null !== $piggyBank) {
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($piggyBank, $transformer, 'piggy_banks');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
throw new FireflyException('Could not store new piggy bank.');
|
||||
$resource = new Item($piggyBank, $transformer, 'piggy_banks');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -236,7 +236,7 @@ class RecurrenceController extends Controller
|
||||
$result = $recurring->fire();
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
throw new FireflyException('Could not fire recurring cron job.');
|
||||
throw new FireflyException('200022: Error in cron job.');
|
||||
}
|
||||
if (false === $result) {
|
||||
return response()->json([], 204);
|
||||
|
@@ -257,7 +257,7 @@ class RuleGroupController extends Controller
|
||||
/** @var Collection $rules */
|
||||
$rules = $this->ruleGroupRepository->getActiveRules($group);
|
||||
if (0 === $rules->count()) {
|
||||
throw new FireflyException('No rules in this rule group.');
|
||||
throw new FireflyException('200023: No rules in this rule group.');
|
||||
}
|
||||
$parameters = $request->getTestParameters();
|
||||
$matchingTransactions = [];
|
||||
|
116
app/Api/V1/Controllers/Search/TransferController.php
Normal file
116
app/Api/V1/Controllers/Search/TransferController.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* TransferController.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Search;
|
||||
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Search\TransferRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Support\Search\TransferSearch;
|
||||
use FireflyIII\Transformers\TransactionGroupTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
|
||||
/**
|
||||
* Class TransferController
|
||||
*/
|
||||
class TransferController extends Controller
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse|Response
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function search(TransferRequest $request)
|
||||
{
|
||||
// configure transfer search to search for a > b
|
||||
$search = app(TransferSearch::class);
|
||||
$search->setSource($request->get('source'));
|
||||
$search->setDestination($request->get('destination'));
|
||||
$search->setAmount($request->get('amount'));
|
||||
$search->setDescription($request->get('description'));
|
||||
$search->setDate($request->get('date'));
|
||||
|
||||
$left = $search->search();
|
||||
|
||||
// configure transfer search to search for b > a
|
||||
$search->setSource($request->get('destination'));
|
||||
$search->setDestination($request->get('source'));
|
||||
$search->setAmount($request->get('amount'));
|
||||
$search->setDescription($request->get('description'));
|
||||
$search->setDate($request->get('date'));
|
||||
|
||||
$right = $search->search();
|
||||
|
||||
// add parameters to URL:
|
||||
$this->parameters->set('source', $request->get('source'));
|
||||
$this->parameters->set('destination', $request->get('destination'));
|
||||
$this->parameters->set('amount', $request->get('amount'));
|
||||
$this->parameters->set('description', $request->get('description'));
|
||||
$this->parameters->set('date', $request->get('date'));
|
||||
|
||||
// get all journal ID's.
|
||||
$total = $left->merge($right)->unique('id')->pluck('id')->toArray();
|
||||
if (0 === count($total)) {
|
||||
// forces search to be empty.
|
||||
$total = [-1];
|
||||
}
|
||||
|
||||
// collector to return results.
|
||||
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
|
||||
$manager = $this->getManager();
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setUser($admin)
|
||||
// all info needed for the API:
|
||||
->withAPIInformation()
|
||||
// set page size:
|
||||
->setLimit($pageSize)
|
||||
// set page to retrieve
|
||||
->setPage(1)
|
||||
->setJournalIds($total);
|
||||
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
$paginator->setPath(route('api.v1.search.transfers') . $this->buildParams());
|
||||
$transactions = $paginator->getCollection();
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($transactions, $transformer, 'transactions');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
}
|
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Requests\TransactionStoreRequest;
|
||||
use FireflyIII\Api\V1\Requests\TransactionUpdateRequest;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -279,7 +280,20 @@ class TransactionController extends Controller
|
||||
Log::channel('audit')
|
||||
->info('Store new transaction over API.', $data);
|
||||
|
||||
$transactionGroup = $this->groupRepository->store($data);
|
||||
try {
|
||||
$transactionGroup = $this->groupRepository->store($data);
|
||||
} catch (DuplicateTransactionException $e) {
|
||||
// return bad validation message.
|
||||
// TODO use Laravel's internal validation thing to do this.
|
||||
$response = [
|
||||
'message' => 'The given data was invalid.',
|
||||
'errors' => [
|
||||
'transactions.0.description' => [$e->getMessage()],
|
||||
],
|
||||
];
|
||||
|
||||
return response()->json($response, 422);
|
||||
}
|
||||
|
||||
event(new StoredTransactionGroup($transactionGroup));
|
||||
|
||||
|
@@ -165,7 +165,7 @@ class TransactionLinkController extends Controller
|
||||
$inward = $this->journalRepository->findNull($data['inward_id'] ?? 0);
|
||||
$outward = $this->journalRepository->findNull($data['outward_id'] ?? 0);
|
||||
if (null === $inward || null === $outward) {
|
||||
throw new FireflyException('Source or destination is NULL.');
|
||||
throw new FireflyException('200024: Source or destination does not exist.');
|
||||
}
|
||||
$data['direction'] = 'inward';
|
||||
|
||||
@@ -196,7 +196,7 @@ class TransactionLinkController extends Controller
|
||||
$data['inward'] = $this->journalRepository->findNull($data['inward_id'] ?? 0);
|
||||
$data['outward'] = $this->journalRepository->findNull($data['outward_id'] ?? 0);
|
||||
if (null === $data['inward'] || null === $data['outward']) {
|
||||
throw new FireflyException('Source or destination is NULL.');
|
||||
throw new FireflyException('200024: Source or destination does not exist.');
|
||||
}
|
||||
$data['direction'] = 'inward';
|
||||
$journalLink = $this->repository->updateLink($journalLink, $data);
|
||||
|
@@ -83,7 +83,7 @@ class UserController extends Controller
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
throw new FireflyException('No access to method.'); // @codeCoverageIgnore
|
||||
throw new FireflyException('200025: No access to function.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* TagsSpaceTest.php
|
||||
* TransferRequest.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
@@ -19,43 +19,40 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Requests\Search;
|
||||
|
||||
namespace Tests\Unit\Import\MapperPreProcess;
|
||||
|
||||
use FireflyIII\Import\MapperPreProcess\TagsSpace;
|
||||
use Log;
|
||||
use Tests\TestCase;
|
||||
use FireflyIII\Api\V1\Requests\Request;
|
||||
use FireflyIII\Rules\IsTransferAccount;
|
||||
|
||||
/**
|
||||
* Class TagsSpaceTest
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
|
||||
* Class TransferRequest
|
||||
*/
|
||||
class TagsSpaceTest extends TestCase
|
||||
class TransferRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Authorize logged in users.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setUp(): void
|
||||
public function authorize(): bool
|
||||
{
|
||||
parent::setUp();
|
||||
Log::info(sprintf('Now in %s.', get_class($this)));
|
||||
// Only allow authenticated users
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \FireflyIII\Import\MapperPreProcess\TagsSpace
|
||||
* @return array
|
||||
*/
|
||||
public function testBasic(): void
|
||||
public function rules(): array
|
||||
{
|
||||
$input = 'some tags with spaces,and without ';
|
||||
$output = ['some', 'tags', 'with', 'spaces,and', 'without'];
|
||||
$mapper = new TagsSpace();
|
||||
$result = $mapper->run($input);
|
||||
|
||||
$this->assertEquals($output, $result);
|
||||
return [
|
||||
'source' => ['required', new IsTransferAccount],
|
||||
'destination' => ['required', new IsTransferAccount],
|
||||
'amount' => 'required|numeric|more:0',
|
||||
'description' => 'required|min:1',
|
||||
'date' => 'required|date',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -58,8 +58,9 @@ class TransactionStoreRequest extends Request
|
||||
public function getAll(): array
|
||||
{
|
||||
$data = [
|
||||
'group_title' => $this->string('group_title'),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
'group_title' => $this->string('group_title'),
|
||||
'error_if_duplicate_hash' => $this->boolean('error_if_duplicate_hash'),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
];
|
||||
|
||||
return $data;
|
||||
@@ -75,6 +76,7 @@ class TransactionStoreRequest extends Request
|
||||
$rules = [
|
||||
// basic fields for group:
|
||||
'group_title' => 'between:1,1000|nullable',
|
||||
'error_if_duplicate_hash' => [new IsBoolean],
|
||||
|
||||
// transaction rules (in array for splits):
|
||||
'transactions.*.type' => 'required|in:withdrawal,deposit,transfer,opening-balance,reconciliation',
|
||||
|
@@ -27,6 +27,7 @@ use Exception;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Console\Command;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class DeleteEmptyGroups
|
||||
@@ -54,6 +55,7 @@ class DeleteEmptyGroups extends Command
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$start = microtime(true);
|
||||
$groupIds =
|
||||
TransactionGroup
|
||||
@@ -61,6 +63,7 @@ class DeleteEmptyGroups extends Command
|
||||
->whereNull('transaction_journals.id')->get(['transaction_groups.id'])->pluck('id')->toArray();
|
||||
|
||||
$total = count($groupIds);
|
||||
Log::debug(sprintf('Count is %d', $total));
|
||||
if ($total > 0) {
|
||||
$this->info(sprintf('Deleted %d empty transaction group(s).', $total));
|
||||
|
||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Console\Command;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class FixAccountTypes
|
||||
@@ -66,6 +67,7 @@ class FixAccountTypes extends Command
|
||||
public function handle(): int
|
||||
{
|
||||
$this->stupidLaravel();
|
||||
Log::debug('Now in fix-account-types');
|
||||
$start = microtime(true);
|
||||
$this->factory = app(AccountFactory::class);
|
||||
// some combinations can be fixed by this script:
|
||||
@@ -88,13 +90,16 @@ class FixAccountTypes extends Command
|
||||
|
||||
$this->expected = config('firefly.source_dests');
|
||||
$journals = TransactionJournal::with(['TransactionType', 'transactions', 'transactions.account', 'transactions.account.accounttype'])->get();
|
||||
Log::debug(sprintf('Found %d journals to fix.', $journals->count()));
|
||||
foreach ($journals as $journal) {
|
||||
$this->inspectJournal($journal);
|
||||
}
|
||||
if (0 === $this->count) {
|
||||
Log::debug('No journals had to be fixed.');
|
||||
$this->info('All account types are OK!');
|
||||
}
|
||||
if (0 !== $this->count) {
|
||||
Log::debug(sprintf('%d journals had to be fixed.', $this->count));
|
||||
$this->info(sprintf('Acted on %d transaction(s)!', $this->count));
|
||||
}
|
||||
|
||||
@@ -223,21 +228,36 @@ class FixAccountTypes extends Command
|
||||
*/
|
||||
private function inspectJournal(TransactionJournal $journal): void
|
||||
{
|
||||
Log::debug(sprintf('Now trying to fix journal #%d', $journal->id));
|
||||
$count = $journal->transactions()->count();
|
||||
if (2 !== $count) {
|
||||
Log::debug(sprintf('Journal has %d transactions, so cant fix.', $count));
|
||||
$this->info(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $count));
|
||||
|
||||
return;
|
||||
}
|
||||
$type = $journal->transactionType->type;
|
||||
$sourceTransaction = $this->getSourceTransaction($journal);
|
||||
$destTransaction = $this->getDestinationTransaction($journal);
|
||||
if (null === $sourceTransaction) {
|
||||
Log::error('Source transaction is unexpectedly NULL. Wont fix this journal.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (null === $destTransaction) {
|
||||
Log::error('Destination transaction is unexpectedly NULL. Wont fix this journal.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$sourceAccount = $sourceTransaction->account;
|
||||
$sourceAccountType = $sourceAccount->accountType->type;
|
||||
$destTransaction = $this->getDestinationTransaction($journal);
|
||||
$destAccount = $destTransaction->account;
|
||||
$destAccountType = $destAccount->accountType->type;
|
||||
|
||||
if (!isset($this->expected[$type])) {
|
||||
// @codeCoverageIgnoreStart
|
||||
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
$this->info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
|
||||
return;
|
||||
|
75
app/Console/Commands/CreateDatabase.php
Normal file
75
app/Console/Commands/CreateDatabase.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
||||
|
||||
/**
|
||||
* Class CreateDatabase
|
||||
*/
|
||||
class CreateDatabase extends Command
|
||||
{
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Tries to create the database if it doesn\'t exist yet.';
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:create-database';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if ('mysql' !== env('DB_CONNECTION')) {
|
||||
$this->info('This command currently applies to MySQL connections only.');
|
||||
}
|
||||
// try to set up a raw connection:
|
||||
$dsn = sprintf('mysql:host=%s;charset=utf8mb4', env('DB_HOST'));
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
try {
|
||||
$pdo = new PDO($dsn, env('DB_USERNAME'), env('DB_PASSWORD'), $options);
|
||||
} catch (PDOException $e) {
|
||||
$this->error(sprintf('Error when connecting to DB: %s', $e->getMessage()));
|
||||
|
||||
return 1;
|
||||
}
|
||||
// with PDO, try to list DB's (
|
||||
$stmt = $pdo->query('SHOW DATABASES;');
|
||||
$exists = false;
|
||||
// slightly more complex but less error prone.
|
||||
foreach ($stmt as $row) {
|
||||
$name = $row['Database'] ?? false;
|
||||
if ($name === env('DB_DATABASE')) {
|
||||
$exists = true;
|
||||
}
|
||||
}
|
||||
if (false === $exists) {
|
||||
$this->error(sprintf('Database "%s" does not exist.', env('DB_DATABASE')));
|
||||
|
||||
// try to create it.
|
||||
$pdo->exec(sprintf('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', env('DB_DATABASE')));
|
||||
$this->info(sprintf('Created database "%s"', env('DB_DATABASE')));
|
||||
|
||||
return 0;
|
||||
}
|
||||
$this->info(sprintf('Database "%s" exists.', env('DB_DATABASE')));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
50
app/Console/Commands/SetLatestVersion.php
Normal file
50
app/Console/Commands/SetLatestVersion.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class SetLatestVersion extends Command
|
||||
{
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:set-latest-version {--james-is-cool}';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (!$this->option('james-is-cool')) {
|
||||
$this->error('Am too!');
|
||||
|
||||
return;
|
||||
}
|
||||
app('fireflyconfig')->set('db_version', config('firefly.db_version'));
|
||||
app('fireflyconfig')->set('ff3_version', config('firefly.version'));
|
||||
$this->line('Updated version.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
31
app/Exceptions/DuplicateTransactionException.php
Normal file
31
app/Exceptions/DuplicateTransactionException.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* DuplicateTransactionException.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class DuplicateTransactionException
|
||||
*/
|
||||
class DuplicateTransactionException extends Exception
|
||||
{
|
||||
|
||||
}
|
@@ -101,6 +101,7 @@ class GracefulNotFoundHandler extends ExceptionHandler
|
||||
break;
|
||||
case 'tags.show.all':
|
||||
case 'tags.show':
|
||||
case 'tags.edit':
|
||||
$request->session()->reflash();
|
||||
|
||||
return redirect(route('tags.index'));
|
||||
|
@@ -24,10 +24,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Services\Internal\Support\BillServiceTrait;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
@@ -55,6 +57,7 @@ class BillFactory
|
||||
* @param array $data
|
||||
*
|
||||
* @return Bill|null
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function create(array $data): ?Bill
|
||||
{
|
||||
@@ -64,28 +67,31 @@ class BillFactory
|
||||
$currency = $factory->find((int)($data['currency_id'] ?? null), (string)($data['currency_code'] ?? null));
|
||||
|
||||
if (null === $currency) {
|
||||
// use default currency:
|
||||
$currency = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||
}
|
||||
try {
|
||||
/** @var Bill $bill */
|
||||
$bill = Bill::create(
|
||||
[
|
||||
'name' => $data['name'],
|
||||
'match' => 'MIGRATED_TO_RULES',
|
||||
'amount_min' => $data['amount_min'],
|
||||
'user_id' => $this->user->id,
|
||||
'transaction_currency_id' => $currency->id,
|
||||
'amount_max' => $data['amount_max'],
|
||||
'date' => $data['date'],
|
||||
'repeat_freq' => $data['repeat_freq'],
|
||||
'skip' => $data['skip'],
|
||||
'automatch' => true,
|
||||
'active' => $data['active'] ?? true,
|
||||
]
|
||||
);
|
||||
} catch(QueryException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('400000: Could not store bill.');
|
||||
}
|
||||
|
||||
/** @var Bill $bill */
|
||||
$bill = Bill::create(
|
||||
[
|
||||
'name' => $data['name'],
|
||||
'match' => 'MIGRATED_TO_RULES',
|
||||
'amount_min' => $data['amount_min'],
|
||||
'user_id' => $this->user->id,
|
||||
'transaction_currency_id' => $currency->id,
|
||||
'amount_max' => $data['amount_max'],
|
||||
'date' => $data['date'],
|
||||
'repeat_freq' => $data['repeat_freq'],
|
||||
'skip' => $data['skip'],
|
||||
'automatch' => true,
|
||||
'active' => $data['active'] ?? true,
|
||||
]
|
||||
);
|
||||
|
||||
// update note:
|
||||
if (isset($data['notes'])) {
|
||||
$this->updateNote($bill, $data['notes']);
|
||||
}
|
||||
|
@@ -24,8 +24,10 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
@@ -62,7 +64,7 @@ class CategoryFactory
|
||||
* @param null|string $categoryName
|
||||
*
|
||||
* @return Category|null
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function findOrCreate(?int $categoryId, ?string $categoryName): ?Category
|
||||
{
|
||||
@@ -88,13 +90,17 @@ class CategoryFactory
|
||||
if (null !== $category) {
|
||||
return $category;
|
||||
}
|
||||
|
||||
return Category::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $categoryName,
|
||||
]
|
||||
);
|
||||
try {
|
||||
return Category::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $categoryName,
|
||||
]
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
Log::error($e->getMessage());
|
||||
throw new FireflyException('400003: Could not store new category.');
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@@ -27,6 +27,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
@@ -51,9 +52,10 @@ class TransactionCurrencyFactory
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
* @return TransactionCurrency
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function create(array $data): ?TransactionCurrency
|
||||
public function create(array $data): TransactionCurrency
|
||||
{
|
||||
try {
|
||||
/** @var TransactionCurrency $currency */
|
||||
@@ -69,6 +71,7 @@ class TransactionCurrencyFactory
|
||||
} catch (QueryException $e) {
|
||||
$result = null;
|
||||
Log::error(sprintf('Could not create new currency: %s', $e->getMessage()));
|
||||
throw new FireflyException('400004: Could not store new currency.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\User;
|
||||
|
||||
@@ -52,10 +53,13 @@ class TransactionGroupFactory
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionGroup
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
public function create(array $data): TransactionGroup
|
||||
{
|
||||
$this->journalFactory->setUser($this->user);
|
||||
$this->journalFactory->setErrorOnHash($data['error_if_duplicate_hash'] ?? false);
|
||||
|
||||
$collection = $this->journalFactory->create($data);
|
||||
$title = $data['group_title'] ?? null;
|
||||
$title = '' === $title ? null : $title;
|
||||
|
@@ -26,10 +26,12 @@ namespace FireflyIII\Factory;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionJournalMeta;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
@@ -72,6 +74,8 @@ class TransactionJournalFactory
|
||||
private $typeRepository;
|
||||
/** @var User The user */
|
||||
private $user;
|
||||
/** @var bool */
|
||||
private $errorOnHash;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -81,7 +85,8 @@ class TransactionJournalFactory
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->fields = [
|
||||
$this->errorOnHash = false;
|
||||
$this->fields = [
|
||||
// sepa
|
||||
'sepa_cc', 'sepa_ct_op', 'sepa_ct_id',
|
||||
'sepa_db', 'sepa_country', 'sepa_ep',
|
||||
@@ -119,6 +124,7 @@ class TransactionJournalFactory
|
||||
* @param array $data
|
||||
*
|
||||
* @return Collection
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
public function create(array $data): Collection
|
||||
{
|
||||
@@ -193,11 +199,15 @@ class TransactionJournalFactory
|
||||
* @param NullArrayObject $row
|
||||
*
|
||||
* @return TransactionJournal|null
|
||||
* @throws Exception
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
private function createJournal(NullArrayObject $row): ?TransactionJournal
|
||||
{
|
||||
$row['import_hash_v2'] = $this->hashArray($row);
|
||||
|
||||
$this->errorIfDuplicate($row['import_hash_v2']);
|
||||
|
||||
/** Some basic fields */
|
||||
$type = $this->typeRepository->findTransactionType(null, $row['type']);
|
||||
$carbon = $row['date'] ?? new Carbon;
|
||||
@@ -322,7 +332,7 @@ class TransactionJournalFactory
|
||||
$transactionFactory->setCurrency($sourceCurrency);
|
||||
$transactionFactory->setForeignCurrency($sourceForeignCurrency);
|
||||
$transactionFactory->setReconciled($row['reconciled'] ?? false);
|
||||
$transactionFactory->createNegative((string)$row['amount'], $row['foreign_amount']);
|
||||
$transactionFactory->createNegative((string)$row['amount'], (string)$row['foreign_amount']);
|
||||
|
||||
// and the destination one:
|
||||
/** @var TransactionFactory $transactionFactory */
|
||||
@@ -333,7 +343,7 @@ class TransactionJournalFactory
|
||||
$transactionFactory->setCurrency($destCurrency);
|
||||
$transactionFactory->setForeignCurrency($destForeignCurrency);
|
||||
$transactionFactory->setReconciled($row['reconciled'] ?? false);
|
||||
$transactionFactory->createPositive((string)$row['amount'], $row['foreign_amount']);
|
||||
$transactionFactory->createPositive((string)$row['amount'], (string)$row['foreign_amount']);
|
||||
|
||||
// verify that journal has two transactions. Otherwise, delete and cancel.
|
||||
// TODO this can't be faked so it can't be tested.
|
||||
@@ -376,6 +386,30 @@ class TransactionJournalFactory
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this transaction already exists, throw an error.
|
||||
*
|
||||
* @param string $hash
|
||||
*
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
private function errorIfDuplicate(string $hash): void
|
||||
{
|
||||
if (false === $this->errorOnHash) {
|
||||
return;
|
||||
}
|
||||
$result = null;
|
||||
if ($this->errorOnHash) {
|
||||
/** @var TransactionJournalMeta $result */
|
||||
$result = TransactionJournalMeta::where('data', json_encode($hash, JSON_THROW_ON_ERROR))
|
||||
->with(['transactionJournal', 'transactionJournal.transactionGroup'])
|
||||
->first();
|
||||
}
|
||||
if (null !== $result) {
|
||||
throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $result->transactionJournal->transaction_group_id));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency|null $currency
|
||||
* @param Account $account
|
||||
@@ -485,4 +519,14 @@ class TransactionJournalFactory
|
||||
throw new FireflyException(sprintf('Destination: %s', $this->accountValidator->destError)); // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $errorOnHash
|
||||
*/
|
||||
public function setErrorOnHash(bool $errorOnHash): void
|
||||
{
|
||||
$this->errorOnHash = $errorOnHash;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Handlers\Events;
|
||||
|
||||
|
||||
use FireflyIII\Events\RequestedVersionCheckStatus;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Update\UpdateTrait;
|
||||
use FireflyIII\Models\Configuration;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
@@ -78,8 +79,15 @@ class VersionCheckEventHandler
|
||||
}
|
||||
// last check time was more than a week ago.
|
||||
Log::debug('Have not checked for a new version in a week!');
|
||||
try {
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e);
|
||||
session()->flash('error', (string)trans('firefly.update_check_error'));
|
||||
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
// softfail.
|
||||
return;
|
||||
}
|
||||
$versionCheck = $this->versionCheck($latestRelease);
|
||||
$resultString = $this->parseResult($versionCheck, $latestRelease);
|
||||
if (0 !== $versionCheck && '' !== $resultString) {
|
||||
|
@@ -70,6 +70,8 @@ class GroupCollector implements GroupCollectorInterface
|
||||
private $total;
|
||||
/** @var User The user object. */
|
||||
private $user;
|
||||
/** @var array */
|
||||
private $integerFields;
|
||||
|
||||
/**
|
||||
* Group collector constructor.
|
||||
@@ -84,7 +86,23 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$this->hasBudgetInformation = false;
|
||||
$this->hasBillInformation = false;
|
||||
$this->hasJoinedTagTables = false;
|
||||
|
||||
$this->integerFields = [
|
||||
'transaction_group_id',
|
||||
'user_id',
|
||||
'transaction_journal_id',
|
||||
'transaction_type_id',
|
||||
'order',
|
||||
'source_transaction_id',
|
||||
'source_account_id',
|
||||
'currency_id',
|
||||
'currency_decimal_places',
|
||||
'foreign_currency_id',
|
||||
'foreign_currency_decimal_places',
|
||||
'destination_transaction_id',
|
||||
'destination_account_id',
|
||||
'category_id',
|
||||
'budget_id'
|
||||
];
|
||||
$this->total = 0;
|
||||
$this->fields = [
|
||||
# group
|
||||
@@ -903,6 +921,22 @@ class GroupCollector implements GroupCollectorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a selected set of fields to arrays.
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function convertToInteger(array $array): array
|
||||
{
|
||||
foreach ($this->integerFields as $field) {
|
||||
$array[$field] = isset($array[$field]) ? (int)$array[$field] : null;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join table to get tag information.
|
||||
*/
|
||||
@@ -965,8 +999,8 @@ class GroupCollector implements GroupCollectorInterface
|
||||
// make new array
|
||||
$parsedGroup = $this->parseAugmentedGroup($augumentedJournal);
|
||||
$groupArray = [
|
||||
'id' => $augumentedJournal->transaction_group_id,
|
||||
'user_id' => $augumentedJournal->user_id,
|
||||
'id' => (int)$augumentedJournal->transaction_group_id,
|
||||
'user_id' => (int)$augumentedJournal->user_id,
|
||||
'title' => $augumentedJournal->transaction_group_title,
|
||||
'transaction_type' => $parsedGroup['transaction_type_type'],
|
||||
'count' => 1,
|
||||
@@ -1014,6 +1048,10 @@ class GroupCollector implements GroupCollectorInterface
|
||||
} catch (Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
}
|
||||
|
||||
// convert values to integers:
|
||||
$result = $this->convertToInteger($result);
|
||||
|
||||
$result['reconciled'] = 1 === (int)$result['reconciled'];
|
||||
if (isset($augumentedJournal['tag_id'])) { // assume the other fields are present as well.
|
||||
$tagId = (int)$augumentedJournal['tag_id'];
|
||||
|
@@ -25,8 +25,7 @@ namespace FireflyIII\Helpers\Update;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Services\Github\Object\Release;
|
||||
use FireflyIII\Services\Github\Request\UpdateRequest;
|
||||
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequestInterface;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
@@ -38,75 +37,54 @@ trait UpdateTrait
|
||||
/**
|
||||
* Get object for the latest release from GitHub.
|
||||
*
|
||||
* @return Release|null
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getLatestRelease(): ?Release
|
||||
public function getLatestRelease(): array
|
||||
{
|
||||
Log::debug('Now in getLatestRelease()');
|
||||
$return = null;
|
||||
/** @var UpdateRequest $request */
|
||||
$request = app(UpdateRequest::class);
|
||||
try {
|
||||
$request->call();
|
||||
} catch (FireflyException $e) {
|
||||
Log::error(sprintf('Could not check for updates: %s', $e->getMessage()));
|
||||
/** @var UpdateRequestInterface $checker */
|
||||
$checker = app(UpdateRequestInterface::class);
|
||||
$channel = app('fireflyconfig')->get('update_channel', 'stable')->data;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// get releases from array.
|
||||
$releases = $request->getReleases();
|
||||
|
||||
Log::debug(sprintf('Found %d releases', count($releases)));
|
||||
|
||||
if (count($releases) > 0) {
|
||||
// first entry should be the latest entry:
|
||||
/** @var Release $first */
|
||||
$first = reset($releases);
|
||||
$return = $first;
|
||||
Log::debug(sprintf('Number of releases found is larger than zero. Return %s ', $first->getTitle()));
|
||||
}
|
||||
|
||||
return $return;
|
||||
return $checker->getVersion($channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the version check result in a human readable sentence.
|
||||
*
|
||||
* @param int $versionCheck
|
||||
* @param Release|null $release
|
||||
* @param int $versionCheck
|
||||
* @param array $information
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function parseResult(int $versionCheck, Release $release = null): string
|
||||
public function parseResult(int $versionCheck, array $information): string
|
||||
{
|
||||
Log::debug(sprintf('Now in parseResult(%d)', $versionCheck));
|
||||
$current = (string)config('firefly.version');
|
||||
$return = '';
|
||||
$triggered = false;
|
||||
if ($versionCheck === -2) {
|
||||
Log::debug('-2, so give error.');
|
||||
$return = (string)trans('firefly.update_check_error');
|
||||
$triggered = true;
|
||||
}
|
||||
if ($versionCheck === -1 && null !== $release) {
|
||||
$triggered = true;
|
||||
Log::debug('New version!');
|
||||
// there is a new FF version!
|
||||
// has it been released for at least three days?
|
||||
$today = new Carbon;
|
||||
$releaseDate = $release->getUpdated();
|
||||
if ($today->diffInDays($releaseDate) > 3) {
|
||||
Log::debug('New version is older than 3 days!');
|
||||
$monthAndDayFormat = (string)trans('config.month_and_day');
|
||||
$return = (string)trans(
|
||||
'firefly.update_new_version_alert',
|
||||
[
|
||||
'your_version' => $current,
|
||||
'new_version' => $release->getTitle(),
|
||||
'date' => $release->getUpdated()->formatLocalized($monthAndDayFormat),
|
||||
]
|
||||
);
|
||||
if (-1 === $versionCheck) {
|
||||
$triggered = true;
|
||||
$monthAndDayFormat = (string)trans('config.month_and_day');
|
||||
$carbon = Carbon::createFromFormat('Y-m-d', $information['date']);
|
||||
$return = (string)trans(
|
||||
'firefly.update_new_version_alert',
|
||||
[
|
||||
'your_version' => $current,
|
||||
'new_version' => $information['version'],
|
||||
'date' => $carbon->formatLocalized($monthAndDayFormat),
|
||||
]
|
||||
);
|
||||
// append warning if beta or alpha.
|
||||
$isBeta = $information['is_beta'] ?? false;
|
||||
if (true === $isBeta) {
|
||||
$return = sprintf('%s %s', $return, trans('firefly.update_version_beta'));
|
||||
}
|
||||
|
||||
$isAlpha = $information['is_alpha'] ?? false;
|
||||
if (true === $isAlpha) {
|
||||
$return = sprintf('%s %s', $return, trans('firefly.update_version_alpha'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,19 +94,16 @@ trait UpdateTrait
|
||||
// you are running the current version!
|
||||
$return = (string)trans('firefly.update_current_version_alert', ['version' => $current]);
|
||||
}
|
||||
if (1 === $versionCheck && null !== $release) {
|
||||
if (1 === $versionCheck) {
|
||||
$triggered = true;
|
||||
Log::debug('User is running NEWER version.');
|
||||
// you are running a newer version!
|
||||
$return = (string)trans('firefly.update_newer_version_alert', ['your_version' => $current, 'new_version' => $release->getTitle()]);
|
||||
$return = (string)trans('firefly.update_newer_version_alert', ['your_version' => $current, 'new_version' => $information['version']]);
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if (false === $triggered) {
|
||||
Log::debug('No option was triggered.');
|
||||
$return = (string)trans('firefly.update_check_error');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $return;
|
||||
}
|
||||
@@ -136,22 +111,16 @@ trait UpdateTrait
|
||||
/**
|
||||
* Compare version and store result.
|
||||
*
|
||||
* @param Release|null $release
|
||||
* @param array $information
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function versionCheck(Release $release = null): int
|
||||
public function versionCheck(array $information): int
|
||||
{
|
||||
Log::debug('Now in versionCheck()');
|
||||
if (null === $release) {
|
||||
Log::debug('Release is null, return -2.');
|
||||
|
||||
return -2;
|
||||
}
|
||||
$current = (string)config('firefly.version');
|
||||
$latest = $release->getTitle();
|
||||
$check = version_compare($current, $latest);
|
||||
Log::debug(sprintf('Comparing %s with %s, result is %s', $current, $latest, $check));
|
||||
$check = version_compare($current, $information['version']);
|
||||
Log::debug(sprintf('Comparing %s with %s, result is %s', $current, $information['version'], $check), $information);
|
||||
|
||||
return $check;
|
||||
}
|
||||
|
@@ -23,10 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Update\UpdateTrait;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Http\Middleware\IsSandStormUser;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
|
||||
@@ -44,7 +46,7 @@ class UpdateController extends Controller
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
static function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.administration'));
|
||||
app('view')->share('mainTitleIcon', 'fa-hand-spock-o');
|
||||
|
||||
@@ -64,17 +66,25 @@ class UpdateController extends Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$subTitle = (string)trans('firefly.update_check_title');
|
||||
$subTitleIcon = 'fa-star';
|
||||
$permission = app('fireflyconfig')->get('permission_update_check', -1);
|
||||
$selected = $permission->data;
|
||||
$options = [
|
||||
$subTitle = (string)trans('firefly.update_check_title');
|
||||
$subTitleIcon = 'fa-star';
|
||||
$permission = app('fireflyconfig')->get('permission_update_check', -1);
|
||||
$channel = app('fireflyconfig')->get('update_channel', 'stable');
|
||||
$selected = $permission->data;
|
||||
$channelSelected = $channel->data;
|
||||
$options = [
|
||||
-1 => (string)trans('firefly.updates_ask_me_later'),
|
||||
0 => (string)trans('firefly.updates_do_not_check'),
|
||||
1 => (string)trans('firefly.updates_enable_check'),
|
||||
];
|
||||
|
||||
return view('admin.update.index', compact('subTitle', 'subTitleIcon', 'selected', 'options'));
|
||||
$channelOptions = [
|
||||
'stable' => (string)trans('firefly.update_channel_stable'),
|
||||
'beta' => (string)trans('firefly.update_channel_beta'),
|
||||
'alpha' => (string)trans('firefly.update_channel_alpha'),
|
||||
];
|
||||
|
||||
return view('admin.update.index', compact('subTitle', 'subTitleIcon', 'selected', 'options', 'channelSelected', 'channelOptions'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,8 +97,11 @@ class UpdateController extends Controller
|
||||
public function post(Request $request)
|
||||
{
|
||||
$checkForUpdates = (int)$request->get('check_for_updates');
|
||||
$channel = $request->get('update_channel');
|
||||
$channel = in_array($channel, ['stable', 'beta', 'alpha'], true) ? $channel : 'stable';
|
||||
app('fireflyconfig')->set('permission_update_check', $checkForUpdates);
|
||||
app('fireflyconfig')->set('last_update_check', time());
|
||||
app('fireflyconfig')->set('update_channel', $channel);
|
||||
session()->flash('success', (string)trans('firefly.configuration_updated'));
|
||||
|
||||
return redirect(route('admin.update-check'));
|
||||
@@ -97,11 +110,33 @@ class UpdateController extends Controller
|
||||
/**
|
||||
* Does a manual update check.
|
||||
*/
|
||||
public function updateCheck()
|
||||
public function updateCheck(): JsonResponse
|
||||
{
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
$versionCheck = $this->versionCheck($latestRelease);
|
||||
$resultString = $this->parseResult($versionCheck, $latestRelease);
|
||||
$success = true;
|
||||
$latestRelease = '1.0';
|
||||
$resultString = '';
|
||||
$versionCheck = -2;
|
||||
$channel = app('fireflyconfig')->get('update_channel', 'stable')->data;
|
||||
|
||||
try {
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
$success = false;
|
||||
}
|
||||
|
||||
// if error, tell the user.
|
||||
if (false === $success) {
|
||||
$resultString = (string)trans('firefly.update_check_error');
|
||||
session()->flash('error', $resultString);
|
||||
}
|
||||
|
||||
// if not, compare and tell the user.
|
||||
if (true === $success) {
|
||||
$versionCheck = $this->versionCheck($latestRelease);
|
||||
$resultString = $this->parseResult($versionCheck, $latestRelease);
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Result string is: "%s"', $resultString));
|
||||
|
||||
if (0 !== $versionCheck && '' !== $resultString) {
|
||||
@@ -110,6 +145,11 @@ class UpdateController extends Controller
|
||||
}
|
||||
app('fireflyconfig')->set('last_update_check', time());
|
||||
|
||||
return response()->json(['result' => $resultString]);
|
||||
return response()->json(
|
||||
[
|
||||
'result' => $resultString,
|
||||
'channel' => $channel,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -127,7 +127,7 @@ class IndexController extends Controller
|
||||
$array['spent'] = $spentArr[$entry->transaction_currency_id]['sum'] ?? '0';
|
||||
|
||||
// budgeted in period:
|
||||
$budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency,);
|
||||
$budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency, );
|
||||
$array['budgeted'] = $budgeted;
|
||||
$availableBudgets[] = $array;
|
||||
unset($spentArr);
|
||||
@@ -135,7 +135,7 @@ class IndexController extends Controller
|
||||
|
||||
if (0 === count($availableBudgets)) {
|
||||
// get budgeted for default currency:
|
||||
$budgeted = $this->blRepository->budgeted($start, $end, $defaultCurrency,);
|
||||
$budgeted = $this->blRepository->budgeted($start, $end, $defaultCurrency, );
|
||||
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $defaultCurrency);
|
||||
$spent = $spentArr[$defaultCurrency->id]['sum'] ?? '0';
|
||||
unset($spentArr);
|
||||
|
@@ -144,17 +144,25 @@ class ShowController extends Controller
|
||||
public function show(Request $request, Budget $budget)
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = session('first', Carbon::now()->startOfYear());
|
||||
$end = new Carbon;
|
||||
$allStart = session('first', Carbon::now()->startOfYear());
|
||||
$allEnd = new Carbon;
|
||||
|
||||
// use session range:
|
||||
$start = session('start');
|
||||
$end = session('end');
|
||||
|
||||
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$limits = $this->getLimits($budget, $start, $end);
|
||||
$limits = $this->getLimits($budget, $allStart, $allEnd);
|
||||
$repetition = null;
|
||||
|
||||
// collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setRange($start, $end)->setBudget($budget)->setLimit($pageSize)->setPage($page)->withBudgetInformation()->withCategoryInformation();
|
||||
$collector->setRange($start, $end)->setBudget($budget)
|
||||
->withAccountInformation()
|
||||
->setLimit($pageSize)->setPage($page)->withBudgetInformation()->withCategoryInformation();
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath(route('budgets.show', [$budget->id]));
|
||||
|
||||
|
@@ -56,7 +56,6 @@ class BudgetController extends Controller
|
||||
protected $repository;
|
||||
/** @var BudgetLimitRepositoryInterface */
|
||||
private $blRepository;
|
||||
|
||||
/** @var NoBudgetRepositoryInterface */
|
||||
private $nbRepository;
|
||||
|
||||
@@ -86,8 +85,6 @@ class BudgetController extends Controller
|
||||
/**
|
||||
* Shows overview of a single budget.
|
||||
*
|
||||
* TODO this chart is not multi-currency aware.
|
||||
*
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return JsonResponse
|
||||
@@ -107,27 +104,47 @@ class BudgetController extends Controller
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$step = $this->calculateStep($start, $end); // depending on diff, do something with range of chart.
|
||||
$budgetCollection = new Collection([$budget]);
|
||||
$chartData = [];
|
||||
$current = clone $start;
|
||||
$current = app('navigation')->startOfPeriod($current, $step);
|
||||
while ($end >= $current) {
|
||||
$step = $this->calculateStep($start, $end); // depending on diff, do something with range of chart.
|
||||
$collection = new Collection([$budget]);
|
||||
$chartData = [];
|
||||
$loopStart = clone $start;
|
||||
$loopStart = app('navigation')->startOfPeriod($loopStart, $step);
|
||||
$currencies = [];
|
||||
$defaultEntries = [];
|
||||
// echo '<hr>';
|
||||
while ($end >= $loopStart) {
|
||||
/** @var Carbon $currentEnd */
|
||||
$currentEnd = app('navigation')->endOfPeriod($current, $step);
|
||||
$loopEnd = app('navigation')->endOfPeriod($loopStart, $step);
|
||||
if ('1Y' === $step) {
|
||||
$currentEnd->subDay(); // @codeCoverageIgnore
|
||||
$loopEnd->subDay(); // @codeCoverageIgnore
|
||||
}
|
||||
$spent = $this->opsRepository->spentInPeriod($budgetCollection, new Collection, $current, $currentEnd);
|
||||
$label = app('navigation')->periodShow($current, $step);
|
||||
$chartData[$label] = (float)bcmul($spent, '-1');
|
||||
$current = clone $currentEnd;
|
||||
$current->addDay();
|
||||
$spent = $this->opsRepository->sumExpenses($loopStart, $loopEnd, null, $collection);
|
||||
$label = trim(app('navigation')->periodShow($loopStart, $step));
|
||||
|
||||
foreach ($spent as $row) {
|
||||
$currencyId = $row['currency_id'];
|
||||
$currencies[$currencyId] = $currencies[$currencyId] ?? $row; // don't mind the field 'sum'
|
||||
// also store this day's sum:
|
||||
$currencies[$currencyId]['spent'][$label] = $row['sum'];
|
||||
}
|
||||
$defaultEntries[$label] = 0;
|
||||
// set loop start to the next period:
|
||||
$loopStart = clone $loopEnd;
|
||||
$loopStart->addSecond();
|
||||
}
|
||||
|
||||
$data = $this->generator->singleSet((string)trans('firefly.spent'), $chartData);
|
||||
|
||||
// loop all currencies:
|
||||
foreach ($currencies as $currencyId => $currency) {
|
||||
$chartData[$currencyId] = [
|
||||
'label' => count($currencies) > 1 ? sprintf('%s (%s)', $budget->name, $currency['currency_name']) : $budget->name,
|
||||
'type' => 'bar',
|
||||
'currency_symbol' => $currency['currency_symbol'],
|
||||
'entries' => $defaultEntries,
|
||||
];
|
||||
foreach ($currency['spent'] as $label => $spent) {
|
||||
$chartData[$currencyId]['entries'][$label] = round(bcmul($spent, '-1'), $currency['currency_decimal_places']);
|
||||
}
|
||||
}
|
||||
$data = $this->generator->multiSet(array_values($chartData));
|
||||
$cache->store($data);
|
||||
|
||||
return response()->json($data);
|
||||
@@ -379,7 +396,7 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.budget.frontpage');
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
//return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
$budgets = $this->repository->getActiveBudgets();
|
||||
$chartData = [
|
||||
@@ -390,23 +407,42 @@ class BudgetController extends Controller
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
// get relevant repetitions:
|
||||
$limits = $this->blRepository->getBudgetLimits($budget, $start, $end);
|
||||
$expenses = $this->getExpensesForBudget($limits, $budget, $start, $end);
|
||||
|
||||
foreach ($expenses as $name => $row) {
|
||||
$chartData[0]['entries'][$name] = $row['spent'];
|
||||
$chartData[1]['entries'][$name] = $row['left'];
|
||||
$chartData[2]['entries'][$name] = $row['overspent'];
|
||||
$limits = $this->blRepository->getBudgetLimits($budget, $start, $end);
|
||||
if (0 === $limits->count()) {
|
||||
$spent = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$budget]), null);
|
||||
/** @var array $entry */
|
||||
foreach ($spent as $entry) {
|
||||
$title = sprintf('%s (%s)', $budget->name, $entry['currency_name']);
|
||||
$chartData[0]['entries'][$title] = bcmul($entry['sum'], '-1'); // spent
|
||||
$chartData[1]['entries'][$title] = 0; // left to spend
|
||||
$chartData[2]['entries'][$title] = 0; // overspent
|
||||
}
|
||||
}
|
||||
if (0 !== $limits->count()) {
|
||||
/** @var BudgetLimit $limit */
|
||||
foreach ($limits as $limit) {
|
||||
$spent = $this->opsRepository->sumExpenses(
|
||||
$limit->start_date, $limit->end_date, null, new Collection([$budget]), $limit->transactionCurrency
|
||||
);
|
||||
/** @var array $entry */
|
||||
foreach ($spent as $entry) {
|
||||
$title = sprintf('%s (%s)', $budget->name, $entry['currency_name']);
|
||||
if ($limit->start_date->startOfDay()->ne($start->startOfDay()) || $limit->end_date->startOfDay()->ne($end->startOfDay())) {
|
||||
$title = sprintf(
|
||||
'%s (%s) (%s - %s)', $budget->name, $entry['currency_name'],
|
||||
$limit->start_date->formatLocalized($this->monthAndDayFormat),
|
||||
$limit->end_date->formatLocalized($this->monthAndDayFormat)
|
||||
);
|
||||
}
|
||||
|
||||
$chartData[0]['entries'][$title] = bcmul($entry['sum'], '-1'); // spent
|
||||
$chartData[1]['entries'][$title] = 1 === bccomp($limit->amount, bcmul($entry['sum'], '-1')) ? bcadd($entry['sum'], $limit->amount)
|
||||
: '0';
|
||||
$chartData[2]['entries'][$title] = 1 === bccomp($limit->amount, bcmul($entry['sum'], '-1')) ?
|
||||
'0' : bcmul(bcadd($entry['sum'], $limit->amount), '-1');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// for no budget:
|
||||
$spent = $this->spentInPeriodWithout($start, $end);
|
||||
$name = (string)trans('firefly.no_budget');
|
||||
if (0 !== bccomp($spent, '0')) {
|
||||
$chartData[0]['entries'][$name] = bcmul($spent, '-1');
|
||||
$chartData[1]['entries'][$name] = '0';
|
||||
$chartData[2]['entries'][$name] = '0';
|
||||
}
|
||||
|
||||
$data = $this->generator->multiSet($chartData);
|
||||
|
@@ -174,9 +174,9 @@ class ReportController extends Controller
|
||||
$data[$currencyId] = $data[$currencyId] ?? [
|
||||
'currency_id' => $currencyId,
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_decimal_places' => $journal['currency_decimal_places'],
|
||||
'currency_decimal_places' => (int)$journal['currency_decimal_places'],
|
||||
];
|
||||
$data[$currencyId][$period] = $data[$currencyId][$period] ?? [
|
||||
'period' => $period,
|
||||
@@ -218,7 +218,6 @@ class ReportController extends Controller
|
||||
// loop all possible periods between $start and $end
|
||||
$currentStart = clone $start;
|
||||
while ($currentStart <= $end) {
|
||||
$currentEnd = app('navigation')->endOfPeriod($currentStart, $preferredRange);
|
||||
$key = $currentStart->format($format);
|
||||
$title = $currentStart->formatLocalized($titleFormat);
|
||||
$income['entries'][$title] = round($currency[$key]['earned'] ?? '0', $currency['currency_decimal_places']);
|
||||
|
@@ -55,12 +55,26 @@ class Controller extends BaseController
|
||||
public function __construct()
|
||||
{
|
||||
// is site a demo site?
|
||||
$isDemoSite = app('fireflyconfig')->get('is_demo_site', config('firefly.configuration.is_demo_site', ), )->data;
|
||||
app('view')->share('IS_DEMO_SITE', $isDemoSite, );
|
||||
$isDemoSite = app('fireflyconfig')->get('is_demo_site', config('firefly.configuration.is_demo_site',),)->data;
|
||||
app('view')->share('IS_DEMO_SITE', $isDemoSite,);
|
||||
app('view')->share('DEMO_USERNAME', config('firefly.demo_username'));
|
||||
app('view')->share('DEMO_PASSWORD', config('firefly.demo_password'));
|
||||
app('view')->share('FF_VERSION', config('firefly.version'));
|
||||
|
||||
// share is alpha, is beta
|
||||
$isAlpha = false;
|
||||
if (false !== strpos(config('firefly.version'), 'alpha')) {
|
||||
$isAlpha = true;
|
||||
}
|
||||
|
||||
$isBeta = false;
|
||||
if (false !== strpos(config('firefly.version'), 'beta')) {
|
||||
$isBeta = true;
|
||||
}
|
||||
|
||||
app('view')->share('FF_IS_ALPHA', $isAlpha);
|
||||
app('view')->share('FF_IS_BETA', $isBeta);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
// translations for specific strings:
|
||||
|
@@ -129,7 +129,9 @@ class HomeController extends Controller
|
||||
foreach ($accounts as $account) {
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->setLimit(10)->setPage(1);
|
||||
$collector->setAccounts(new Collection([$account]))
|
||||
->withAccountInformation()
|
||||
->setRange($start, $end)->setLimit(10)->setPage(1);
|
||||
$set = $collector->getGroups();
|
||||
$transactions[] = [$set, $account];
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
@@ -282,6 +283,39 @@ class AutoCompleteController extends Controller
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An auto-complete specifically for asset accounts and liabilities, used when mass updating and for rules mostly.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function assetAccounts(Request $request): JsonResponse
|
||||
{
|
||||
$search = $request->get('search');
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
// filter the account types:
|
||||
$allowedAccountTypes = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
|
||||
Log::debug(sprintf('Now in expenseAccounts(%s). Filtering results.', $search), $allowedAccountTypes);
|
||||
|
||||
$return = [];
|
||||
$result = $repository->searchAccount((string)$search, $allowedAccountTypes);
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($result as $account) {
|
||||
$return[] = [
|
||||
'id' => $account->id,
|
||||
'name' => $account->name,
|
||||
'type' => $account->accountType->type,
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse
|
||||
* @codeCoverageIgnore
|
||||
@@ -291,7 +325,26 @@ class AutoCompleteController extends Controller
|
||||
/** @var PiggyBankRepositoryInterface $repository */
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
|
||||
return response()->json($repository->getPiggyBanks()->toArray());
|
||||
/** @var AccountRepositoryInterface $accountRepos */
|
||||
$accountRepos = app(AccountRepositoryInterface::class);
|
||||
|
||||
$piggies = $repository->getPiggyBanks();
|
||||
$defaultCurrency = \Amount::getDefaultCurrency();
|
||||
$response = [];
|
||||
/** @var PiggyBank $piggy */
|
||||
foreach ($piggies as $piggy) {
|
||||
$currency = $accountRepos->getAccountCurrency($piggy->account) ?? $defaultCurrency;
|
||||
$currentAmount = $repository->getRepetition($piggy)->currentamount ?? '0';
|
||||
$piggy->name_with_amount = sprintf(
|
||||
'%s (%s / %s)',
|
||||
$piggy->name,
|
||||
app('amount')->formatAnything($currency, $currentAmount, false),
|
||||
app('amount')->formatAnything($currency, $piggy->targetamount, false),
|
||||
);
|
||||
$response[] = $piggy->toArray();
|
||||
}
|
||||
|
||||
return response()->json($response);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -82,9 +82,6 @@ class IndexController extends Controller
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$collection = $this->recurring->get();
|
||||
$today = new Carbon;
|
||||
$year = new Carbon;
|
||||
$year->addYear();
|
||||
|
||||
// split collection
|
||||
$total = $collection->count();
|
||||
@@ -98,6 +95,14 @@ class IndexController extends Controller
|
||||
$recurring = [];
|
||||
/** @var Recurrence $recurrence */
|
||||
foreach ($recurrences as $recurrence) {
|
||||
$today = new Carbon;
|
||||
$year = new Carbon;
|
||||
$year->addYear();
|
||||
if($recurrence->first_date > $today) {
|
||||
$today =clone $recurrence->first_date;
|
||||
$year = clone $today;
|
||||
$year->addYear();
|
||||
}
|
||||
$array = $transformer->transform($recurrence);
|
||||
$array['first_date'] = new Carbon($array['first_date']);
|
||||
$array['repeat_until'] = null === $array['repeat_until'] ? null : new Carbon($array['repeat_until']);
|
||||
|
@@ -102,6 +102,9 @@ class InstallController extends Controller
|
||||
'firefly-iii:rename-meta-fields' => [],
|
||||
'firefly-iii:fix-ob-currencies' => [],
|
||||
'firefly-iii:fix-long-descriptions' => [],
|
||||
|
||||
// final command to set latest version in DB
|
||||
'firefly-iii:set-latest-version' => ['--james-is-cool' => true],
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -78,7 +78,8 @@ class CreateController extends Controller
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$previousUri = $this->rememberPreviousUri('transactions.create.uri');
|
||||
$parts = parse_url($previousUri);
|
||||
$previousUri = sprintf('%s://%s/%s', $parts['scheme'], $parts['host'], $parts['path']);
|
||||
$search = sprintf('?%s', $parts['query'] ?? '');
|
||||
$previousUri = str_replace($search, '', $previousUri);
|
||||
|
||||
session()->put('preFilled', $preFilled);
|
||||
|
||||
|
@@ -83,7 +83,8 @@ class EditController extends Controller
|
||||
$cash = $repository->getCashAccount();
|
||||
$previousUri = $this->rememberPreviousUri('transactions.edit.uri');
|
||||
$parts = parse_url($previousUri);
|
||||
$previousUri = sprintf('%s://%s/%s', $parts['scheme'], $parts['host'], $parts['path']);
|
||||
$search = sprintf('?%s', $parts['query'] ?? '');
|
||||
$previousUri = str_replace($search, '', $previousUri);
|
||||
|
||||
|
||||
return view('transactions.edit', compact('cash', 'transactionGroup', 'allowedOpposingTypes', 'accountToTypes', 'defaultCurrency', 'previousUri'));
|
||||
|
@@ -89,7 +89,7 @@ class RuleFormRequest extends Request
|
||||
'triggers.*.type' => 'required|in:' . implode(',', $validTriggers),
|
||||
'triggers.*.value' => sprintf('required_if:triggers.*.type,%s|min:1|ruleTriggerValue', $contextTriggers),
|
||||
'actions.*.type' => 'required|in:' . implode(',', $validActions),
|
||||
'actions.*.value' => sprintf('required_if:actions.*.type,%s|min:1|ruleActionValue', $contextActions),
|
||||
'actions.*.value' => sprintf('required_if:actions.*.type,%s|min:0|max:255|ruleActionValue', $contextActions),
|
||||
'strict' => 'in:0,1',
|
||||
];
|
||||
|
||||
|
@@ -49,6 +49,8 @@ class BankDebitCredit implements ConverterInterface
|
||||
'DR', // https://old.reddit.com/r/FireflyIII/comments/bn2edf/generic_debitcredit_indicator/
|
||||
'Af', // ING (NL).
|
||||
'Debet', // Triodos (NL)
|
||||
'S', // "Soll", German term for debit
|
||||
'Debit', // Community America (US)
|
||||
];
|
||||
if (in_array(trim($value), $negative, true)) {
|
||||
return -1;
|
||||
|
@@ -319,7 +319,7 @@ class ImportArrayStorage
|
||||
private function getHash(array $transaction): string
|
||||
{
|
||||
unset($transaction['import_hash_v2'], $transaction['original_source']);
|
||||
$json = json_encode($transaction);
|
||||
$json = json_encode($transaction, JSON_THROW_ON_ERROR);
|
||||
if (false === $json) {
|
||||
// @codeCoverageIgnoreStart
|
||||
/** @noinspection ForgottenDebugOutputInspection */
|
||||
@@ -332,8 +332,9 @@ class ImportArrayStorage
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$hash = hash('sha256', $json);
|
||||
Log::debug(sprintf('The hash is: %s', $hash));
|
||||
Log::debug(sprintf('The hash is: %s', $hash), $transaction);
|
||||
|
||||
return $hash;
|
||||
}
|
||||
@@ -442,7 +443,8 @@ class ImportArrayStorage
|
||||
Log::debug(sprintf('Comparison is a hit! (%s)', $hits));
|
||||
|
||||
// compare description:
|
||||
$comparison = '(empty description)' === $transfer['description'] ? '' : $transfer['description'];
|
||||
// $comparison = '(empty description)' === $transfer['description'] ? '' : $transfer['description'];
|
||||
$comparison = $transfer['description'];
|
||||
Log::debug(sprintf('Comparing "%s" to "%s" (original: "%s")', $description, $transfer['description'], $comparison));
|
||||
if ($description !== $comparison) {
|
||||
Log::debug('Description is not a match, continue with next transfer.');
|
||||
@@ -483,7 +485,7 @@ class ImportArrayStorage
|
||||
/** @noinspection DisconnectedForeachInstructionInspection */
|
||||
Log::debug('Comparing current transaction source+dest names', $transactionSourceNames);
|
||||
Log::debug('.. with current transfer source+dest names', $transferSource);
|
||||
if ($transactionSourceNames === $transferSource) {
|
||||
if ($transactionSourceNames === $transferSource && $transferSource !== ['', '']) {
|
||||
// @codeCoverageIgnoreStart
|
||||
++$hits;
|
||||
Log::debug(sprintf('Source names are the same! (%d)', $hits));
|
||||
|
@@ -242,8 +242,8 @@ class CreateRecurringTransactions implements ShouldQueue
|
||||
'recurrence_id' => (int)$recurrence->id,
|
||||
'order' => $index,
|
||||
'notes' => (string)trans('firefly.created_from_recurrence', ['id' => $recurrence->id, 'title' => $recurrence->title]),
|
||||
'tags' => $this->repository->getTags($recurrence),
|
||||
'piggy_bank_id' => null,
|
||||
'tags' => $this->repository->getTags($transaction),
|
||||
'piggy_bank_id' => $this->repository->getPiggyBank($transaction),
|
||||
'piggy_bank_name' => null,
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
@@ -324,7 +324,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
||||
Log::info(sprintf('Created new transaction group #%d', $group->id));
|
||||
|
||||
// link to piggy:
|
||||
$this->linkGroupToPiggies($recurrence, $group);
|
||||
//$this->linkGroupToPiggies($recurrence, $group);
|
||||
|
||||
// trigger event:
|
||||
event(new StoredTransactionGroup($group, $recurrence->apply_rules));
|
||||
|
@@ -150,6 +150,21 @@ class Account extends Model
|
||||
return $this->belongsTo(AccountType::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the account number.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccountNumberAttribute(): string
|
||||
{
|
||||
/** @var AccountMeta $metaValue */
|
||||
$metaValue = $this->accountMeta()
|
||||
->where('name', 'account_number')
|
||||
->first();
|
||||
|
||||
return $metaValue ? $metaValue->data : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @codeCoverageIgnore
|
||||
|
@@ -42,6 +42,8 @@ use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepository;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Services\Currency\ExchangeRateInterface;
|
||||
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequest;
|
||||
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequestInterface;
|
||||
use FireflyIII\Services\IP\IpifyOrg;
|
||||
use FireflyIII\Services\IP\IPRetrievalInterface;
|
||||
use FireflyIII\Services\Password\PwndVerifierV3;
|
||||
@@ -64,7 +66,7 @@ use FireflyIII\Support\Twig\Translation;
|
||||
use FireflyIII\Validation\FireflyValidator;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Twig;
|
||||
use Twig_Extension_Debug;
|
||||
use Twig\Extension\DebugExtension;
|
||||
use TwigBridge\Extension\Loader\Functions;
|
||||
use Validator;
|
||||
|
||||
@@ -88,14 +90,14 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
return new FireflyValidator($translator, $data, $rules, $messages);
|
||||
}
|
||||
);
|
||||
$config = app('config');
|
||||
Twig::addExtension(new Functions($config));
|
||||
//$config = app('config');
|
||||
//Twig::addExtension(new Functions($config));
|
||||
Twig::addExtension(new General);
|
||||
Twig::addExtension(new TransactionGroupTwig);
|
||||
Twig::addExtension(new Translation);
|
||||
Twig::addExtension(new Rule);
|
||||
Twig::addExtension(new AmountFormat);
|
||||
Twig::addExtension(new Twig_Extension_Debug);
|
||||
//Twig::addExtension(new DebugExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,6 +186,8 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
$this->app->bind(HelpInterface::class, Help::class);
|
||||
$this->app->bind(ReportHelperInterface::class, ReportHelper::class);
|
||||
$this->app->bind(FiscalHelperInterface::class, FiscalHelper::class);
|
||||
$this->app->bind(UpdateRequestInterface::class, UpdateRequest::class);
|
||||
|
||||
$class = (string)config(sprintf('firefly.cer_providers.%s', (string)config('firefly.cer_provider')));
|
||||
if ('' === $class) {
|
||||
throw new FireflyException('Invalid currency exchange rate provider. Cannot continue.');
|
||||
|
@@ -554,10 +554,16 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
{
|
||||
$dbQuery = $this->user->accounts()
|
||||
->where('active', 1)
|
||||
->orderBy('accounts.name', 'ASC')
|
||||
->with(['accountType']);
|
||||
if ('' !== $query) {
|
||||
$search = sprintf('%%%s%%', $query);
|
||||
$dbQuery->where('name', 'LIKE', $search);
|
||||
// split query on spaces just in case:
|
||||
$parts = explode(' ', $query);
|
||||
foreach($parts as $part) {
|
||||
$search = sprintf('%%%s%%', $part);
|
||||
$dbQuery->where('name', 'LIKE', $search);
|
||||
}
|
||||
|
||||
}
|
||||
if (count($types) > 0) {
|
||||
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Repositories\Bill;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\BillFactory;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Note;
|
||||
@@ -662,9 +663,10 @@ class BillRepository implements BillRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Bill|null
|
||||
* @return Bill
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?Bill
|
||||
public function store(array $data): Bill
|
||||
{
|
||||
/** @var BillFactory $factory */
|
||||
$factory = app(BillFactory::class);
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Bill;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
@@ -266,9 +267,10 @@ interface BillRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Bill|null
|
||||
* @return Bill
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?Bill;
|
||||
public function store(array $data): Bill;
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
|
@@ -73,6 +73,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
|
||||
->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.transaction_currency_id', $currency->id)
|
||||
->whereNull('budgets.deleted_at')
|
||||
->where('budgets.user_id', $this->user->id);
|
||||
if (null !== $budgets && $budgets->count() > 0) {
|
||||
$query->whereIn('budget_limits.budget_id', $budgets->pluck('id')->toArray());
|
||||
|
@@ -25,6 +25,7 @@ namespace FireflyIII\Repositories\Budget;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\RecurrenceTransactionMeta;
|
||||
@@ -32,6 +33,7 @@ use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
use FireflyIII\Services\Internal\Destroy\BudgetDestroyService;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
@@ -269,16 +271,20 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): Budget
|
||||
{
|
||||
$newBudget = new Budget(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $data['name'],
|
||||
]
|
||||
);
|
||||
$newBudget->save();
|
||||
try {
|
||||
$newBudget = Budget::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $data['name'],
|
||||
]
|
||||
);
|
||||
} catch(QueryException $e) {
|
||||
throw new FireflyException('400002: Could not store budget.');
|
||||
}
|
||||
|
||||
return $newBudget;
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Budget;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -132,6 +133,7 @@ interface BudgetRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): Budget;
|
||||
|
||||
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Repositories\Category;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\CategoryFactory;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\RecurrenceTransactionMeta;
|
||||
@@ -239,6 +240,7 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return Category
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): Category
|
||||
{
|
||||
@@ -246,7 +248,13 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
$factory = app(CategoryFactory::class);
|
||||
$factory->setUser($this->user);
|
||||
|
||||
return $factory->findOrCreate(null, $data['name']);
|
||||
$category = $factory->findOrCreate(null, $data['name']);
|
||||
|
||||
if (null === $category) {
|
||||
throw new FireflyException(sprintf('400003: Could not store new category with name "%s"', $data['name']));
|
||||
}
|
||||
return $category;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Category;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -117,7 +118,7 @@ interface CategoryRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return Category
|
||||
*/
|
||||
public function store(array $data): Category;
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Currency;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\TransactionCurrencyFactory;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
@@ -489,14 +490,20 @@ class CurrencyRepository implements CurrencyRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
* @return TransactionCurrency
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?TransactionCurrency
|
||||
public function store(array $data): TransactionCurrency
|
||||
{
|
||||
/** @var TransactionCurrencyFactory $factory */
|
||||
$factory = app(TransactionCurrencyFactory::class);
|
||||
$result = $factory->create($data);
|
||||
|
||||
return $factory->create($data);
|
||||
if (null === $result) {
|
||||
throw new FireflyException('400004: Could not store new currency.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -234,9 +234,9 @@ interface CurrencyRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function store(array $data): ?TransactionCurrency;
|
||||
public function store(array $data): TransactionCurrency;
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Journal;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
@@ -377,4 +378,26 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getSourceAccount(TransactionJournal $journal): Account
|
||||
{
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $journal->transactions()->with('account')->where('amount', '<', 0)->first();
|
||||
|
||||
return $transaction->account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getDestinationAccount(TransactionJournal $journal): Account
|
||||
{
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $journal->transactions()->with('account')->where('amount', '>', 0)->first();
|
||||
|
||||
return $transaction->account;
|
||||
}
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Journal;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionJournalLink;
|
||||
@@ -109,6 +110,22 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function getJournalSourceAccounts(TransactionJournal $journal): Collection;
|
||||
|
||||
/**
|
||||
* Returns the source account of the journal.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @return Account
|
||||
*/
|
||||
public function getSourceAccount(TransactionJournal $journal): Account;
|
||||
|
||||
/**
|
||||
* Returns the destination account of the journal.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @return Account
|
||||
*/
|
||||
public function getDestinationAccount(TransactionJournal $journal): Account;
|
||||
|
||||
/**
|
||||
* Return total amount of journal. Is always positive.
|
||||
*
|
||||
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Repositories\PiggyBank;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
@@ -33,6 +34,7 @@ use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
@@ -416,9 +418,11 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
*/
|
||||
public function getPiggyBanks(): Collection
|
||||
{
|
||||
return $this->user->piggyBanks()->orderBy('order', 'ASC')->get();
|
||||
return $this->user->piggyBanks()->with(['account'])->orderBy('order', 'ASC')->get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Also add amount in name.
|
||||
*
|
||||
@@ -556,13 +560,19 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
* @return PiggyBank
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?PiggyBank
|
||||
public function store(array $data): PiggyBank
|
||||
{
|
||||
$data['order'] = $this->getMaxOrder() + 1;
|
||||
try {
|
||||
/** @var PiggyBank $piggyBank */
|
||||
$piggyBank = PiggyBank::create($data);
|
||||
} catch(QueryException $e) {
|
||||
Log::error(sprintf('Could not store piggy bank: %s',$e->getMessage()));
|
||||
throw new FireflyException('400005: Could not store new piggy bank.');
|
||||
}
|
||||
|
||||
$this->updateNote($piggyBank, $data['notes']);
|
||||
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\PiggyBank;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\PiggyBankRepetition;
|
||||
@@ -245,9 +246,10 @@ interface PiggyBankRepositoryInterface
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
* @return PiggyBank
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?PiggyBank;
|
||||
public function store(array $data): PiggyBank;
|
||||
|
||||
/**
|
||||
* Update existing piggy bank.
|
||||
|
@@ -28,7 +28,6 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\RecurrenceFactory;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\RecurrenceMeta;
|
||||
@@ -253,19 +252,17 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
* @param RecurrenceTransaction $transaction
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
* @return int|null
|
||||
*/
|
||||
public function getPiggyBank(Recurrence $recurrence): ?PiggyBank
|
||||
public function getPiggyBank(RecurrenceTransaction $transaction): ?int
|
||||
{
|
||||
$meta = $recurrence->recurrenceMeta;
|
||||
/** @var RecurrenceMeta $metaEntry */
|
||||
$meta = $transaction->recurrenceTransactionMeta;
|
||||
/** @var RecurrenceTransactionMeta $metaEntry */
|
||||
foreach ($meta as $metaEntry) {
|
||||
if ('piggy_bank_id' === $metaEntry->name) {
|
||||
$piggyId = (int)$metaEntry->value;
|
||||
|
||||
return $this->user->piggyBanks()->where('piggy_banks.id', $piggyId)->first(['piggy_banks.*']);
|
||||
return (int)$metaEntry->value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,17 +272,18 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
/**
|
||||
* Get the tags from the recurring transaction.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
* @param RecurrenceTransaction $transaction
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTags(Recurrence $recurrence): array
|
||||
public function getTags(RecurrenceTransaction $transaction): array
|
||||
{
|
||||
$tags = [];
|
||||
/** @var RecurrenceMeta $meta */
|
||||
foreach ($recurrence->recurrenceMeta as $meta) {
|
||||
foreach ($transaction->recurrenceTransactionMeta as $meta) {
|
||||
if ('tags' === $meta->name && '' !== $meta->value) {
|
||||
$tags = explode(',', $meta->value);
|
||||
//$tags = explode(',', $meta->value);
|
||||
$tags = json_decode($meta->value, true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -120,19 +120,19 @@ interface RecurringRepositoryInterface
|
||||
public function getOccurrencesInRange(RecurrenceRepetition $repetition, Carbon $start, Carbon $end): array;
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
* @return PiggyBank|null
|
||||
* @param RecurrenceTransaction $transaction
|
||||
* @return int|null
|
||||
*/
|
||||
public function getPiggyBank(Recurrence $recurrence): ?PiggyBank;
|
||||
public function getPiggyBank(RecurrenceTransaction $transaction): ?int;
|
||||
|
||||
/**
|
||||
* Get the tags from the recurring transaction.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
* @param RecurrenceTransaction $transaction
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTags(Recurrence $recurrence): array;
|
||||
public function getTags(RecurrenceTransaction $transaction): array;
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
|
@@ -301,9 +301,11 @@ class TagRepository implements TagRepositoryInterface
|
||||
$journals = $collector->getExtractedJournals();
|
||||
|
||||
$sums = [
|
||||
TransactionType::WITHDRAWAL => '0',
|
||||
TransactionType::DEPOSIT => '0',
|
||||
TransactionType::TRANSFER => '0',
|
||||
TransactionType::WITHDRAWAL => '0',
|
||||
TransactionType::DEPOSIT => '0',
|
||||
TransactionType::TRANSFER => '0',
|
||||
TransactionType::RECONCILIATION => '0',
|
||||
TransactionType::OPENING_BALANCE => '0',
|
||||
];
|
||||
|
||||
/** @var array $journal */
|
||||
|
@@ -27,6 +27,7 @@ namespace FireflyIII\Repositories\TransactionGroup;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\TransactionGroupFactory;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
@@ -314,6 +315,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionGroup
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
public function store(array $data): TransactionGroup
|
||||
{
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Repositories\TransactionGroup;
|
||||
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use FireflyIII\User;
|
||||
@@ -125,6 +126,7 @@ interface TransactionGroupRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionGroup
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
public function store(array $data): TransactionGroup;
|
||||
|
||||
|
73
app/Rules/IsTransferAccount.php
Normal file
73
app/Rules/IsTransferAccount.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* IsTransferAccount.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Rules;
|
||||
|
||||
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Validation\AccountValidator;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class IsTransferAccount
|
||||
*/
|
||||
class IsTransferAccount implements Rule
|
||||
{
|
||||
/**
|
||||
* Get the validation error message.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function message(): string
|
||||
{
|
||||
return (string)trans('validation.not_transfer_account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the validation rule passes.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function passes($attribute, $value): bool
|
||||
{
|
||||
Log::debug(sprintf('Now in %s(%s)', __METHOD__, $value));
|
||||
/** @var AccountValidator $validator */
|
||||
$validator = app(AccountValidator::class);
|
||||
$validator->setTransactionType(TransactionType::TRANSFER);
|
||||
$validator->setUser(auth()->user());
|
||||
|
||||
$validAccount = $validator->validateSource(null, (string)$value);
|
||||
if (true === $validAccount) {
|
||||
Log::debug('Found account based on name. Return true.');
|
||||
|
||||
// found by name, use repos to return.
|
||||
return true;
|
||||
}
|
||||
$validAccount = $validator->validateSource((int)$value, null);
|
||||
Log::debug(sprintf('Search by id (%d), result is %s.', (int)$value, var_export($validAccount, true)));
|
||||
|
||||
return !(false === $validAccount);
|
||||
}
|
||||
}
|
75
app/Services/FireflyIIIOrg/Update/UpdateRequest.php
Normal file
75
app/Services/FireflyIIIOrg/Update/UpdateRequest.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* UpdateRequest.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Services\FireflyIIIOrg\Update;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use JsonException;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class UpdateRequest
|
||||
*/
|
||||
class UpdateRequest implements UpdateRequestInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $channel
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getVersion(string $channel): array
|
||||
{
|
||||
$uri = config('firefly.update_endpoint');
|
||||
Log::debug(sprintf('Going to call %s', $uri));
|
||||
try {
|
||||
$client = new Client();
|
||||
$options = [
|
||||
'headers' => [
|
||||
'User-Agent' => sprintf('FireflyIII/%s/%s', config('firefly.version'), $channel),
|
||||
],
|
||||
];
|
||||
$res = $client->request('GET', $uri, $options);
|
||||
} catch (GuzzleException|Exception $e) {
|
||||
throw new FireflyException(sprintf('Response error from update check: %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
if (200 !== $res->getStatusCode()) {
|
||||
throw new FireflyException(sprintf('Returned error code %d from update check.', $res->getStatusCode()));
|
||||
}
|
||||
$body = (string)$res->getBody();
|
||||
try {
|
||||
$json = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
throw new FireflyException('Invalid JSON in server response.');
|
||||
}
|
||||
|
||||
if (!isset($json['firefly_iii'][$channel])) {
|
||||
throw new FireflyException(sprintf('Unknown update channel "%s"', $channel));
|
||||
}
|
||||
|
||||
return $json['firefly_iii'][$channel];
|
||||
}
|
||||
}
|
39
app/Services/FireflyIIIOrg/Update/UpdateRequestInterface.php
Normal file
39
app/Services/FireflyIIIOrg/Update/UpdateRequestInterface.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* UpdateRequestInterface.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Services\FireflyIIIOrg\Update;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
|
||||
/**
|
||||
* Interface UpdateRequestInterface
|
||||
*/
|
||||
interface UpdateRequestInterface
|
||||
{
|
||||
/**
|
||||
* @param string $channel
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getVersion(string $channel): array;
|
||||
|
||||
}
|
@@ -228,16 +228,20 @@ class AccountForm
|
||||
|
||||
// get all asset accounts:
|
||||
$repository = $this->getAccountRepository();
|
||||
$types = [AccountType::ASSET, AccountType::DEFAULT];
|
||||
$types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT];
|
||||
$assetAccounts = $repository->getAccountsByType($types);
|
||||
$grouped = [];
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($assetAccounts as $account) {
|
||||
$role = $repository->getMetaValue($account, 'account_role');
|
||||
if (null === $role) {
|
||||
if (null === $role && in_array($account->accountType->type, [AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT], true)) {
|
||||
$role = sprintf('l_%s', $account->accountType->type);
|
||||
}
|
||||
if (null === $role && !in_array($account->accountType->type, [AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT], true)) {
|
||||
$role = 'no_account_type';
|
||||
}
|
||||
|
||||
$key = (string)trans(sprintf('firefly.opt_group_%s', $role));
|
||||
$grouped[$key][$account->id] = $account->name;
|
||||
}
|
||||
|
@@ -71,109 +71,6 @@ trait AugumentData
|
||||
return $combined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group by category (earnings).
|
||||
*
|
||||
* @param Collection $assets
|
||||
* @param Collection $opposing
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
protected function earnedByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
|
||||
$total = $assets->merge($opposing);
|
||||
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($total);
|
||||
$collector->withCategoryInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$sum = [];
|
||||
// loop to support multi currency
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = $journal['currency_id'];
|
||||
$categoryName = $journal['category_name'];
|
||||
$categoryId = (int)$journal['category_id'];
|
||||
|
||||
// if not set, set to zero:
|
||||
if (!isset($sum[$categoryId][$currencyId])) {
|
||||
$sum[$categoryId] = [
|
||||
'grand_total' => '0',
|
||||
'name' => $categoryName,
|
||||
'per_currency' => [
|
||||
$currencyId => [
|
||||
'sum' => '0',
|
||||
'category' => [
|
||||
'id' => $categoryId,
|
||||
'name' => $categoryName,
|
||||
],
|
||||
'currency' => [
|
||||
'symbol' => $journal['currency_symbol'],
|
||||
'dp' => $journal['currency_decimal_places'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// add amount
|
||||
$sum[$categoryId]['per_currency'][$currencyId]['sum'] = bcadd(
|
||||
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $journal['amount']
|
||||
);
|
||||
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $journal['amount']);
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Earned in period for accounts.
|
||||
*
|
||||
* @param Collection $assets
|
||||
* @param Collection $opposing
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function earnedInPeriod(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
|
||||
$total = $assets->merge($opposing);
|
||||
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($total);
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$sum = [
|
||||
'grand_sum' => '0',
|
||||
'per_currency' => [],
|
||||
];
|
||||
// loop to support multi currency
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
|
||||
// if not set, set to zero:
|
||||
if (!isset($sum['per_currency'][$currencyId])) {
|
||||
$sum['per_currency'][$currencyId] = [
|
||||
'sum' => '0',
|
||||
'currency' => [
|
||||
'symbol' => $journal['currency_symbol'],
|
||||
'decimal_places' => $journal['currency_decimal_places'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// add amount
|
||||
$sum['per_currency'][$currencyId]['sum'] = bcadd($sum['per_currency'][$currencyId]['sum'], $journal['amount']);
|
||||
$sum['grand_sum'] = bcadd($sum['grand_sum'], $journal['amount']);
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Small helper function for the revenue and expense account charts.
|
||||
*
|
||||
@@ -209,34 +106,6 @@ trait AugumentData
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the budget limits belonging to the given budget and valid on the given day.
|
||||
*
|
||||
* @param Collection $budgetLimits
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
protected function filterBudgetLimits(Collection $budgetLimits, Budget $budget, Carbon $start, Carbon $end): Collection // filter data
|
||||
{
|
||||
$set = $budgetLimits->filter(
|
||||
static function (BudgetLimit $budgetLimit) use ($budget, $start, $end) {
|
||||
if ($budgetLimit->budget_id === $budget->id
|
||||
&& $budgetLimit->start_date->lte($start) // start of budget limit is on or before start
|
||||
&& $budgetLimit->end_date->gte($end) // end of budget limit is on or after end
|
||||
) {
|
||||
return $budgetLimit;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the account names belonging to a bunch of account ID's.
|
||||
*
|
||||
@@ -285,39 +154,6 @@ trait AugumentData
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of money budgeted in a period.
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getBudgetedInPeriod(Budget $budget, Carbon $start, Carbon $end): array // get data + augment with info
|
||||
{
|
||||
/** @var BudgetLimitRepositoryInterface $blRepository */
|
||||
$blRepository = app(BudgetLimitRepositoryInterface::class);
|
||||
|
||||
$key = app('navigation')->preferredCarbonFormat($start, $end);
|
||||
$range = app('navigation')->preferredRangeFormat($start, $end);
|
||||
$current = clone $start;
|
||||
$budgeted = [];
|
||||
while ($current < $end) {
|
||||
/** @var Carbon $currentStart */
|
||||
$currentStart = app('navigation')->startOfPeriod($current, $range);
|
||||
/** @var Carbon $currentEnd */
|
||||
$currentEnd = app('navigation')->endOfPeriod($current, $range);
|
||||
$budgetLimits = $blRepository->getBudgetLimits($budget, $currentStart, $currentEnd);
|
||||
$index = $currentStart->format($key);
|
||||
$budgeted[$index] = $budgetLimits->sum('amount');
|
||||
$currentEnd->addDay();
|
||||
$current = clone $currentEnd;
|
||||
}
|
||||
|
||||
return $budgeted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the category names from a set of category ID's. Small helper function for some of the charts.
|
||||
*
|
||||
@@ -342,48 +178,6 @@ trait AugumentData
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expenses for a budget in a date range.
|
||||
*
|
||||
* @param Collection $limits
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
protected function getExpensesForBudget(Collection $limits, Budget $budget, Carbon $start, Carbon $end): array // get data + augment with info
|
||||
{
|
||||
/** @var BudgetRepositoryInterface $repository */
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
/** @var OperationsRepositoryInterface $opsRepository */
|
||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||
|
||||
$return = [];
|
||||
if (0 === $limits->count()) {
|
||||
$spent = $opsRepository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end);
|
||||
if (0 !== bccomp($spent, '0')) {
|
||||
$return[$budget->name]['spent'] = bcmul($spent, '-1');
|
||||
$return[$budget->name]['left'] = 0;
|
||||
$return[$budget->name]['overspent'] = 0;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
$rows = $this->spentInPeriodMulti($budget, $limits);
|
||||
foreach ($rows as $name => $row) {
|
||||
if (0 !== bccomp($row['spent'], '0') || 0 !== bccomp($row['left'], '0')) {
|
||||
$return[$name] = $row;
|
||||
}
|
||||
}
|
||||
unset($rows);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all budget limits for a budget.
|
||||
*
|
||||
@@ -425,48 +219,6 @@ trait AugumentData
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that groups expenses.
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function groupByBudget(array $array): array // filter + group data
|
||||
{
|
||||
// group by category ID:
|
||||
$grouped = [];
|
||||
/** @var array $journal */
|
||||
foreach ($array as $journal) {
|
||||
$budgetId = (int)$journal['budget_id'];
|
||||
$grouped[$budgetId] = $grouped[$budgetId] ?? '0';
|
||||
$grouped[$budgetId] = bcadd($journal['amount'], $grouped[$budgetId]);
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group transactions by category.
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function groupByCategory(array $array): array // filter + group data
|
||||
{
|
||||
// group by category ID:
|
||||
$grouped = [];
|
||||
/** @var array $journal */
|
||||
foreach ($array as $journal) {
|
||||
$categoryId = (int)$journal['category_id'];
|
||||
$grouped[$categoryId] = $grouped[$categoryId] ?? '0';
|
||||
$grouped[$categoryId] = bcadd($journal['amount'], $grouped[$categoryId]);
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group set of transactions by name of opposing account.
|
||||
*
|
||||
@@ -496,147 +248,6 @@ trait AugumentData
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group transactions by tag.
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function groupByTag(array $array): array // filter + group data
|
||||
{
|
||||
// group by category ID:
|
||||
$grouped = [];
|
||||
/** @var array $journal */
|
||||
foreach ($array as $journal) {
|
||||
$tags = $journal['tags'] ?? [];
|
||||
/**
|
||||
* @var int $id
|
||||
* @var array $tag
|
||||
*/
|
||||
foreach ($tags as $id => $tag) {
|
||||
$grouped[$id] = $grouped[$id] ?? '0';
|
||||
$grouped[$id] = bcadd($journal['amount'], $grouped[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spent by budget.
|
||||
*
|
||||
* @param Collection $assets
|
||||
* @param Collection $opposing
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
protected function spentByBudget(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$total = $assets->merge($opposing);
|
||||
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($total);
|
||||
$collector->withBudgetInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$sum = [];
|
||||
// loop to support multi currency
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = $journal['currency_id'];
|
||||
$budgetName = $journal['budget_name'];
|
||||
$budgetId = (int)$journal['budget_id'];
|
||||
|
||||
// if not set, set to zero:
|
||||
if (!isset($sum[$budgetId][$currencyId])) {
|
||||
$sum[$budgetId] = [
|
||||
'grand_total' => '0',
|
||||
'name' => $budgetName,
|
||||
'per_currency' => [
|
||||
$currencyId => [
|
||||
'sum' => '0',
|
||||
'budget' => [
|
||||
'id' => $budgetId,
|
||||
'name' => $budgetName,
|
||||
],
|
||||
'currency' => [
|
||||
'symbol' => $journal['currency_symbol'],
|
||||
'dp' => $journal['currency_decimal_places'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// add amount
|
||||
$sum[$budgetId]['per_currency'][$currencyId]['sum'] = bcadd(
|
||||
$sum[$budgetId]['per_currency'][$currencyId]['sum'], $journal['amount']
|
||||
);
|
||||
$sum[$budgetId]['grand_total'] = bcadd($sum[$budgetId]['grand_total'], $journal['amount']);
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spent by category.
|
||||
*
|
||||
* @param Collection $assets
|
||||
* @param Collection $opposing
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
protected function spentByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$total = $assets->merge($opposing);
|
||||
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($total);
|
||||
$collector->withCategoryInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$sum = [];
|
||||
// loop to support multi currency
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$categoryName = $journal['category_name'];
|
||||
$categoryId = (int)$journal['category_id'];
|
||||
|
||||
// if not set, set to zero:
|
||||
if (!isset($sum[$categoryId][$currencyId])) {
|
||||
$sum[$categoryId] = [
|
||||
'grand_total' => '0',
|
||||
'name' => $categoryName,
|
||||
'per_currency' => [
|
||||
$currencyId => [
|
||||
'sum' => '0',
|
||||
'category' => [
|
||||
'id' => $categoryId,
|
||||
'name' => $categoryName,
|
||||
],
|
||||
'currency' => [
|
||||
'symbol' => $journal['currency_symbol'],
|
||||
'dp' => $journal['currency_decimal_places'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// add amount
|
||||
$sum[$categoryId]['per_currency'][$currencyId]['sum'] = bcadd(
|
||||
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $journal['amount']
|
||||
);
|
||||
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $journal['amount']);
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spent in a period.
|
||||
*
|
||||
@@ -682,85 +293,4 @@ trait AugumentData
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns an array with the following values:
|
||||
* 0 =>
|
||||
* 'name' => name of budget + repetition
|
||||
* 'left' => left in budget repetition (always zero)
|
||||
* 'overspent' => spent more than budget repetition? (always zero)
|
||||
* 'spent' => actually spent in period for budget
|
||||
* 1 => (etc)
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param Collection $limits
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
protected function spentInPeriodMulti(Budget $budget, Collection $limits): array // get data + augment with info
|
||||
{
|
||||
/** @var BudgetRepositoryInterface $repository */
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
/** @var OperationsRepositoryInterface $opsRepository */
|
||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||
|
||||
$return = [];
|
||||
$format = (string)trans('config.month_and_day');
|
||||
$name = $budget->name;
|
||||
/** @var BudgetLimit $budgetLimit */
|
||||
foreach ($limits as $budgetLimit) {
|
||||
$expenses = $opsRepository->spentInPeriod(new Collection([$budget]), new Collection, $budgetLimit->start_date, $budgetLimit->end_date);
|
||||
$expenses = app('steam')->positive($expenses);
|
||||
|
||||
if ($limits->count() > 1) {
|
||||
$name = $budget->name . ' ' . trans(
|
||||
'firefly.between_dates',
|
||||
[
|
||||
'start' => $budgetLimit->start_date->formatLocalized($format),
|
||||
'end' => $budgetLimit->end_date->formatLocalized($format),
|
||||
]
|
||||
);
|
||||
}
|
||||
$amount = $budgetLimit->amount;
|
||||
$leftInLimit = bcsub($amount, $expenses);
|
||||
$hasOverspent = bccomp($leftInLimit, '0') === -1;
|
||||
$left = $hasOverspent ? '0' : bcsub($amount, $expenses);
|
||||
$spent = $hasOverspent ? $amount : $expenses;
|
||||
$overspent = $hasOverspent ? app('steam')->positive($leftInLimit) : '0';
|
||||
|
||||
$return[$name] = [
|
||||
'left' => $left,
|
||||
'overspent' => $overspent,
|
||||
'spent' => $spent,
|
||||
];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with the following values:
|
||||
* 'name' => "no budget" in local language
|
||||
* 'repetition_left' => left in budget repetition (always zero)
|
||||
* 'repetition_overspent' => spent more than budget repetition? (always zero)
|
||||
* 'spent' => actually spent in period for budget.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function spentInPeriodWithout(Carbon $start, Carbon $end): string // get data + augment with info
|
||||
{
|
||||
// collector
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$types = [TransactionType::WITHDRAWAL];
|
||||
$collector->setTypes($types)->setRange($start, $end)->withoutBudget();
|
||||
|
||||
return $collector->getSum();
|
||||
}
|
||||
}
|
||||
|
@@ -575,8 +575,7 @@ trait PeriodOverview
|
||||
$return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $journal['amount'] ?? '0');
|
||||
$return[$currencyId]['count']++;
|
||||
|
||||
|
||||
if (null !== $foreignCurrencyId) {
|
||||
if (null !== $foreignCurrencyId && null !== $journal['foreign_amount']) {
|
||||
if (!isset($return[$foreignCurrencyId])) {
|
||||
$return[$foreignCurrencyId] = [
|
||||
'amount' => '0',
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user