Reorganize project part 2

This commit is contained in:
Bernd Bestel 2018-04-11 19:49:35 +02:00
parent bcd5092427
commit feb88ab685
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
56 changed files with 1988 additions and 826 deletions

View File

@ -1,66 +0,0 @@
<?php
class GrocyPhpHelper
{
public static function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue)
{
foreach($array as $object)
{
if($object->{$propertyName} == $propertyValue)
{
return $object;
}
}
return null;
}
public static function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyValue, $operator = '==')
{
$returnArray = array();
foreach($array as $object)
{
switch($operator)
{
case '==':
if($object->{$propertyName} == $propertyValue)
{
$returnArray[] = $object;
}
break;
case '>':
if($object->{$propertyName} > $propertyValue)
{
$returnArray[] = $object;
}
break;
case '<':
if($object->{$propertyName} < $propertyValue)
{
$returnArray[] = $object;
}
break;
}
}
return $returnArray;
}
public static function SumArrayValue($array, $propertyName)
{
$sum = 0;
foreach($array as $object)
{
$sum += $object->{$propertyName};
}
return $sum;
}
public static function GetClassConstants($className)
{
$r = new ReflectionClass($className);
return $r->getConstants();
}
}

View File

@ -1,8 +1,15 @@
{ {
"require": { "require": {
"slim/slim": "^3.8", "slim/slim": "^3.8",
"slim/php-view": "^2.2",
"morris/lessql": "^0.3.4", "morris/lessql": "^0.3.4",
"pavlakis/slim-cli": "^1.0" "pavlakis/slim-cli": "^1.0",
"rubellum/slim-blade-view": "^0.1.1"
},
"autoload": {
"psr-4": {
"Grocy\\Services\\": "services/",
"Grocy\\Controllers\\": "controllers/",
"Grocy\\Middleware\\": "middleware/"
}
} }
} }

807
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "bf75d2487343249c600746a03f63cfd2", "content-hash": "12ebab60e283dfdab831d1cc22430d05",
"packages": [ "packages": [
{ {
"name": "container-interop/container-interop", "name": "container-interop/container-interop",
@ -37,6 +37,363 @@
"homepage": "https://github.com/container-interop/container-interop", "homepage": "https://github.com/container-interop/container-interop",
"time": "2017-02-14T19:40:03+00:00" "time": "2017-02-14T19:40:03+00:00"
}, },
{
"name": "doctrine/inflector",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "5527a48b7313d15261292c149e55e26eae771b0a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a",
"reference": "5527a48b7313d15261292c149e55e26eae771b0a",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^6.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"inflection",
"pluralize",
"singularize",
"string"
],
"time": "2018-01-09T20:05:19+00:00"
},
{
"name": "illuminate/container",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
"reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/container/zipball/4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
"reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
"shasum": ""
},
"require": {
"illuminate/contracts": "5.6.*",
"php": "^7.1.3",
"psr/container": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Container\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Container package.",
"homepage": "https://laravel.com",
"time": "2018-01-21T02:13:38+00:00"
},
{
"name": "illuminate/contracts",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
"reference": "322ec80498b3bf85bc4025d028e130a9b50242b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/322ec80498b3bf85bc4025d028e130a9b50242b9",
"reference": "322ec80498b3bf85bc4025d028e130a9b50242b9",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/container": "~1.0",
"psr/simple-cache": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Contracts\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Contracts package.",
"homepage": "https://laravel.com",
"time": "2018-04-07T17:05:26+00:00"
},
{
"name": "illuminate/events",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/events.git",
"reference": "b6e73ed40478cef2ef98d5ddb27f333291606cea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/events/zipball/b6e73ed40478cef2ef98d5ddb27f333291606cea",
"reference": "b6e73ed40478cef2ef98d5ddb27f333291606cea",
"shasum": ""
},
"require": {
"illuminate/container": "5.6.*",
"illuminate/contracts": "5.6.*",
"illuminate/support": "5.6.*",
"php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Events\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Events package.",
"homepage": "https://laravel.com",
"time": "2018-02-26T19:00:55+00:00"
},
{
"name": "illuminate/filesystem",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/filesystem.git",
"reference": "c9ab9376076cedd88a374d7281d62b619634d578"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/filesystem/zipball/c9ab9376076cedd88a374d7281d62b619634d578",
"reference": "c9ab9376076cedd88a374d7281d62b619634d578",
"shasum": ""
},
"require": {
"illuminate/contracts": "5.6.*",
"illuminate/support": "5.6.*",
"php": "^7.1.3",
"symfony/finder": "~4.0"
},
"suggest": {
"league/flysystem": "Required to use the Flysystem local and FTP drivers (~1.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
"league/flysystem-cached-adapter": "Required to use the Flysystem cache (~1.0).",
"league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).",
"league/flysystem-sftp": "Required to use the Flysystem SFTP driver (~1.0)."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Filesystem\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Filesystem package.",
"homepage": "https://laravel.com",
"time": "2018-04-06T13:15:37+00:00"
},
{
"name": "illuminate/support",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
"reference": "fad0669f858423679497a17f973261cc32f9a5a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/support/zipball/fad0669f858423679497a17f973261cc32f9a5a8",
"reference": "fad0669f858423679497a17f973261cc32f9a5a8",
"shasum": ""
},
"require": {
"doctrine/inflector": "~1.1",
"ext-mbstring": "*",
"illuminate/contracts": "5.6.*",
"nesbot/carbon": "^1.24.1",
"php": "^7.1.3"
},
"conflict": {
"tightenco/collect": "<5.5.33"
},
"suggest": {
"illuminate/filesystem": "Required to use the composer class (5.6.*).",
"symfony/process": "Required to use the composer class (~4.0).",
"symfony/var-dumper": "Required to use the dd function (~4.0)."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Support\\": ""
},
"files": [
"helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Support package.",
"homepage": "https://laravel.com",
"time": "2018-04-05T21:19:22+00:00"
},
{
"name": "illuminate/view",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/view.git",
"reference": "54eaf45ee7946d8f8cde13d5e89c5ea2e997040d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/view/zipball/54eaf45ee7946d8f8cde13d5e89c5ea2e997040d",
"reference": "54eaf45ee7946d8f8cde13d5e89c5ea2e997040d",
"shasum": ""
},
"require": {
"illuminate/container": "5.6.*",
"illuminate/contracts": "5.6.*",
"illuminate/events": "5.6.*",
"illuminate/filesystem": "5.6.*",
"illuminate/support": "5.6.*",
"php": "^7.1.3",
"symfony/debug": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\View\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate View package.",
"homepage": "https://laravel.com",
"time": "2018-04-03T12:56:35+00:00"
},
{ {
"name": "morris/lessql", "name": "morris/lessql",
"version": "v0.3.5", "version": "v0.3.5",
@ -85,6 +442,59 @@
], ],
"time": "2018-01-27T13:18:21+00:00" "time": "2018-01-27T13:18:21+00:00"
}, },
{
"name": "nesbot/carbon",
"version": "1.25.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cbcf13da0b531767e39eb86e9687f5deba9857b4",
"reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/translation": "~2.6 || ~3.0 || ~4.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2",
"phpunit/phpunit": "^4.8.35 || ^5.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.23-dev"
}
},
"autoload": {
"psr-4": {
"Carbon\\": "src/Carbon/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brian Nesbitt",
"email": "brian@nesbot.com",
"homepage": "http://nesbot.com"
}
],
"description": "A simple API extension for DateTime.",
"homepage": "http://carbon.nesbot.com",
"keywords": [
"date",
"datetime",
"time"
],
"time": "2018-03-19T15:50:49+00:00"
},
{ {
"name": "nikic/fast-route", "name": "nikic/fast-route",
"version": "v1.3.0", "version": "v1.3.0",
@ -180,6 +590,47 @@
], ],
"time": "2017-01-30T22:50:06+00:00" "time": "2017-01-30T22:50:06+00:00"
}, },
{
"name": "philo/laravel-blade",
"version": "v3.1",
"source": {
"type": "git",
"url": "https://github.com/PhiloNL/Laravel-Blade.git",
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PhiloNL/Laravel-Blade/zipball/3f0ce2ee198604c53c25188110e6d7b5e887527a",
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a",
"shasum": ""
},
"require": {
"illuminate/events": "~5",
"illuminate/view": "~5"
},
"type": "library",
"autoload": {
"psr-4": {
"Philo\\Blade\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Philo Hermans",
"email": "me@philohermans.com"
}
],
"description": "Use the simple and yet powerful Laravel Blade templating engine as a standalone component.",
"keywords": [
"blade",
"laravel"
],
"time": "2015-12-04T09:42:42+00:00"
},
{ {
"name": "pimple/pimple", "name": "pimple/pimple",
"version": "v3.2.3", "version": "v3.2.3",
@ -330,24 +781,121 @@
"time": "2016-08-06T14:39:51+00:00" "time": "2016-08-06T14:39:51+00:00"
}, },
{ {
"name": "slim/php-view", "name": "psr/log",
"version": "2.2.0", "version": "1.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/slimphp/PHP-View.git", "url": "https://github.com/php-fig/log.git",
"reference": "122ed121a8d9cf91a94020814d2a3ee6c836754f" "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/slimphp/PHP-View/zipball/122ed121a8d9cf91a94020814d2a3ee6c836754f", "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"reference": "122ed121a8d9cf91a94020814d2a3ee6c836754f", "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2016-10-10T12:19:37+00:00"
},
{
"name": "psr/simple-cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for simple caching",
"keywords": [
"cache",
"caching",
"psr",
"psr-16",
"simple-cache"
],
"time": "2017-10-23T01:57:42+00:00"
},
{
"name": "rubellum/slim-blade-view",
"version": "0.1.1",
"source": {
"type": "git",
"url": "https://github.com/rubellum/Slim-Blade-View.git",
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/rubellum/Slim-Blade-View/zipball/9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
"shasum": ""
},
"require": {
"illuminate/view": "5.*",
"philo/laravel-blade": "3.*",
"psr/http-message": "^1.0" "psr/http-message": "^1.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8", "phpunit/phpunit": "^5.0",
"slim/slim": "^3.0" "slim/slim": "^3.0"
}, },
"type": "library", "type": "library",
@ -362,21 +910,20 @@
], ],
"authors": [ "authors": [
{ {
"name": "Glenn Eggleton", "name": "Hiroaki Matsuura",
"email": "geggleto@gmail.com" "email": "hiropeke.jp@gmail.com"
} }
], ],
"description": "Render PHP view scripts into a PSR-7 Response object.", "description": "Slim Framework 3 view helper built on the Blade component",
"keywords": [ "keywords": [
"blade",
"framework", "framework",
"php",
"phtml",
"renderer", "renderer",
"slim", "slim",
"template", "template",
"view" "view"
], ],
"time": "2016-10-11T07:43:08+00:00" "time": "2016-03-11T02:32:00+00:00"
}, },
{ {
"name": "slim/slim", "name": "slim/slim",
@ -448,6 +995,238 @@
"router" "router"
], ],
"time": "2017-11-26T19:13:09+00:00" "time": "2017-11-26T19:13:09+00:00"
},
{
"name": "symfony/debug",
"version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "5961d02d48828671f5d8a7805e06579d692f6ede"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/5961d02d48828671f5d8a7805e06579d692f6ede",
"reference": "5961d02d48828671f5d8a7805e06579d692f6ede",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/log": "~1.0"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "~3.4|~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2018-04-03T05:24:00+00:00"
},
{
"name": "symfony/finder",
"version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
"reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2018-04-04T05:10:37+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.7.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.7-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"time": "2018-01-30T19:27:44+00:00"
},
{
"name": "symfony/translation",
"version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/e20a9b7f9f62cb33a11638b345c248e7d510c938",
"reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/config": "<3.4",
"symfony/dependency-injection": "<3.4",
"symfony/yaml": "<3.4"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/finder": "~2.8|~3.0|~4.0",
"symfony/intl": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"psr/log": "To use logging capability in translator",
"symfony/config": "",
"symfony/yaml": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Translation\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
"time": "2018-02-22T10:50:29+00:00"
} }
], ],
"packages-dev": [], "packages-dev": [],

View File

@ -0,0 +1,11 @@
<?php
namespace Grocy\Controllers;
class BaseApiController extends BaseController
{
protected function ApiEncode($response)
{
return json_encode($response);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\DatabaseService;
class BaseController
{
public function __construct(\Slim\Container $container) {
$this->AppContainer = $container;
$databaseService = new DatabaseService();
$this->Database = $databaseService->GetDbConnection();
}
protected $AppContainer;
protected $Database;
}

View File

@ -0,0 +1,32 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\BatteriesService;
class BatteriesApiController extends BaseApiController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->BatteriesService = new BatteriesService();
}
protected $BatteriesService;
public function TrackChargeCycle($request, $response, $args)
{
$trackedTime = date('Y-m-d H:i:s');
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
{
$trackedTime = $request->getQueryParams()['tracked_time'];
}
return $this->ApiEncode(array('success' => $this->BatteriesService->TrackChargeCycle($args['batteryId'], $trackedTime)));
}
public function BatteryDetails($request, $response, $args)
{
return $this->ApiEncode($this->BatteriesService->GetBatteryDetails($args['batteryId']));
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\BatteriesService;
class BatteriesController extends BaseController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->BatteriesService = new BatteriesService();
}
protected $BatteriesService;
public function Overview($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'batteriesoverview', [
'title' => 'Batteries overview',
'contentPage' => 'batteriesoverview.php',
'batteries' => $this->Database->batteries(),
'current' => $this->BatteriesService->GetCurrent(),
]);
}
public function TrackChargeCycle($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'batterytracking', [
'title' => 'Battery tracking',
'contentPage' => 'batterytracking.php',
'batteries' => $this->Database->batteries()
]);
}
public function BatteriesList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'batteries', [
'title' => 'Batteries',
'contentPage' => 'batteries.php',
'batteries' => $this->Database->batteries()
]);
}
public function BatteryEditForm($request, $response, $args)
{
if ($args['batteryId'] == 'new')
{
return $this->AppContainer->view->render($response, 'batteryform', [
'title' => 'Create battery',
'contentPage' => 'batteryform.php',
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'batteryform', [
'title' => 'Edit battery',
'contentPage' => 'batteryform.php',
'battery' => $this->Database->batteries($args['batteryId']),
'mode' => 'edit'
]);
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\ApplicationService;
use Grocy\Services\DatabaseMigrationService;
class CliController extends BaseController
{
public function RecreateDemo($request, $response, $args)
{
$applicationService = new ApplicationService();
if ($applicationService->IsDemoInstallation())
{
$databaseMigrationService = new DatabaseMigrationService();
$databaseMigrationService->RecreateDemo();
}
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Grocy\Controllers;
class GenericEntityApiController extends BaseApiController
{
public function GetObjects($request, $response, $args)
{
return $this->ApiEncode($this->Database->{$args['entity']}());
}
public function GetObject($request, $response, $args)
{
return $this->ApiEncode($this->Database->{$args['entity']}($args['objectId']));
}
public function AddObject($request, $response, $args)
{
$newRow = $this->Database->{$args['entity']}()->createRow($request->getParsedBody());
$newRow->save();
$success = $newRow->isClean();
return $this->ApiEncode(array('success' => $success));
}
public function EditObject($request, $response, $args)
{
$row = $this->Database->{$args['entity']}($args['objectId']);
$row->update($request->getParsedBody());
$success = $row->isClean();
return $this->ApiEncode(array('success' => $success));
}
public function DeleteObject($request, $response, $args)
{
$row = $this->Database->{$args['entity']}($args['objectId']);
$row->delete();
$success = $row->isClean();
return $this->ApiEncode(array('success' => $success));
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\HabitsService;
class HabitsApiController extends BaseApiController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->HabitsService = new HabitsService();
}
protected $HabitsService;
public function TrackHabitExecution($request, $response, $args)
{
$trackedTime = date('Y-m-d H:i:s');
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
{
$trackedTime = $request->getQueryParams()['tracked_time'];
}
return $this->ApiEncode(array('success' => $this->HabitsService->TrackHabit($args['habitId'], $trackedTime)));
}
public function HabitDetails($request, $response, $args)
{
return $this->ApiEncode($this->HabitsService->GetHabitDetails($args['habitId']));
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\HabitsService;
class HabitsController extends BaseController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->HabitsService = new HabitsService();
}
protected $HabitsService;
public function Overview($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'habitsoverview', [
'title' => 'Habits overview',
'contentPage' => 'habitsoverview.php',
'habits' => $this->Database->habits(),
'currentHabits' => $this->HabitsService->GetCurrentHabits(),
]);
}
public function TrackHabitExecution($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'habittracking', [
'title' => 'Habit tracking',
'contentPage' => 'habittracking.php',
'habits' => $this->Database->habits()
]);
}
public function HabitsList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'habits', [
'title' => 'Habits',
'contentPage' => 'habits.php',
'habits' => $this->Database->habits()
]);
}
public function HabitEditForm($request, $response, $args)
{
if ($args['habitId'] == 'new')
{
return $this->AppContainer->view->render($response, 'habitform', [
'title' => 'Create habit',
'contentPage' => 'habitform.php',
'periodTypes' => GetClassConstants('Grocy\Services\HabitsService'),
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'habitform', [
'title' => 'Edit habit',
'contentPage' => 'habitform.php',
'habit' => $this->Database->habits($args['habitId']),
'periodTypes' => GetClassConstants('Grocy\Services\HabitsService'),
'mode' => 'edit'
]);
}
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\SessionService;
use Grocy\Services\DatabaseService;
use Grocy\Services\ApplicationService;
use Grocy\Services\DatabaseMigrationService;
use Grocy\Services\DemoDataGeneratorService;
class LoginController extends BaseController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->SessionService = new SessionService();
}
protected $SessionService;
public function ProcessLogin($request, $response, $args)
{
$postParams = $request->getParsedBody();
if (isset($postParams['username']) && isset($postParams['password']))
{
if ($postParams['username'] === HTTP_USER && $postParams['password'] === HTTP_PASSWORD)
{
$sessionKey = $this->SessionService->CreateSession();
setcookie('grocy_session', $sessionKey, time()+2592000); //30 days
return $response->withRedirect('/');
}
else
{
return $response->withRedirect('/login?invalid=true');
}
}
else
{
return $response->withRedirect('/login?invalid=true');
}
}
public function LoginPage($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'login', [
'title' => 'Login',
'contentPage' => 'login.php'
]);
}
public function Logout($request, $response, $args)
{
$this->SessionService->RemoveSession($_COOKIE['grocy_session']);
return $response->withRedirect('/');
}
public function Root($request, $response, $args)
{
// Schema migration is done here
$databaseMigrationService = new DatabaseMigrationService();
$databaseMigrationService->MigrateDatabase();
$applicationService = new ApplicationService();
if ($applicationService->IsDemoInstallation())
{
$demoDataGeneratorService = new DemoDataGeneratorService();
$demoDataGeneratorService->PopulateDemoData();
}
return $response->withRedirect('/stockoverview');
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\StockService;
class StockApiController extends BaseApiController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->StockService = new StockService();
}
protected $StockService;
public function ProductDetails($request, $response, $args)
{
return $this->ApiEncode($this->StockService->GetProductDetails($args['productId']));
}
public function AddProduct($request, $response, $args)
{
$bestBeforeDate = date('Y-m-d');
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
{
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
}
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
{
$transactionType = $request->getQueryParams()['transactiontype'];
}
return $this->ApiEncode(array('success' => $this->StockService->AddProduct($args['productId'], $args['amount'], $bestBeforeDate, $transactionType)));
}
public function ConsumeProduct($request, $response, $args)
{
$spoiled = false;
if (isset($request->getQueryParams()['spoiled']) && !empty($request->getQueryParams()['spoiled']) && $request->getQueryParams()['spoiled'] == '1')
{
$spoiled = true;
}
$transactionType = StockService::TRANSACTION_TYPE_CONSUME;
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
{
$transactionType = $request->getQueryParams()['transactiontype'];
}
return $this->ApiEncode(array('success' => $this->StockService->ConsumeProduct($args['productId'], $args['amount'], $spoiled, $transactionType)));
}
public function InventoryProduct($request, $response, $args)
{
$bestBeforeDate = date('Y-m-d');
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
{
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
}
return $this->ApiEncode(array('success' => $this->StockService->InventoryProduct($args['productId'], $args['newAmount'], $bestBeforeDate)));
}
public function CurrentStock($request, $response, $args)
{
return $this->ApiEncode($this->StockService->GetCurrentStock());
}
public function AddmissingProductsToShoppingList($request, $response, $args)
{
$this->StockService->AddMissingProductsToShoppingList();
return $this->ApiEncode(array('success' => true));
}
}

View File

@ -0,0 +1,187 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\StockService;
class StockController extends BaseController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->StockService = new StockService();
}
protected $StockService;
public function Overview($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'stockoverview', [
'title' => 'Stock overview',
'contentPage' => 'stockoverview.php',
'products' => $this->Database->products(),
'quantityunits' => $this->Database->quantity_units(),
'currentStock' => $this->StockService->GetCurrentStock(),
'missingProducts' => $this->StockService->GetMissingProducts()
]);
}
public function Purchase($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'purchase', [
'title' => 'Purchase',
'contentPage' => 'purchase.php',
'products' => $this->Database->products()
]);
}
public function Consume($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'consume', [
'title' => 'Consume',
'contentPage' => 'consume.php',
'products' => $this->Database->products()
]);
}
public function Inventory($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'inventory', [
'title' => 'Inventory',
'contentPage' => 'inventory.php',
'products' => $this->Database->products()
]);
}
public function ShoppingList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'shoppinglist', [
'title' => 'Shopping list',
'contentPage' => 'shoppinglist.php',
'listItems' => $this->Database->shopping_list(),
'products' => $this->Database->products(),
'quantityunits' => $this->Database->quantity_units(),
'missingProducts' => $this->StockService->GetMissingProducts()
]);
}
public function ProductsList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'products', [
'title' => 'Products',
'contentPage' => 'products.php',
'products' => $this->Database->products(),
'locations' => $this->Database->locations(),
'quantityunits' => $this->Database->quantity_units()
]);
}
public function LocationsList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'locations', [
'title' => 'Locations',
'contentPage' => 'locations.php',
'locations' => $this->Database->locations()
]);
}
public function QuantityUnitsList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'quantityunits', [
'title' => 'Quantity units',
'contentPage' => 'quantityunits.php',
'quantityunits' => $this->Database->quantity_units()
]);
}
public function ProductEditForm($request, $response, $args)
{
if ($args['productId'] == 'new')
{
return $this->AppContainer->view->render($response, 'productform', [
'title' => 'Create product',
'contentPage' => 'productform.php',
'locations' => $this->Database->locations(),
'quantityunits' => $this->Database->quantity_units(),
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'productform', [
'title' => 'Edit product',
'contentPage' => 'productform.php',
'product' => $this->Database->products($args['productId']),
'locations' => $this->Database->locations(),
'quantityunits' => $this->Database->quantity_units(),
'mode' => 'edit'
]);
}
}
public function LocationEditForm($request, $response, $args)
{
if ($args['locationId'] == 'new')
{
return $this->AppContainer->view->render($response, 'locationform', [
'title' => 'Create location',
'contentPage' => 'locationform.php',
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'locationform', [
'title' => 'Edit location',
'contentPage' => 'locationform.php',
'location' => $this->Database->locations($args['locationId']),
'mode' => 'edit'
]);
}
}
public function QuantityUnitEditForm($request, $response, $args)
{
if ($args['quantityunitId'] == 'new')
{
return $this->AppContainer->view->render($response, 'quantityunitform', [
'title' => 'Create quantity unit',
'contentPage' => 'quantityunitform.php',
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'quantityunitform', [
'title' => 'Edit quantity unit',
'contentPage' => 'quantityunitform.php',
'quantityunit' => $this->Database->quantity_units($args['quantityunitId']),
'mode' => 'edit'
]);
}
}
public function ShoppingListItemEditForm($request, $response, $args)
{
if ($args['itemId'] == 'new')
{
return $this->AppContainer->view->render($response, 'shoppinglistform', [
'title' => 'Add shopping list item',
'contentPage' => 'shoppinglistform.php',
'products' => $this->Database->products(),
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'shoppinglistform', [
'title' => 'Edit shopping list item',
'contentPage' => 'shoppinglistform.php',
'listItem' => $this->Database->shopping_list($args['itemId']),
'products' => $this->Database->products(),
'mode' => 'edit'
]);
}
}
}

1
data/.gitignore vendored
View File

@ -1,2 +1,3 @@
* *
!.gitignore !.gitignore
!viewcache

2
data/viewcache/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

63
extensions.php Normal file
View File

@ -0,0 +1,63 @@
<?php
function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue)
{
foreach($array as $object)
{
if($object->{$propertyName} == $propertyValue)
{
return $object;
}
}
return null;
}
function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyValue, $operator = '==')
{
$returnArray = array();
foreach($array as $object)
{
switch($operator)
{
case '==':
if($object->{$propertyName} == $propertyValue)
{
$returnArray[] = $object;
}
break;
case '>':
if($object->{$propertyName} > $propertyValue)
{
$returnArray[] = $object;
}
break;
case '<':
if($object->{$propertyName} < $propertyValue)
{
$returnArray[] = $object;
}
break;
}
}
return $returnArray;
}
function SumArrayValue($array, $propertyName)
{
$sum = 0;
foreach($array as $object)
{
$sum += $object->{$propertyName};
}
return $sum;
}
function GetClassConstants($className)
{
$r = new ReflectionClass($className);
return $r->getConstants();
}

583
index.php
View File

@ -2,22 +2,19 @@
use \Psr\Http\Message\ServerRequestInterface as Request; use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response; use \Psr\Http\Message\ResponseInterface as Response;
use Slim\Views\PhpRenderer;
use Grocy\Middleware\SessionMiddleware;
use Grocy\Middleware\JsonMiddleware;
use Grocy\Middleware\CliMiddleware;
use Grocy\Services\ApplicationService;
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/data/config.php'; require_once __DIR__ . '/data/config.php';
require_once __DIR__ . '/services/ApplicationService.php'; require_once __DIR__ . '/extensions.php';
require_once __DIR__ . '/services/DatabaseService.php';
require_once __DIR__ . '/services/SessionService.php';
require_once __DIR__ . '/GrocyDbMigrator.php';
require_once __DIR__ . '/GrocyDemoDataGenerator.php';
require_once __DIR__ . '/services/StockService.php';
require_once __DIR__ . '/services/HabitsService.php';
require_once __DIR__ . '/services/BatteriesService.php';
require_once __DIR__ . '/GrocyPhpHelper.php';
// Setup base application
$app = new \Slim\App; $app = new \Slim\App;
if (PHP_SAPI !== 'cli') if (PHP_SAPI !== 'cli')
{ {
$app = new \Slim\App(new \Slim\Container([ $app = new \Slim\App(new \Slim\Container([
@ -26,508 +23,92 @@ if (PHP_SAPI !== 'cli')
'determineRouteBeforeAppMiddleware' => true 'determineRouteBeforeAppMiddleware' => true
], ],
])); ]));
$container = $app->getContainer(); $container = $app->getContainer();
$container['renderer'] = new PhpRenderer('./views'); $container['view'] = function($container)
}
if (PHP_SAPI === 'cli')
{
$app->add(new \pavlakis\cli\CliRequest());
}
if (!ApplicationService::IsDemoInstallation())
{
$sessionMiddleware = function(Request $request, Response $response, callable $next)
{ {
$route = $request->getAttribute('route'); return new \Slim\Views\Blade(__DIR__ . '/views', __DIR__ . '/data/viewcache');
$routeName = $route->getName();
if ((!isset($_COOKIE['grocy_session']) || !SessionService::IsValidSession($_COOKIE['grocy_session'])) && $routeName !== 'login')
{
$response = $response->withRedirect('/login');
}
else
{
$response = $next($request, $response);
}
return $response;
}; };
}
$app->add($sessionMiddleware); else
{
$app->add(\pavlakis\cli\CliRequest::class);
} }
$db = DatabaseService::GetDbConnection(); // Add session handling if this is not a demo installation
$applicationService = new ApplicationService();
$app->get('/login', function(Request $request, Response $response) if (!$applicationService->IsDemoInstallation())
{ {
return $this->renderer->render($response, 'layout/default.php', [ $app->add(SessionMiddleware::class);
'title' => 'Login', }
'contentPage' => 'login.php'
]);
})->setName('login');
$app->post('/login', function(Request $request, Response $response) // Base route
$app->get('/', 'Grocy\Controllers\LoginController:Root');
// Login routes
$app->get('/login', 'Grocy\Controllers\LoginController:LoginPage')->setName('login');
$app->post('/login', 'Grocy\Controllers\LoginController:ProcessLogin')->setName('login');
$app->get('/logout', 'Grocy\Controllers\LoginController:Logout');
// Stock routes
$app->get('/stockoverview', 'Grocy\Controllers\StockController:Overview');
$app->get('/purchase', 'Grocy\Controllers\StockController:Purchase');
$app->get('/consume', 'Grocy\Controllers\StockController:Consume');
$app->get('/inventory', 'Grocy\Controllers\StockController:Inventory');
$app->get('/products', 'Grocy\Controllers\StockController:ProductsList');
$app->get('/product/{productId}', 'Grocy\Controllers\StockController:ProductEditForm');
$app->get('/locations', 'Grocy\Controllers\StockController:LocationsList');
$app->get('/location/{locationId}', 'Grocy\Controllers\StockController:LocationEditForm');
$app->get('/quantityunits', 'Grocy\Controllers\StockController:QuantityUnitsList');
$app->get('/quantityunit/{quantityunitId}', 'Grocy\Controllers\StockController:QuantityUnitEditForm');
$app->get('/shoppinglist', 'Grocy\Controllers\StockController:ShoppingList');
$app->get('/shoppinglistitem/{itemId}', 'Grocy\Controllers\StockController:ShoppingListItemEditForm');
// Habit routes
$app->get('/habitsoverview', 'Grocy\Controllers\HabitsController:Overview');
$app->get('/habittracking', 'Grocy\Controllers\HabitsController:TrackHabitExecution');
$app->get('/habits', 'Grocy\Controllers\HabitsController:HabitsList');
$app->get('/habit/{habitId}', 'Grocy\Controllers\HabitsController:HabitEditForm');
// Batterry routes
$app->get('/batteriesoverview', 'Grocy\Controllers\BatteriesController:Overview');
$app->get('/batterytracking', 'Grocy\Controllers\BatteriesController:TrackChargeCycle');
$app->get('/batteries', 'Grocy\Controllers\BatteriesController:BatteriesList');
$app->get('/battery/{batteryId}', 'Grocy\Controllers\BatteriesController:BatteryEditForm');
$app->group('/api', function()
{ {
$postParams = $request->getParsedBody(); $this->get('/get-objects/{entity}', 'Grocy\Controllers\GenericEntityApiController:GetObjects');
if (isset($postParams['username']) && isset($postParams['password'])) $this->get('/get-object/{entity}/{objectId}', 'Grocy\Controllers\GenericEntityApiController:GetObject');
{ $this->post('/add-object/{entity}', 'Grocy\Controllers\GenericEntityApiController:AddObject');
if ($postParams['username'] === HTTP_USER && $postParams['password'] === HTTP_PASSWORD) $this->post('/edit-object/{entity}/{objectId}', 'Grocy\Controllers\GenericEntityApiController:EditObject');
{ $this->get('/delete-object/{entity}/{objectId}', 'Grocy\Controllers\GenericEntityApiController:DeleteObject');
$sessionKey = SessionService::CreateSession();
setcookie('grocy_session', $sessionKey, time()+2592000); //30 days
return $response->withRedirect('/'); $this->get('/stock/add-product/{productId}/{amount}', 'Grocy\Controllers\StockApiController:AddProduct');
} $this->get('/stock/consume-product/{productId}/{amount}', 'Grocy\Controllers\StockApiController:ConsumeProduct');
else $this->get('/stock/inventory-product/{productId}/{newAmount}', 'Grocy\Controllers\StockApiController:InventoryProduct');
{ $this->get('/stock/get-product-details/{productId}', 'Grocy\Controllers\StockApiController:ProductDetails');
return $response->withRedirect('/login?invalid=true'); $this->get('/stock/get-current-stock', 'Grocy\Controllers\StockApiController:CurrentStock');
} $this->get('/stock/add-missing-products-to-shoppinglist', 'Grocy\Controllers\StockApiController:AddMissingProductsToShoppingList');
}
else
{
return $response->withRedirect('/login?invalid=true');
}
})->setName('login');
$app->get('/logout', function(Request $request, Response $response) $this->get('/habits/track-habit-execution/{habitId}', 'Grocy\Controllers\HabitsApiController:TrackHabitExecution');
{ $this->get('/habits/get-habit-details/{habitId}', 'Grocy\Controllers\HabitsApiController:HabitDetails');
SessionService::RemoveSession($_COOKIE['grocy_session']);
return $response->withRedirect('/'); $this->get('/batteries/track-charge-cycle/{batteryId}', 'Grocy\Controllers\BatteriesApiController:TrackChargeCycle');
}); $this->get('/batteries/get-battery-details/{batteryId}', 'Grocy\Controllers\BatteriesApiController:BatteryDetails');
})->add(JsonMiddleware::class);
$app->get('/', function(Request $request, Response $response) use($db)
{
$db = DatabaseService::GetDbConnection(true); //For database schema migration
return $response->withRedirect('/stockoverview');
});
$app->get('/stockoverview', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Stock overview',
'contentPage' => 'stockoverview.php',
'products' => $db->products(),
'quantityunits' => $db->quantity_units(),
'currentStock' => StockService::GetCurrentStock(),
'missingProducts' => StockService::GetMissingProducts()
]);
});
$app->get('/habitsoverview', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Habits overview',
'contentPage' => 'habitsoverview.php',
'habits' => $db->habits(),
'currentHabits' => HabitsService::GetCurrentHabits(),
]);
});
$app->get('/batteriesoverview', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Batteries overview',
'contentPage' => 'batteriesoverview.php',
'batteries' => $db->batteries(),
'current' => BatteriesService::GetCurrent(),
]);
});
$app->get('/purchase', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Purchase',
'contentPage' => 'purchase.php',
'products' => $db->products()
]);
});
$app->get('/consume', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Consume',
'contentPage' => 'consume.php',
'products' => $db->products()
]);
});
$app->get('/inventory', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Inventory',
'contentPage' => 'inventory.php',
'products' => $db->products()
]);
});
$app->get('/shoppinglist', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Shopping list',
'contentPage' => 'shoppinglist.php',
'listItems' => $db->shopping_list(),
'products' => $db->products(),
'quantityunits' => $db->quantity_units(),
'missingProducts' => StockService::GetMissingProducts()
]);
});
$app->get('/habittracking', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Habit tracking',
'contentPage' => 'habittracking.php',
'habits' => $db->habits()
]);
});
$app->get('/batterytracking', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Battery tracking',
'contentPage' => 'batterytracking.php',
'batteries' => $db->batteries()
]);
});
$app->get('/products', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Products',
'contentPage' => 'products.php',
'products' => $db->products(),
'locations' => $db->locations(),
'quantityunits' => $db->quantity_units()
]);
});
$app->get('/locations', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Locations',
'contentPage' => 'locations.php',
'locations' => $db->locations()
]);
});
$app->get('/quantityunits', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Quantity units',
'contentPage' => 'quantityunits.php',
'quantityunits' => $db->quantity_units()
]);
});
$app->get('/habits', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Habits',
'contentPage' => 'habits.php',
'habits' => $db->habits()
]);
});
$app->get('/batteries', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Batteries',
'contentPage' => 'batteries.php',
'batteries' => $db->batteries()
]);
});
$app->get('/product/{productId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['productId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create product',
'contentPage' => 'productform.php',
'locations' => $db->locations(),
'quantityunits' => $db->quantity_units(),
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit product',
'contentPage' => 'productform.php',
'product' => $db->products($args['productId']),
'locations' => $db->locations(),
'quantityunits' => $db->quantity_units(),
'mode' => 'edit'
]);
}
});
$app->get('/location/{locationId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['locationId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create location',
'contentPage' => 'locationform.php',
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit location',
'contentPage' => 'locationform.php',
'location' => $db->locations($args['locationId']),
'mode' => 'edit'
]);
}
});
$app->get('/quantityunit/{quantityunitId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['quantityunitId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create quantity unit',
'contentPage' => 'quantityunitform.php',
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit quantity unit',
'contentPage' => 'quantityunitform.php',
'quantityunit' => $db->quantity_units($args['quantityunitId']),
'mode' => 'edit'
]);
}
});
$app->get('/habit/{habitId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['habitId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create habit',
'contentPage' => 'habitform.php',
'periodTypes' => GrocyPhpHelper::GetClassConstants('HabitsService'),
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit habit',
'contentPage' => 'habitform.php',
'habit' => $db->habits($args['habitId']),
'periodTypes' => GrocyPhpHelper::GetClassConstants('HabitsService'),
'mode' => 'edit'
]);
}
});
$app->get('/battery/{batteryId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['batteryId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create battery',
'contentPage' => 'batteryform.php',
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit battery',
'contentPage' => 'batteryform.php',
'battery' => $db->batteries($args['batteryId']),
'mode' => 'edit'
]);
}
});
$app->get('/shoppinglistitem/{itemId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['itemId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Add shopping list item',
'contentPage' => 'shoppinglistform.php',
'products' => $db->products(),
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit shopping list item',
'contentPage' => 'shoppinglistform.php',
'listItem' => $db->shopping_list($args['itemId']),
'products' => $db->products(),
'mode' => 'edit'
]);
}
});
$app->group('/api', function() use($db)
{
$this->get('/get-objects/{entity}', function(Request $request, Response $response, $args) use($db)
{
echo json_encode($db->{$args['entity']}());
});
$this->get('/get-object/{entity}/{objectId}', function(Request $request, Response $response, $args) use($db)
{
echo json_encode($db->{$args['entity']}($args['objectId']));
});
$this->post('/add-object/{entity}', function(Request $request, Response $response, $args) use($db)
{
$newRow = $db->{$args['entity']}()->createRow($request->getParsedBody());
$newRow->save();
$success = $newRow->isClean();
echo json_encode(array('success' => $success));
});
$this->post('/edit-object/{entity}/{objectId}', function(Request $request, Response $response, $args) use($db)
{
$row = $db->{$args['entity']}($args['objectId']);
$row->update($request->getParsedBody());
$success = $row->isClean();
echo json_encode(array('success' => $success));
});
$this->get('/delete-object/{entity}/{objectId}', function(Request $request, Response $response, $args) use($db)
{
$row = $db->{$args['entity']}($args['objectId']);
$row->delete();
$success = $row->isClean();
echo json_encode(array('success' => $success));
});
$this->get('/stock/add-product/{productId}/{amount}', function(Request $request, Response $response, $args)
{
$bestBeforeDate = date('Y-m-d');
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
{
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
}
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
{
$transactionType = $request->getQueryParams()['transactiontype'];
}
echo json_encode(array('success' => StockService::AddProduct($args['productId'], $args['amount'], $bestBeforeDate, $transactionType)));
});
$this->get('/stock/consume-product/{productId}/{amount}', function(Request $request, Response $response, $args)
{
$spoiled = false;
if (isset($request->getQueryParams()['spoiled']) && !empty($request->getQueryParams()['spoiled']) && $request->getQueryParams()['spoiled'] == '1')
{
$spoiled = true;
}
$transactionType = StockService::TRANSACTION_TYPE_CONSUME;
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
{
$transactionType = $request->getQueryParams()['transactiontype'];
}
echo json_encode(array('success' => StockService::ConsumeProduct($args['productId'], $args['amount'], $spoiled, $transactionType)));
});
$this->get('/stock/inventory-product/{productId}/{newAmount}', function(Request $request, Response $response, $args)
{
$bestBeforeDate = date('Y-m-d');
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
{
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
}
echo json_encode(array('success' => StockService::InventoryProduct($args['productId'], $args['newAmount'], $bestBeforeDate)));
});
$this->get('/stock/get-product-details/{productId}', function(Request $request, Response $response, $args)
{
echo json_encode(StockService::GetProductDetails($args['productId']));
});
$this->get('/stock/get-current-stock', function(Request $request, Response $response)
{
echo json_encode(StockService::GetCurrentStock());
});
$this->get('/stock/add-missing-products-to-shoppinglist', function(Request $request, Response $response)
{
StockService::AddMissingProductsToShoppingList();
echo json_encode(array('success' => true));
});
$this->get('/habits/track-habit/{habitId}', function(Request $request, Response $response, $args)
{
$trackedTime = date('Y-m-d H:i:s');
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
{
$trackedTime = $request->getQueryParams()['tracked_time'];
}
echo json_encode(array('success' => HabitsService::TrackHabit($args['habitId'], $trackedTime)));
});
$this->get('/habits/get-habit-details/{habitId}', function(Request $request, Response $response, $args)
{
echo json_encode(HabitsService::GetHabitDetails($args['habitId']));
});
$this->get('/batteries/track-charge-cycle/{batteryId}', function(Request $request, Response $response, $args)
{
$trackedTime = date('Y-m-d H:i:s');
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
{
$trackedTime = $request->getQueryParams()['tracked_time'];
}
echo json_encode(array('success' => BatteriesService::TrackChargeCycle($args['batteryId'], $trackedTime)));
});
$this->get('/batteries/get-battery-details/{batteryId}', function(Request $request, Response $response, $args)
{
echo json_encode(BatteriesService::GetBatteryDetails($args['batteryId']));
});
})->add(function($request, $response, $next)
{
$response = $next($request, $response);
return $response->withHeader('Content-Type', 'application/json');
});
$app->group('/cli', function() $app->group('/cli', function()
{ {
$this->get('/recreatedemo', function(Request $request, Response $response) $this->get('/recreatedemo', 'Grocy\Controllers\CliController:RecreateDemo');
{ })->add(CliMiddleware::class);
if (ApplicationService::IsDemoInstallation())
{
GrocyDemoDataGenerator::RecreateDemo();
}
});
})->add(function($request, $response, $next)
{
$response = $next($request, $response);
if (PHP_SAPI !== 'cli')
{
echo 'Please call this only from CLI';
return $response->withHeader('Content-Type', 'text/plain')->withStatus(400);
}
return $response->withHeader('Content-Type', 'text/plain');
});
$app->run(); $app->run();

View File

@ -0,0 +1,25 @@
<?php
namespace Grocy\Middleware;
class CliMiddleware
{
public function __construct(\Slim\Container $container) {
$this->container = $container;
}
protected $container;
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
{
$response = $next($request, $response);
if (PHP_SAPI !== 'cli')
{
$response->write('Please call this only from CLI');
return $response->withHeader('Content-Type', 'text/plain')->withStatus(400);
}
return $response->withHeader('Content-Type', 'text/plain');
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Grocy\Middleware;
class JsonMiddleware
{
public function __construct(\Slim\Container $container) {
$this->container = $container;
}
protected $container;
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
{
$response = $next($request, $response, $next);
return $response->withHeader('Content-Type', 'application/json');
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Grocy\Middleware;
use Grocy\Services\SessionService;
class SessionMiddleware
{
public function __construct(\Slim\Container $container) {
$this->container = $container;
}
protected $container;
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
{
$route = $request->getAttribute('route');
$routeName = $route->getName();
$sessionService = new SessionService();
if ((!isset($_COOKIE['grocy_session']) || !$sessionService->IsValidSession($_COOKIE['grocy_session'])) && $routeName !== 'login')
{
$response = $response->withRedirect('/login');
}
else
{
$response = $next($request, $response);
}
return $response;
}
}

View File

@ -1,26 +1,28 @@
<?php <?php
class ApplicationService namespace Grocy\Services;
class ApplicationService extends BaseService
{ {
/** /**
* @return boolean * @return boolean
*/ */
public static function IsDemoInstallation() public function IsDemoInstallation()
{ {
return file_exists(__DIR__ . '/../data/demo.txt'); return file_exists(__DIR__ . '/../data/demo.txt');
} }
private static $InstalledVersion; private $InstalledVersion;
/** /**
* @return string * @return string
*/ */
public static function GetInstalledVersion() public function GetInstalledVersion()
{ {
if (self::$InstalledVersion == null) if ($this->InstalledVersion == null)
{ {
self::$InstalledVersion = preg_replace("/\r|\n/", '', file_get_contents(__DIR__ . '/../version.txt')); $this->InstalledVersion = preg_replace("/\r|\n/", '', file_get_contents(__DIR__ . '/../version.txt'));
} }
return self::$InstalledVersion; return $this->InstalledVersion;
} }
} }

16
services/BaseService.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace Grocy\Services;
use Grocy\Services\DatabaseService;
class BaseService
{
public function __construct() {
$this->DatabaseService = new DatabaseService();
$this->Database = $this->DatabaseService->GetDbConnection();
}
protected $DatabaseService;
protected $Database;
}

View File

@ -1,19 +1,19 @@
<?php <?php
class BatteriesService namespace Grocy\Services;
class BatteriesService extends BaseService
{ {
public static function GetCurrent() public function GetCurrent()
{ {
$sql = 'SELECT * from batteries_current'; $sql = 'SELECT * from batteries_current';
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ); return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
} }
public static function GetNextChargeTime(int $batteryId) public function GetNextChargeTime(int $batteryId)
{ {
$db = DatabaseService::GetDbConnection(); $battery = $this->Database->batteries($batteryId);
$batteryLastLogRow = $this->DatabaseService->ExecuteDbQuery("SELECT * from batteries_current WHERE battery_id = $batteryId LIMIT 1")->fetch(\PDO::FETCH_OBJ);
$battery = $db->batteries($batteryId);
$batteryLastLogRow = DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), "SELECT * from batteries_current WHERE battery_id = $batteryId LIMIT 1")->fetch(PDO::FETCH_OBJ);
if ($battery->charge_interval_days > 0) if ($battery->charge_interval_days > 0)
{ {
@ -27,13 +27,11 @@ class BatteriesService
return null; return null;
} }
public static function GetBatteryDetails(int $batteryId) public function GetBatteryDetails(int $batteryId)
{ {
$db = DatabaseService::GetDbConnection(); $battery = $this->Database->batteries($batteryId);
$batteryChargeCylcesCount = $this->Database->battery_charge_cycles()->where('battery_id', $batteryId)->count();
$battery = $db->batteries($batteryId); $batteryLastChargedTime = $this->Database->battery_charge_cycles()->where('battery_id', $batteryId)->max('tracked_time');
$batteryChargeCylcesCount = $db->battery_charge_cycles()->where('battery_id', $batteryId)->count();
$batteryLastChargedTime = $db->battery_charge_cycles()->where('battery_id', $batteryId)->max('tracked_time');
return array( return array(
'battery' => $battery, 'battery' => $battery,
@ -42,11 +40,9 @@ class BatteriesService
); );
} }
public static function TrackChargeCycle(int $batteryId, string $trackedTime) public function TrackChargeCycle(int $batteryId, string $trackedTime)
{ {
$db = DatabaseService::GetDbConnection(); $logRow = $this->Database->battery_charge_cycles()->createRow(array(
$logRow = $db->battery_charge_cycles()->createRow(array(
'battery_id' => $batteryId, 'battery_id' => $batteryId,
'tracked_time' => $trackedTime 'tracked_time' => $trackedTime
)); ));

View File

@ -1,10 +1,14 @@
<?php <?php
class GrocyDbMigrator namespace Grocy\Services;
class DatabaseMigrationService extends BaseService
{ {
public static function MigrateDb(PDO $pdo) public function MigrateDatabase()
{ {
self::ExecuteMigrationWhenNeeded($pdo, 1, " $this->DatabaseService->ExecuteDbStatement("CREATE TABLE IF NOT EXISTS migrations (migration INTEGER NOT NULL PRIMARY KEY UNIQUE, execution_time_timestamp DATETIME DEFAULT (datetime('now', 'localtime')))");
$this->ExecuteMigrationWhenNeeded(1, "
CREATE TABLE products ( CREATE TABLE products (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE, name TEXT NOT NULL UNIQUE,
@ -20,7 +24,7 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 2, " $this->ExecuteMigrationWhenNeeded(2, "
CREATE TABLE locations ( CREATE TABLE locations (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE, name TEXT NOT NULL UNIQUE,
@ -29,7 +33,7 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 3, " $this->ExecuteMigrationWhenNeeded(3, "
CREATE TABLE quantity_units ( CREATE TABLE quantity_units (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE, name TEXT NOT NULL UNIQUE,
@ -38,7 +42,7 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 4, " $this->ExecuteMigrationWhenNeeded(4, "
CREATE TABLE stock ( CREATE TABLE stock (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
product_id INTEGER NOT NULL, product_id INTEGER NOT NULL,
@ -50,7 +54,7 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 5, " $this->ExecuteMigrationWhenNeeded(5, "
CREATE TABLE stock_log ( CREATE TABLE stock_log (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
product_id INTEGER NOT NULL, product_id INTEGER NOT NULL,
@ -65,14 +69,14 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 6, " $this->ExecuteMigrationWhenNeeded(6, "
INSERT INTO locations (name, description) VALUES ('DefaultLocation', 'This is the first default location, edit or delete it'); INSERT INTO locations (name, description) VALUES ('DefaultLocation', 'This is the first default location, edit or delete it');
INSERT INTO quantity_units (name, description) VALUES ('DefaultQuantityUnit', 'This is the first default quantity unit, edit or delete it'); INSERT INTO quantity_units (name, description) VALUES ('DefaultQuantityUnit', 'This is the first default quantity unit, edit or delete it');
INSERT INTO products (name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('DefaultProduct1', 'This is the first default product, edit or delete it', 1, 1, 1, 1); INSERT INTO products (name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('DefaultProduct1', 'This is the first default product, edit or delete it', 1, 1, 1, 1);
INSERT INTO products (name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('DefaultProduct2', 'This is the second default product, edit or delete it', 1, 1, 1, 1);" INSERT INTO products (name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('DefaultProduct2', 'This is the second default product, edit or delete it', 1, 1, 1, 1);"
); );
self::ExecuteMigrationWhenNeeded($pdo, 7, " $this->ExecuteMigrationWhenNeeded(7, "
CREATE VIEW stock_missing_products CREATE VIEW stock_missing_products
AS AS
SELECT p.id, MAX(p.name) AS name, p.min_stock_amount - IFNULL(SUM(s.amount), 0) AS amount_missing SELECT p.id, MAX(p.name) AS name, p.min_stock_amount - IFNULL(SUM(s.amount), 0) AS amount_missing
@ -84,7 +88,7 @@ class GrocyDbMigrator
HAVING IFNULL(SUM(s.amount), 0) < p.min_stock_amount;" HAVING IFNULL(SUM(s.amount), 0) < p.min_stock_amount;"
); );
self::ExecuteMigrationWhenNeeded($pdo, 8, " $this->ExecuteMigrationWhenNeeded(8, "
CREATE VIEW stock_current CREATE VIEW stock_current
AS AS
SELECT product_id, SUM(amount) AS amount, MIN(best_before_date) AS best_before_date SELECT product_id, SUM(amount) AS amount, MIN(best_before_date) AS best_before_date
@ -93,7 +97,7 @@ class GrocyDbMigrator
ORDER BY MIN(best_before_date) ASC;" ORDER BY MIN(best_before_date) ASC;"
); );
self::ExecuteMigrationWhenNeeded($pdo, 9, " $this->ExecuteMigrationWhenNeeded(9, "
CREATE TABLE shopping_list ( CREATE TABLE shopping_list (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
product_id INTEGER NOT NULL UNIQUE, product_id INTEGER NOT NULL UNIQUE,
@ -103,7 +107,7 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 10, " $this->ExecuteMigrationWhenNeeded(10, "
CREATE TABLE habits ( CREATE TABLE habits (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE, name TEXT NOT NULL UNIQUE,
@ -114,7 +118,7 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 11, " $this->ExecuteMigrationWhenNeeded(11, "
CREATE TABLE habits_log ( CREATE TABLE habits_log (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
habit_id INTEGER NOT NULL, habit_id INTEGER NOT NULL,
@ -123,7 +127,7 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 12, " $this->ExecuteMigrationWhenNeeded(12, "
CREATE VIEW habits_current CREATE VIEW habits_current
AS AS
SELECT habit_id, MAX(tracked_time) AS last_tracked_time SELECT habit_id, MAX(tracked_time) AS last_tracked_time
@ -132,7 +136,7 @@ class GrocyDbMigrator
ORDER BY MAX(tracked_time) DESC;" ORDER BY MAX(tracked_time) DESC;"
); );
self::ExecuteMigrationWhenNeeded($pdo, 13, " $this->ExecuteMigrationWhenNeeded(13, "
CREATE TABLE batteries ( CREATE TABLE batteries (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE, name TEXT NOT NULL UNIQUE,
@ -143,7 +147,7 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 14, " $this->ExecuteMigrationWhenNeeded(14, "
CREATE TABLE battery_charge_cycles ( CREATE TABLE battery_charge_cycles (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
battery_id TEXT NOT NULL, battery_id TEXT NOT NULL,
@ -152,7 +156,7 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 15, " $this->ExecuteMigrationWhenNeeded(15, "
CREATE VIEW batteries_current CREATE VIEW batteries_current
AS AS
SELECT battery_id, MAX(tracked_time) AS last_tracked_time SELECT battery_id, MAX(tracked_time) AS last_tracked_time
@ -161,11 +165,11 @@ class GrocyDbMigrator
ORDER BY MAX(tracked_time) DESC;" ORDER BY MAX(tracked_time) DESC;"
); );
self::ExecuteMigrationWhenNeeded($pdo, 16, " $this->ExecuteMigrationWhenNeeded(16, "
ALTER TABLE shopping_list RENAME TO shopping_list_old;" ALTER TABLE shopping_list RENAME TO shopping_list_old;"
); );
self::ExecuteMigrationWhenNeeded($pdo, 17, " $this->ExecuteMigrationWhenNeeded(17, "
CREATE TABLE shopping_list ( CREATE TABLE shopping_list (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
product_id INTEGER, product_id INTEGER,
@ -176,25 +180,25 @@ class GrocyDbMigrator
)" )"
); );
self::ExecuteMigrationWhenNeeded($pdo, 18, " $this->ExecuteMigrationWhenNeeded(18, "
INSERT INTO shopping_list INSERT INTO shopping_list
(product_id, amount, amount_autoadded, row_created_timestamp) (product_id, amount, amount_autoadded, row_created_timestamp)
SELECT product_id, amount, amount_autoadded, row_created_timestamp SELECT product_id, amount, amount_autoadded, row_created_timestamp
FROM shopping_list_old" FROM shopping_list_old"
); );
self::ExecuteMigrationWhenNeeded($pdo, 19, " $this->ExecuteMigrationWhenNeeded(19, "
DROP TABLE shopping_list_old;" DROP TABLE shopping_list_old;"
); );
} }
private static function ExecuteMigrationWhenNeeded(PDO $pdo, int $migrationId, string $sql) private function ExecuteMigrationWhenNeeded(int $migrationId, string $sql)
{ {
$rowCount = DatabaseService::ExecuteDbQuery($pdo, 'SELECT COUNT(*) FROM migrations WHERE migration = ' . $migrationId)->fetchColumn(); $rowCount = $this->DatabaseService->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = ' . $migrationId)->fetchColumn();
if (intval($rowCount) === 0) if (intval($rowCount) === 0)
{ {
DatabaseService::ExecuteDbStatement($pdo, $sql); $this->DatabaseService->ExecuteDbStatement($sql);
DatabaseService::ExecuteDbStatement($pdo, 'INSERT INTO migrations (migration) VALUES (' . $migrationId . ')'); $this->DatabaseService->ExecuteDbStatement('INSERT INTO migrations (migration) VALUES (' . $migrationId . ')');
} }
} }
} }

View File

@ -1,64 +1,47 @@
<?php <?php
namespace Grocy\Services;
use Grocy\Services\ApplicationService;
class DatabaseService class DatabaseService
{ {
private static $DbConnectionRaw; private $DbConnectionRaw;
/** /**
* @return PDO * @return \PDO
*/ */
public static function GetDbConnectionRaw($doMigrations = false) public function GetDbConnectionRaw()
{ {
if ($doMigrations === true) if ($this->DbConnectionRaw == null)
{ {
self::$DbConnectionRaw = null; $pdo = new \PDO('sqlite:' . __DIR__ . '/../data/grocy.db');
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->DbConnectionRaw = $pdo;
} }
if (self::$DbConnectionRaw == null) return $this->DbConnectionRaw;
{
$pdo = new PDO('sqlite:' . __DIR__ . '/../data/grocy.db');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if ($doMigrations === true)
{
self::ExecuteDbStatement($pdo, "CREATE TABLE IF NOT EXISTS migrations (migration INTEGER NOT NULL PRIMARY KEY UNIQUE, execution_time_timestamp DATETIME DEFAULT (datetime('now', 'localtime')))");
GrocyDbMigrator::MigrateDb($pdo);
if (ApplicationService::IsDemoInstallation())
{
GrocyDemoDataGenerator::PopulateDemoData($pdo);
}
}
self::$DbConnectionRaw = $pdo;
}
return self::$DbConnectionRaw;
} }
private static $DbConnection; private $DbConnection;
/** /**
* @return LessQL\Database * @return \LessQL\Database
*/ */
public static function GetDbConnection($doMigrations = false) public function GetDbConnection()
{ {
if ($doMigrations === true) if ($this->DbConnection == null)
{ {
self::$DbConnection = null; $this->DbConnection = new \LessQL\Database($this->GetDbConnectionRaw());
} }
if (self::$DbConnection == null) return $this->DbConnection;
{
self::$DbConnection = new LessQL\Database(self::GetDbConnectionRaw($doMigrations));
}
return self::$DbConnection;
} }
/** /**
* @return boolean * @return boolean
*/ */
public static function ExecuteDbStatement(PDO $pdo, string $sql) public function ExecuteDbStatement(string $sql)
{ {
$pdo = $this->GetDbConnectionRaw();
if ($pdo->exec($sql) === false) if ($pdo->exec($sql) === false)
{ {
throw new Exception($pdo->errorInfo()); throw new Exception($pdo->errorInfo());
@ -68,11 +51,12 @@ class DatabaseService
} }
/** /**
* @return boolean|PDOStatement * @return boolean|\PDOStatement
*/ */
public static function ExecuteDbQuery(PDO $pdo, string $sql) public function ExecuteDbQuery(string $sql)
{ {
if (self::ExecuteDbStatement($pdo, $sql) === true) $pdo = $this->GetDbConnectionRaw();
if ($this->ExecuteDbStatement($sql) === true)
{ {
return $pdo->query($sql); return $pdo->query($sql);
} }

View File

@ -1,10 +1,12 @@
<?php <?php
class GrocyDemoDataGenerator namespace Grocy\Services;
class DemoDataGeneratorService extends BaseService
{ {
public static function PopulateDemoData(PDO $pdo) public function PopulateDemoData()
{ {
$rowCount = DatabaseService::ExecuteDbQuery($pdo, 'SELECT COUNT(*) FROM migrations WHERE migration = -1')->fetchColumn(); $rowCount = $this->DatabaseService->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = -1')->fetchColumn();
if (intval($rowCount) === 0) if (intval($rowCount) === 0)
{ {
$sql = " $sql = "
@ -45,46 +47,47 @@ class GrocyDemoDataGenerator
INSERT INTO migrations (migration) VALUES (-1); INSERT INTO migrations (migration) VALUES (-1);
"; ";
DatabaseService::ExecuteDbStatement($pdo, $sql); $this->DatabaseService->ExecuteDbStatement($sql);
StockService::AddProduct(3, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService = new StockService();
StockService::AddProduct(4, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(3, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(5, 5, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(4, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(6, 5, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(5, 5, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(7, 5, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(6, 5, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(8, 5, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(7, 5, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(9, 5, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(8, 5, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(10, 5, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(9, 5, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(11, 5, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(10, 5, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(12, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(11, 5, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(13, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(12, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(14, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(13, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(15, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE); $stockService->AddProduct(14, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddMissingProductsToShoppingList(); $stockService->AddProduct(15, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddMissingProductsToShoppingList();
HabitsService::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-5 days'))); $habitsService = new HabitsService();
HabitsService::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-10 days'))); $habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-5 days')));
HabitsService::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-15 days'))); $habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-10 days')));
HabitsService::TrackHabit(2, date('Y-m-d H:i:s', strtotime('-10 days'))); $habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-15 days')));
HabitsService::TrackHabit(2, date('Y-m-d H:i:s', strtotime('-20 days'))); $habitsService->TrackHabit(2, date('Y-m-d H:i:s', strtotime('-10 days')));
$habitsService->TrackHabit(2, date('Y-m-d H:i:s', strtotime('-20 days')));
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-200 days'))); $batteriesService = new BatteriesService();
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-150 days'))); $batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-200 days')));
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-100 days'))); $batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-150 days')));
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-50 days'))); $batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-100 days')));
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-200 days'))); $batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-50 days')));
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-150 days'))); $batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-200 days')));
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-100 days'))); $batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-150 days')));
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-50 days'))); $batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-100 days')));
BatteriesService::TrackChargeCycle(3, date('Y-m-d H:i:s', strtotime('-65 days'))); $batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-50 days')));
$batteriesService->TrackChargeCycle(3, date('Y-m-d H:i:s', strtotime('-65 days')));
} }
} }
public static function RecreateDemo() public function RecreateDemo()
{ {
unlink(__DIR__ . '/data/grocy.db'); unlink(__DIR__ . '/data/grocy.db');
$this->PopulateDemoData($this->DatabaseService->GetDbConnectionRaw(true));
$db = DatabaseService::GetDbConnectionRaw(true);
self::PopulateDemoData($db);
} }
} }

View File

@ -1,22 +1,22 @@
<?php <?php
class HabitsService namespace Grocy\Services;
class HabitsService extends BaseService
{ {
const HABIT_TYPE_MANUALLY = 'manually'; const HABIT_TYPE_MANUALLY = 'manually';
const HABIT_TYPE_DYNAMIC_REGULAR = 'dynamic-regular'; const HABIT_TYPE_DYNAMIC_REGULAR = 'dynamic-regular';
public static function GetCurrentHabits() public function GetCurrentHabits()
{ {
$sql = 'SELECT * from habits_current'; $sql = 'SELECT * from habits_current';
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ); return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
} }
public static function GetNextHabitTime(int $habitId) public function GetNextHabitTime(int $habitId)
{ {
$db = DatabaseService::GetDbConnection(); $habit = $this->Database->habits($habitId);
$habitLastLogRow = $this->DatabaseService->ExecuteDbQuery("SELECT * from habits_current WHERE habit_id = $habitId LIMIT 1")->fetch(\PDO::FETCH_OBJ);
$habit = $db->habits($habitId);
$habitLastLogRow = DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), "SELECT * from habits_current WHERE habit_id = $habitId LIMIT 1")->fetch(PDO::FETCH_OBJ);
switch ($habit->period_type) switch ($habit->period_type)
{ {
@ -29,13 +29,11 @@ class HabitsService
return null; return null;
} }
public static function GetHabitDetails(int $habitId) public function GetHabitDetails(int $habitId)
{ {
$db = DatabaseService::GetDbConnection(); $habit = $this->Database->habits($habitId);
$habitTrackedCount = $this->Database->habits_log()->where('habit_id', $habitId)->count();
$habit = $db->habits($habitId); $habitLastTrackedTime = $this->Database->habits_log()->where('habit_id', $habitId)->max('tracked_time');
$habitTrackedCount = $db->habits_log()->where('habit_id', $habitId)->count();
$habitLastTrackedTime = $db->habits_log()->where('habit_id', $habitId)->max('tracked_time');
return array( return array(
'habit' => $habit, 'habit' => $habit,
@ -44,11 +42,9 @@ class HabitsService
); );
} }
public static function TrackHabit(int $habitId, string $trackedTime) public function TrackHabit(int $habitId, string $trackedTime)
{ {
$db = DatabaseService::GetDbConnection(); $logRow = $this->Database->habits_log()->createRow(array(
$logRow = $db->habits_log()->createRow(array(
'habit_id' => $habitId, 'habit_id' => $habitId,
'tracked_time' => $trackedTime 'tracked_time' => $trackedTime
)); ));

View File

@ -1,11 +1,13 @@
<?php <?php
class SessionService namespace Grocy\Services;
class SessionService extends BaseService
{ {
/** /**
* @return boolean * @return boolean
*/ */
public static function IsValidSession($sessionKey) public function IsValidSession($sessionKey)
{ {
if ($sessionKey === null || empty($sessionKey)) if ($sessionKey === null || empty($sessionKey))
{ {
@ -20,7 +22,7 @@ class SessionService
/** /**
* @return string * @return string
*/ */
public static function CreateSession() public function CreateSession()
{ {
if (!file_exists(__DIR__ . '/../data/sessions')) if (!file_exists(__DIR__ . '/../data/sessions'))
{ {
@ -28,7 +30,7 @@ class SessionService
} }
$now = time(); $now = time();
foreach (new FilesystemIterator(__DIR__ . '/../data/sessions') as $file) foreach (new \FilesystemIterator(__DIR__ . '/../data/sessions') as $file)
{ {
if ($now - $file->getCTime() >= 2678400) //31 days if ($now - $file->getCTime() >= 2678400) //31 days
{ {
@ -41,7 +43,7 @@ class SessionService
return $newSessionKey; return $newSessionKey;
} }
public static function RemoveSession($sessionKey) public function RemoveSession($sessionKey)
{ {
unlink(__DIR__ . "/../data/sessions/$sessionKey.txt"); unlink(__DIR__ . "/../data/sessions/$sessionKey.txt");
} }

View File

@ -1,33 +1,33 @@
<?php <?php
class StockService namespace Grocy\Services;
class StockService extends BaseService
{ {
const TRANSACTION_TYPE_PURCHASE = 'purchase'; const TRANSACTION_TYPE_PURCHASE = 'purchase';
const TRANSACTION_TYPE_CONSUME = 'consume'; const TRANSACTION_TYPE_CONSUME = 'consume';
const TRANSACTION_TYPE_INVENTORY_CORRECTION = 'inventory-correction'; const TRANSACTION_TYPE_INVENTORY_CORRECTION = 'inventory-correction';
public static function GetCurrentStock() public function GetCurrentStock()
{ {
$sql = 'SELECT * from stock_current'; $sql = 'SELECT * from stock_current';
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ); return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
} }
public static function GetMissingProducts() public function GetMissingProducts()
{ {
$sql = 'SELECT * from stock_missing_products'; $sql = 'SELECT * from stock_missing_products';
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ); return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
} }
public static function GetProductDetails(int $productId) public function GetProductDetails(int $productId)
{ {
$db = DatabaseService::GetDbConnection(); $product = $this->Database->products($productId);
$productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
$product = $db->products($productId); $productLastPurchased = $this->Database->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_PURCHASE)->max('purchased_date');
$productStockAmount = $db->stock()->where('product_id', $productId)->sum('amount'); $productLastUsed = $this->Database->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->max('used_date');
$productLastPurchased = $db->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_PURCHASE)->max('purchased_date'); $quPurchase = $this->Database->quantity_units($product->qu_id_purchase);
$productLastUsed = $db->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->max('used_date'); $quStock = $this->Database->quantity_units($product->qu_id_stock);
$quPurchase = $db->quantity_units($product->qu_id_purchase);
$quStock = $db->quantity_units($product->qu_id_stock);
return array( return array(
'product' => $product, 'product' => $product,
@ -39,14 +39,13 @@ class StockService
); );
} }
public static function AddProduct(int $productId, int $amount, string $bestBeforeDate, $transactionType) public function AddProduct(int $productId, int $amount, string $bestBeforeDate, $transactionType)
{ {
if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_PURCHASE || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION) if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_PURCHASE || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION)
{ {
$db = DatabaseService::GetDbConnection();
$stockId = uniqid(); $stockId = uniqid();
$logRow = $db->stock_log()->createRow(array( $logRow = $this->Database->stock_log()->createRow(array(
'product_id' => $productId, 'product_id' => $productId,
'amount' => $amount, 'amount' => $amount,
'best_before_date' => $bestBeforeDate, 'best_before_date' => $bestBeforeDate,
@ -56,7 +55,7 @@ class StockService
)); ));
$logRow->save(); $logRow->save();
$stockRow = $db->stock()->createRow(array( $stockRow = $this->Database->stock()->createRow(array(
'product_id' => $productId, 'product_id' => $productId,
'amount' => $amount, 'amount' => $amount,
'best_before_date' => $bestBeforeDate, 'best_before_date' => $bestBeforeDate,
@ -73,14 +72,12 @@ class StockService
} }
} }
public static function ConsumeProduct(int $productId, int $amount, bool $spoiled, $transactionType) public function ConsumeProduct(int $productId, int $amount, bool $spoiled, $transactionType)
{ {
if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_PURCHASE || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION) if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_PURCHASE || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION)
{ {
$db = DatabaseService::GetDbConnection(); $productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
$potentialStockEntries = $this->Database->stock()->where('product_id', $productId)->orderBy('best_before_date', 'ASC')->orderBy('purchased_date', 'ASC')->fetchAll(); //First expiring first, then first in first out
$productStockAmount = $db->stock()->where('product_id', $productId)->sum('amount');
$potentialStockEntries = $db->stock()->where('product_id', $productId)->orderBy('best_before_date', 'ASC')->orderBy('purchased_date', 'ASC')->fetchAll(); //First expiring first, then first in first out
if ($amount > $productStockAmount) if ($amount > $productStockAmount)
{ {
@ -96,7 +93,7 @@ class StockService
if ($amount >= $stockEntry->amount) //Take the whole stock entry if ($amount >= $stockEntry->amount) //Take the whole stock entry
{ {
$logRow = $db->stock_log()->createRow(array( $logRow = $this->Database->stock_log()->createRow(array(
'product_id' => $stockEntry->product_id, 'product_id' => $stockEntry->product_id,
'amount' => $stockEntry->amount * -1, 'amount' => $stockEntry->amount * -1,
'best_before_date' => $stockEntry->best_before_date, 'best_before_date' => $stockEntry->best_before_date,
@ -113,7 +110,7 @@ class StockService
} }
else //Stock entry amount is > than needed amount -> split the stock entry resp. update the amount else //Stock entry amount is > than needed amount -> split the stock entry resp. update the amount
{ {
$logRow = $db->stock_log()->createRow(array( $logRow = $this->Database->stock_log()->createRow(array(
'product_id' => $stockEntry->product_id, 'product_id' => $stockEntry->product_id,
'amount' => $amount * -1, 'amount' => $amount * -1,
'best_before_date' => $stockEntry->best_before_date, 'best_before_date' => $stockEntry->best_before_date,
@ -142,36 +139,33 @@ class StockService
} }
} }
public static function InventoryProduct(int $productId, int $newAmount, string $bestBeforeDate) public function InventoryProduct(int $productId, int $newAmount, string $bestBeforeDate)
{ {
$db = DatabaseService::GetDbConnection(); $productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
$productStockAmount = $db->stock()->where('product_id', $productId)->sum('amount');
if ($newAmount > $productStockAmount) if ($newAmount > $productStockAmount)
{ {
$amountToAdd = $newAmount - $productStockAmount; $amountToAdd = $newAmount - $productStockAmount;
self::AddProduct($productId, $amountToAdd, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION); $this->AddProduct($productId, $amountToAdd, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
} }
else if ($newAmount < $productStockAmount) else if ($newAmount < $productStockAmount)
{ {
$amountToRemove = $productStockAmount - $newAmount; $amountToRemove = $productStockAmount - $newAmount;
self::ConsumeProduct($productId, $amountToRemove, false, self::TRANSACTION_TYPE_INVENTORY_CORRECTION); $this->ConsumeProduct($productId, $amountToRemove, false, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
} }
return true; return true;
} }
public static function AddMissingProductsToShoppingList() public function AddMissingProductsToShoppingList()
{ {
$db = DatabaseService::GetDbConnection(); $missingProducts = $this->GetMissingProducts();
$missingProducts = self::GetMissingProducts();
foreach ($missingProducts as $missingProduct) foreach ($missingProducts as $missingProduct)
{ {
$product = $db->products()->where('id', $missingProduct->id)->fetch(); $product = $this->Database->products()->where('id', $missingProduct->id)->fetch();
$amount = ceil($missingProduct->amount_missing / $product->qu_factor_purchase_to_stock); $amount = ceil($missingProduct->amount_missing / $product->qu_factor_purchase_to_stock);
$alreadyExistingEntry = $db->shopping_list()->where('product_id', $missingProduct->id)->fetch(); $alreadyExistingEntry = $this->Database->shopping_list()->where('product_id', $missingProduct->id)->fetch();
if ($alreadyExistingEntry) //Update if ($alreadyExistingEntry) //Update
{ {
$alreadyExistingEntry->update(array( $alreadyExistingEntry->update(array(
@ -180,7 +174,7 @@ class StockService
} }
else //Insert else //Insert
{ {
$shoppinglistRow = $db->shopping_list()->createRow(array( $shoppinglistRow = $this->Database->shopping_list()->createRow(array(
'product_id' => $missingProduct->id, 'product_id' => $missingProduct->id,
'amount_autoadded' => $amount 'amount_autoadded' => $amount
)); ));

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header"> <h1 class="page-header">
@ -44,3 +47,4 @@
</div> </div>
</div> </div>
@stop

View File

@ -1,3 +1,11 @@
<?php
use Grocy\Services\BatteriesService;
$batteriesService = new BatteriesService();
?>
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Batteries overview</h1> <h1 class="page-header">Batteries overview</h1>
@ -13,18 +21,18 @@
</thead> </thead>
<tbody> <tbody>
<?php foreach ($current as $curentBatteryEntry) : ?> <?php foreach ($current as $curentBatteryEntry) : ?>
<tr class="<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0 && BatteriesService::GetNextChargeTime($curentBatteryEntry->battery_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>"> <tr class="<?php if (FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0 && $batteriesService->GetNextChargeTime($curentBatteryEntry->battery_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
<td> <td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->name; ?> <?php echo FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->name; ?>
</td> </td>
<td> <td>
<?php echo $curentBatteryEntry->last_tracked_time; ?> <?php echo $curentBatteryEntry->last_tracked_time; ?>
<time class="timeago timeago-contextual" datetime="<?php echo $curentBatteryEntry->last_tracked_time; ?>"></time> <time class="timeago timeago-contextual" datetime="<?php echo $curentBatteryEntry->last_tracked_time; ?>"></time>
</td> </td>
<td> <td>
<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0): ?> <?php if (FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0): ?>
<?php echo BatteriesService::GetNextChargeTime($curentBatteryEntry->battery_id); ?> <?php echo $batteriesService->GetNextChargeTime($curentBatteryEntry->battery_id); ?>
<time class="timeago timeago-contextual" datetime="<?php echo BatteriesService::GetNextChargeTime($curentBatteryEntry->battery_id); ?>"></time> <time class="timeago timeago-contextual" datetime="<?php echo $batteriesService->GetNextChargeTime($curentBatteryEntry->battery_id); ?>"></time>
<?php else: ?> <?php else: ?>
... ...
<?php endif; ?> <?php endif; ?>
@ -36,3 +44,4 @@
</div> </div>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main"> <div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1> <h1 class="page-header"><?php echo $title; ?></h1>
@ -31,3 +34,4 @@
</form> </form>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main"> <div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Battery tracking</h1> <h1 class="page-header">Battery tracking</h1>
@ -40,3 +43,4 @@
<strong>Last charged:</strong> <span id="selected-battery-last-charged"></span> <time id="selected-battery-last-charged-timeago" class="timeago timeago-contextual"></time><br> <strong>Last charged:</strong> <span id="selected-battery-last-charged"></span> <time id="selected-battery-last-charged-timeago" class="timeago timeago-contextual"></time><br>
</p> </p>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main"> <div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Consume</h1> <h1 class="page-header">Consume</h1>
@ -43,3 +46,4 @@
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time> <strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p> </p>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main"> <div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1> <h1 class="page-header"><?php echo $title; ?></h1>
@ -44,3 +47,4 @@
</form> </form>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header"> <h1 class="page-header">
@ -48,3 +51,4 @@
</div> </div>
</div> </div>
@stop

View File

@ -1,3 +1,11 @@
<?php
use Grocy\Services\HabitsService;
$habitsService = new HabitsService();
?>
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Habits overview</h1> <h1 class="page-header">Habits overview</h1>
@ -13,14 +21,14 @@
</thead> </thead>
<tbody> <tbody>
<?php foreach ($currentHabits as $curentHabitEntry) : ?> <?php foreach ($currentHabits as $curentHabitEntry) : ?>
<tr class="<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR && HabitsService::GetNextHabitTime($curentHabitEntry->habit_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>"> <tr class="<?php if (FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR && $habitsService->GetNextHabitTime($curentHabitEntry->habit_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
<td> <td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name; ?> <?php echo FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name; ?>
</td> </td>
<td> <td>
<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR): ?> <?php if (FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR): ?>
<?php echo HabitsService::GetNextHabitTime($curentHabitEntry->habit_id); ?> <?php echo $habitsService->GetNextHabitTime($curentHabitEntry->habit_id); ?>
<time class="timeago timeago-contextual" datetime="<?php echo HabitsService::GetNextHabitTime($curentHabitEntry->habit_id); ?>"></time> <time class="timeago timeago-contextual" datetime="<?php echo $habitsService->GetNextHabitTime($curentHabitEntry->habit_id); ?>"></time>
<?php else: ?> <?php else: ?>
... ...
<?php endif; ?> <?php endif; ?>
@ -36,3 +44,4 @@
</div> </div>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main"> <div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Habit tracking</h1> <h1 class="page-header">Habit tracking</h1>
@ -40,3 +43,4 @@
<strong>Last tracked:</strong> <span id="selected-habit-last-tracked"></span> <time id="selected-habit-last-tracked-timeago" class="timeago timeago-contextual"></time><br> <strong>Last tracked:</strong> <span id="selected-habit-last-tracked"></span> <time id="selected-habit-last-tracked-timeago" class="timeago timeago-contextual"></time><br>
</p> </p>
</div> </div>
@stop

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2 main"> <div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Inventory</h1> <h1 class="page-header">Inventory</h1>
@ -50,3 +53,4 @@
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time> <strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p> </p>
</div> </div>
@stop

View File

@ -1,3 +1,10 @@
<?php
use Grocy\Services\ApplicationService;
$applicationService = new ApplicationService();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -9,24 +16,24 @@
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">
<meta name="author" content="Bernd Bestel (bernd@berrnd.de)"> <meta name="author" content="Bernd Bestel (bernd@berrnd.de)">
<link rel="icon" type="image/png" sizes="200x200" href="/grocy.png"> <link rel="icon" type="image/png" sizes="200x200" href="/views/img/grocy.png">
<title><?php echo $title; ?> | grocy</title> <title><?php echo $title; ?> | grocy</title>
<link href="/bower_components/bootstrap/dist/css/bootstrap.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/bower_components/bootstrap/dist/css/bootstrap.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/font-awesome/css/font-awesome.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/bower_components/font-awesome/css/font-awesome.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker3.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker3.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/bootstrap-combobox/css/bootstrap-combobox.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/bower_components/bootstrap-combobox/css/bootstrap-combobox.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/toastr/toastr.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/bower_components/toastr/toastr.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/tagmanager/tagmanager.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/bower_components/tagmanager/tagmanager.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/vendor_unmanaged/noto-sans-v6-latin/noto-sans-v6-latin.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/vendor_unmanaged/noto-sans-v6-latin/noto-sans-v6-latin.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/style.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet"> <link href="/views/css/grocy.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<script src="/bower_components/jquery/dist/jquery.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/jquery/dist/jquery.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/grocy.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/views/js/grocy.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
</head> </head>
<body> <body>
@ -116,7 +123,7 @@
<br> <br>
Created with passion since 2017 Created with passion since 2017
<br> <br>
Version <?php echo ApplicationService::GetInstalledVersion(); ?> Version <?php echo $applicationService->GetInstalledVersion(); ?>
<br> <br>
Life runs on code Life runs on code
<br> <br>
@ -193,7 +200,7 @@
<br> <br>
Created with passion since 2017 Created with passion since 2017
<br> <br>
Version <?php echo ApplicationService::GetInstalledVersion(); ?> Version <?php echo $applicationService->GetInstalledVersion(); ?>
<br> <br>
Life runs on code Life runs on code
<br> <br>
@ -204,30 +211,31 @@
</div> </div>
<script>Grocy.ContentPage = '<?php echo $contentPage; ?>';</script> <script>Grocy.ContentPage = '{{ $contentPage }}';</script>
<?php include __DIR__ . '/../' . $contentPage; ?> @section('content')
@show
</div> </div>
</div> </div>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/bootstrap/dist/js/bootstrap.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootbox/bootbox.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/bootbox/bootbox.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/jquery.serializeJSON/jquery.serializejson.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/jquery.serializeJSON/jquery.serializejson.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/moment/min/moment.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/moment/min/moment.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-validator/dist/validator.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/bootstrap-validator/dist/validator.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-combobox/js/bootstrap-combobox.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/bootstrap-combobox/js/bootstrap-combobox.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net/js/jquery.dataTables.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/datatables.net/js/jquery.dataTables.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-responsive/js/dataTables.responsive.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/datatables.net-responsive/js/dataTables.responsive.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-responsive-bs/js/responsive.bootstrap.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/datatables.net-responsive-bs/js/responsive.bootstrap.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/jquery-timeago/jquery.timeago.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/jquery-timeago/jquery.timeago.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/toastr/toastr.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/toastr/toastr.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/tagmanager/tagmanager.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/tagmanager/tagmanager.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<?php if (file_exists(__DIR__ . '/' . str_replace('.php', '.js', $contentPage))) : ?> <?php if (file_exists(__DIR__ . '/../../views/viewjs/' . str_replace('.php', '.js', $contentPage))) : ?>
<script src="/views/<?php echo str_replace('.php', '.js', $contentPage) . '?v=' . ApplicationService::GetInstalledVersion(); ?>"></script> <script src="/views/viewjs/<?php echo str_replace('.php', '.js', $contentPage) . '?v=' . $applicationService->GetInstalledVersion(); ?>"></script>
<?php endif; ?> <?php endif; ?>
<?php if (file_exists(__DIR__ . '/../data/add_before_end_body.html')) include __DIR__ . '/../data/add_before_end_body.html' ?> <?php if (file_exists(__DIR__ . '/../data/add_before_end_body.html')) include __DIR__ . '/../data/add_before_end_body.html' ?>

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main"> <div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1> <h1 class="page-header"><?php echo $title; ?></h1>
@ -26,3 +29,4 @@
</form> </form>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header"> <h1 class="page-header">
@ -40,3 +43,4 @@
</div> </div>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-md-4 col-md-offset-5 main"> <div class="col-md-4 col-md-offset-5 main">
<h1 class="page-header text-center">Login</h1> <h1 class="page-header text-center">Login</h1>
@ -21,3 +24,4 @@
</form> </form>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main"> <div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1> <h1 class="page-header"><?php echo $title; ?></h1>
@ -81,3 +84,4 @@
</form> </form>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header"> <h1 class="page-header">
@ -36,16 +39,16 @@
<?php echo $product->name; ?> <?php echo $product->name; ?>
</td> </td>
<td> <td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name; ?> <?php echo FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name; ?>
</td> </td>
<td> <td>
<?php echo $product->min_stock_amount; ?> <?php echo $product->min_stock_amount; ?>
</td> </td>
<td> <td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_purchase)->name; ?> <?php echo FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_purchase)->name; ?>
</td> </td>
<td> <td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_stock)->name; ?> <?php echo FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_stock)->name; ?>
</td> </td>
<td> <td>
<?php echo $product->qu_factor_purchase_to_stock; ?> <?php echo $product->qu_factor_purchase_to_stock; ?>
@ -60,3 +63,4 @@
</div> </div>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2 main"> <div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Purchase</h1> <h1 class="page-header">Purchase</h1>
@ -49,3 +52,4 @@
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time> <strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p> </p>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main"> <div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1> <h1 class="page-header"><?php echo $title; ?></h1>
@ -26,3 +29,4 @@
</form> </form>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header"> <h1 class="page-header">
@ -40,3 +43,4 @@
</div> </div>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header"> <h1 class="page-header">
@ -31,10 +34,10 @@
</a> </a>
</td> </td>
<td> <td>
<?php if (!empty($listItem->product_id)) echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->name . '<br>'; ?><em><?php echo $listItem->note; ?></em> <?php if (!empty($listItem->product_id)) echo FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->name . '<br>'; ?><em><?php echo $listItem->note; ?></em>
</td> </td>
<td> <td>
<?php echo $listItem->amount + $listItem->amount_autoadded; if (!empty($listItem->product_id)) echo ' ' . GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name; ?> <?php echo $listItem->amount + $listItem->amount_autoadded; if (!empty($listItem->product_id)) echo ' ' . FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name; ?>
</td> </td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
@ -43,3 +46,4 @@
</div> </div>
</div> </div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main"> <div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1> <h1 class="page-header"><?php echo $title; ?></h1>
@ -48,3 +51,4 @@
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time> <strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p> </p>
</div> </div>
@stop

View File

@ -1,11 +1,14 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Stock overview <span class="text-muded small"><strong><?php echo count($currentStock) ?></strong> products with <strong><?php echo GrocyPhpHelper::SumArrayValue($currentStock, 'amount'); ?></strong> units in stock</span></h1> <h1 class="page-header">Stock overview <span class="text-muded small"><strong><?php echo count($currentStock) ?></strong> products with <strong><?php echo SumArrayValue($currentStock, 'amount'); ?></strong> units in stock</span></h1>
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<p class="btn btn-lg btn-warning no-real-button"><strong><?php echo count(GrocyPhpHelper::FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('+5 days')), '<')); ?></strong> products expiring within the next 5 days</p> <p class="btn btn-lg btn-warning no-real-button"><strong><?php echo count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('+5 days')), '<')); ?></strong> products expiring within the next 5 days</p>
<p class="btn btn-lg btn-danger no-real-button"><strong><?php echo count(GrocyPhpHelper::FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('-1 days')), '<')); ?></strong> products are already expired</p> <p class="btn btn-lg btn-danger no-real-button"><strong><?php echo count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('-1 days')), '<')); ?></strong> products are already expired</p>
<p class="btn btn-lg btn-info no-real-button"><strong><?php echo count($missingProducts); ?></strong> products are below defined min. stock amount</p> <p class="btn btn-lg btn-info no-real-button"><strong><?php echo count($missingProducts); ?></strong> products are below defined min. stock amount</p>
</div> </div>
</div> </div>
@ -23,12 +26,12 @@
</thead> </thead>
<tbody> <tbody>
<?php foreach ($currentStock as $currentStockEntry) : ?> <?php foreach ($currentStock as $currentStockEntry) : ?>
<tr class="<?php if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('-1 days'))) echo 'error-bg'; else if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('+5 days'))) echo 'warning-bg'; else if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) echo 'info-bg'; ?>"> <tr class="<?php if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('-1 days'))) echo 'error-bg'; else if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('+5 days'))) echo 'warning-bg'; else if (FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) echo 'info-bg'; ?>">
<td> <td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name; ?> <?php echo FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name; ?>
</td> </td>
<td> <td>
<?php echo $currentStockEntry->amount . ' ' . GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name; ?> <?php echo $currentStockEntry->amount . ' ' . FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name; ?>
</td> </td>
<td> <td>
<?php echo $currentStockEntry->best_before_date; ?> <?php echo $currentStockEntry->best_before_date; ?>
@ -41,3 +44,4 @@
</div> </div>
</div> </div>
@stop

View File

@ -7,7 +7,7 @@
Grocy.FetchJson('/api/habits/get-habit-details/' + jsonForm.habit_id, Grocy.FetchJson('/api/habits/get-habit-details/' + jsonForm.habit_id,
function (habitDetails) function (habitDetails)
{ {
Grocy.FetchJson('/api/habits/track-habit/' + jsonForm.habit_id + '?tracked_time=' + $('#tracked_time').val(), Grocy.FetchJson('/api/habits/track-habit-exeuction/' + jsonForm.habit_id + '?tracked_time=' + $('#tracked_time').val(),
function(result) function(result)
{ {
toastr.success('Tracked execution of habit ' + habitDetails.habit.name + ' on ' + $('#tracked_time').val()); toastr.success('Tracked execution of habit ' + habitDetails.habit.name + ' on ' + $('#tracked_time').val());