mirror of
https://github.com/grocy/grocy.git
synced 2026-04-05 20:36:15 +02:00
merged master
only conflict was a migration script
This commit is contained in:
commit
5d980a9bd7
|
|
@ -1,6 +1,25 @@
|
|||
### New feature: Price history per store
|
||||
- Define stores under master data
|
||||
- New product option to set the default store
|
||||
- Track on purchase/inventory in which store you bought the product (gets prefilled by the last store you purchased the product, or the default store of the product if you never bought it)
|
||||
- => The price history chart on the product card shows a line per store
|
||||
- (Thanks @immae and @kriddles)
|
||||
|
||||
### Recipe fixes
|
||||
- Fixed a PHP notice on the recipes page when there are no recipes (thanks @mrunkel)
|
||||
|
||||
### Calendar fixes
|
||||
- Fixed that the "Share/Integrate calendar (iCal)" button did not work (thanks @tsia)
|
||||
|
||||
### API improvements
|
||||
- The endpoint `/stock/products/{productId}/locations` now also returns the current stock amount of the product in that loctation (new field/property `amount`) (thanks @Forceu)
|
||||
|
||||
### General & other improvements
|
||||
- New `config.php` setting `FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD` which activates the number pad for best-before-date fields on (supported) mobile browsers (useful because of [shorthands](https://github.com/grocy/grocy#input-shorthands-for-date-fields)) (defaults to `true`) (thanks @Mik-)
|
||||
- Enhancements for the camera barcode scanner (thanks @Mik-)
|
||||
- The light button only displayed when the device has a flash light
|
||||
- New `config.php` setting `FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA` to always enable the flash light automatically
|
||||
- Various display/CSS improvements
|
||||
- Prerequisites (PHP extensions, critical files/folders) will now be checked and properly reported if there are problems (thanks @Forceu)
|
||||
- Improved the the overview pages on mobile devices (main column was hidden) (thanks @Mik-)
|
||||
- Optimized the handling of settings provided by `data/settingoverrides` files (thanks @dacto)
|
||||
|
|
|
|||
|
|
@ -147,9 +147,11 @@ Setting('FEATURE_FLAG_STOCK_LOCATION_TRACKING', true);
|
|||
Setting('FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING', true);
|
||||
Setting('FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING', true);
|
||||
Setting('FEATURE_FLAG_STOCK_PRODUCT_FREEZING', true);
|
||||
Setting('FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD', true); // Activate the number pad in best-before-date fields on (supported) mobile browsers
|
||||
Setting('FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS', true);
|
||||
Setting('FEATURE_FLAG_CHORES_ASSIGNMENTS', true);
|
||||
|
||||
|
||||
# Feature settings
|
||||
Setting('FEATURE_SETTING_STOCK_COUNT_OPENED_PRODUCTS_AGAINST_MINIMUM_STOCK_AMOUNT', true); // When set to false, opened products will not be considered for minimum stock amounts
|
||||
Setting('FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA', true); // Enables the torch automaticaly in every camera barcode scanner.
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class CalendarApiController extends BaseApiController
|
|||
try
|
||||
{
|
||||
return $this->ApiResponse($response, array(
|
||||
'url' => $this->AppContainer->get('UrlManager')->ConstructUrl('/api/calendar/ical?secret=' . $this->getApiKeyService()->GetOrCreateApiKey(ApiKeyService::API_KEY_TYPE_SPECIAL_PURPOSE_CALENDAR_ICAL))
|
||||
'url' => $this->AppContainer->get('UrlManager')->ConstructUrl('/api/calendar/ical?secret=' . $this->getApiKeyService()->GetOrCreateApiKey(\Grocy\Services\ApiKeyService::API_KEY_TYPE_SPECIAL_PURPOSE_CALENDAR_ICAL))
|
||||
));
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
|
|
|
|||
|
|
@ -82,13 +82,19 @@ class StockApiController extends BaseApiController
|
|||
$locationId = $requestBody['location_id'];
|
||||
}
|
||||
|
||||
$shoppingLocationId = null;
|
||||
if (array_key_exists('shopping_location_id', $requestBody) && is_numeric($requestBody['shopping_location_id']))
|
||||
{
|
||||
$shoppingLocationId = $requestBody['shopping_location_id'];
|
||||
}
|
||||
|
||||
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
|
||||
if (array_key_exists('transaction_type', $requestBody) && !empty($requestBody['transactiontype']))
|
||||
{
|
||||
$transactionType = $requestBody['transactiontype'];
|
||||
}
|
||||
|
||||
$bookingId = $this->getStockService()->AddProduct($args['productId'], $requestBody['amount'], $bestBeforeDate, $transactionType, date('Y-m-d'), $price, $locationId);
|
||||
$bookingId = $this->getStockService()->AddProduct($args['productId'], $requestBody['amount'], $bestBeforeDate, $transactionType, date('Y-m-d'), $price, $locationId, $shoppingLocationId);
|
||||
return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId));
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
|
|
@ -144,7 +150,13 @@ class StockApiController extends BaseApiController
|
|||
$locationId = $requestBody['location_id'];
|
||||
}
|
||||
|
||||
$bookingId = $this->getStockService()->EditStockEntry($args['entryId'], $requestBody['amount'], $bestBeforeDate, $locationId, $price, $requestBody['open'], $requestBody['purchased_date']);
|
||||
$shoppingLocationId = null;
|
||||
if (array_key_exists('shopping_location_id', $requestBody) && is_numeric($requestBody['shopping_location_id']))
|
||||
{
|
||||
$shoppingLocationId = $requestBody['shopping_location_id'];
|
||||
}
|
||||
|
||||
$bookingId = $this->getStockService()->EditStockEntry($args['entryId'], $requestBody['amount'], $bestBeforeDate, $locationId, $shoppingLocationId, $price, $requestBody['open'], $requestBody['purchased_date']);
|
||||
return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId));
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
|
|
@ -312,7 +324,13 @@ class StockApiController extends BaseApiController
|
|||
$price = $requestBody['price'];
|
||||
}
|
||||
|
||||
$bookingId = $this->getStockService()->InventoryProduct($args['productId'], $requestBody['new_amount'], $bestBeforeDate, $locationId, $price);
|
||||
$shoppingLocationId = null;
|
||||
if (array_key_exists('shopping_location_id', $requestBody) && is_numeric($requestBody['shopping_location_id']))
|
||||
{
|
||||
$shoppingLocationId = $requestBody['shopping_location_id'];
|
||||
}
|
||||
|
||||
$bookingId = $this->getStockService()->InventoryProduct($args['productId'], $requestBody['new_amount'], $bestBeforeDate, $locationId, $price, $shoppingLocationId);
|
||||
return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId));
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class StockController extends BaseController
|
|||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||
'stockEntries' => $this->getDatabase()->stock()->orderBy('product_id'),
|
||||
'currentStockLocations' => $this->getStockService()->GetCurrentStockLocations(),
|
||||
'nextXDays' => $nextXDays,
|
||||
|
|
@ -50,6 +51,7 @@ class StockController extends BaseController
|
|||
{
|
||||
return $this->renderPage($response, 'purchase', [
|
||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
||||
]);
|
||||
}
|
||||
|
|
@ -76,6 +78,7 @@ class StockController extends BaseController
|
|||
{
|
||||
return $this->renderPage($response, 'inventory', [
|
||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
||||
]);
|
||||
}
|
||||
|
|
@ -85,6 +88,7 @@ class StockController extends BaseController
|
|||
return $this->renderPage($response, 'stockentryform', [
|
||||
'stockEntry' => $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch(),
|
||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
||||
]);
|
||||
}
|
||||
|
|
@ -140,6 +144,15 @@ class StockController extends BaseController
|
|||
]);
|
||||
}
|
||||
|
||||
public function ShoppingLocationsList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
return $this->renderPage($response, 'shoppinglocations', [
|
||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||
'userfields' => $this->getUserfieldsService()->GetFields('shopping_locations'),
|
||||
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('shopping_locations')
|
||||
]);
|
||||
}
|
||||
|
||||
public function ProductGroupsList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
return $this->renderPage($response, 'productgroups', [
|
||||
|
|
@ -166,6 +179,7 @@ class StockController extends BaseController
|
|||
return $this->renderPage($response, 'productform', [
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||
'products' => $this->getDatabase()->products()->where('parent_product_id IS NULL')->orderBy('name'),
|
||||
|
|
@ -181,6 +195,7 @@ class StockController extends BaseController
|
|||
'product' => $product,
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||
'products' => $this->getDatabase()->products()->where('id != :1 AND parent_product_id IS NULL', $product->id)->orderBy('name'),
|
||||
|
|
@ -210,6 +225,25 @@ class StockController extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
public function ShoppingLocationEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if ($args['shoppingLocationId'] == 'new')
|
||||
{
|
||||
return $this->renderPage($response, 'shoppinglocationform', [
|
||||
'mode' => 'create',
|
||||
'userfields' => $this->getUserfieldsService()->GetFields('shopping_locations')
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->renderPage($response, 'shoppinglocationform', [
|
||||
'shoppinglocation' => $this->getDatabase()->shopping_locations($args['shoppingLocationId']),
|
||||
'mode' => 'edit',
|
||||
'userfields' => $this->getUserfieldsService()->GetFields('shopping_locations')
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function ProductGroupEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if ($args['productGroupId'] == 'new')
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class DemoBarcodeLookupPlugin extends BaseBarcodeLookupPlugin
|
|||
|
||||
/*
|
||||
To try it:
|
||||
Call the API function at /api/stock/external-barcode-lookup/{barcode}
|
||||
Call the API function at /api/stock/barcodes/external-lookup/{barcode}
|
||||
|
||||
When you also add ?add=true as a query parameter to the API call,
|
||||
on a successful lookup the product is added to the database and in the output
|
||||
|
|
|
|||
|
|
@ -1172,6 +1172,11 @@
|
|||
"format": "integer",
|
||||
"description": "If omitted, the default location of the product is used"
|
||||
},
|
||||
"shopping_location_id": {
|
||||
"type": "number",
|
||||
"format": "integer",
|
||||
"description": "If omitted, no store will be affected"
|
||||
},
|
||||
"purchased_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
|
|
@ -1478,6 +1483,11 @@
|
|||
"type": "number",
|
||||
"format": "integer",
|
||||
"description": "If omitted, the default location of the product is used"
|
||||
},
|
||||
"shopping_location_id": {
|
||||
"type": "number",
|
||||
"format": "integer",
|
||||
"description": "If omitted, no store will be affected"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
|
|
@ -1706,6 +1716,11 @@
|
|||
"format": "date",
|
||||
"description": "The best before date which applies to added products"
|
||||
},
|
||||
"shopping_location_id": {
|
||||
"type": "number",
|
||||
"format": "integer",
|
||||
"description": "If omitted, no store will be affected"
|
||||
},
|
||||
"location_id": {
|
||||
"type": "number",
|
||||
"format": "integer",
|
||||
|
|
@ -3303,6 +3318,7 @@
|
|||
"quantity_unit_conversions",
|
||||
"shopping_list",
|
||||
"shopping_lists",
|
||||
"shopping_locations",
|
||||
"recipes",
|
||||
"recipes_pos",
|
||||
"recipes_nestings",
|
||||
|
|
@ -3328,6 +3344,7 @@
|
|||
"quantity_unit_conversions",
|
||||
"shopping_list",
|
||||
"shopping_lists",
|
||||
"shopping_locations",
|
||||
"recipes",
|
||||
"recipes_pos",
|
||||
"recipes_nestings",
|
||||
|
|
@ -3418,6 +3435,9 @@
|
|||
"row_created_timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"shopping_location_id": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
|
|
@ -3438,7 +3458,8 @@
|
|||
"allow_partial_units_in_stock": "0",
|
||||
"enable_tare_weight_handling": "0",
|
||||
"tare_weight": "0.0",
|
||||
"not_check_stock_fulfillment_for_recipes": "0"
|
||||
"not_check_stock_fulfillment_for_recipes": "0",
|
||||
"shopping_location_id": null
|
||||
}
|
||||
},
|
||||
"QuantityUnit": {
|
||||
|
|
@ -3497,6 +3518,30 @@
|
|||
"row_created_timestamp": "2019-05-02 20:12:25"
|
||||
}
|
||||
},
|
||||
"ShoppingLocation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"row_created_timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"id": "2",
|
||||
"name": "0",
|
||||
"description": null,
|
||||
"row_created_timestamp": "2019-05-02 20:12:25"
|
||||
}
|
||||
},
|
||||
"StockLocation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -3506,6 +3551,9 @@
|
|||
"product_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"amount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"location_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
|
@ -3519,6 +3567,7 @@
|
|||
"example": {
|
||||
"id": "1",
|
||||
"product_id": "3",
|
||||
"amount": "2",
|
||||
"location_id": "1",
|
||||
"name": "Fridge"
|
||||
}
|
||||
|
|
@ -3535,6 +3584,9 @@
|
|||
"location_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"shopping_location_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"amount": {
|
||||
"type": "number"
|
||||
},
|
||||
|
|
@ -3576,7 +3628,8 @@
|
|||
"open": "0",
|
||||
"opened_date": null,
|
||||
"row_created_timestamp": "2019-05-03 18:24:04",
|
||||
"location_id": "4"
|
||||
"location_id": "4",
|
||||
"shopping_location_id": null
|
||||
}
|
||||
},
|
||||
"RecipeFulfillmentResponse": {
|
||||
|
|
@ -3641,6 +3694,9 @@
|
|||
"type": "number",
|
||||
"format": "number"
|
||||
},
|
||||
"last_shopping_location_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location"
|
||||
},
|
||||
|
|
@ -3672,7 +3728,8 @@
|
|||
"allow_partial_units_in_stock": "0",
|
||||
"enable_tare_weight_handling": "0",
|
||||
"tare_weight": "0.0",
|
||||
"not_check_stock_fulfillment_for_recipes": "0"
|
||||
"not_check_stock_fulfillment_for_recipes": "0",
|
||||
"last_shopping_location_id": null
|
||||
},
|
||||
"last_purchased": null,
|
||||
"last_used": null,
|
||||
|
|
@ -3695,6 +3752,7 @@
|
|||
"plural_forms": null
|
||||
},
|
||||
"last_price": null,
|
||||
"last_shopping_location_id": null,
|
||||
"next_best_before_date": "2019-07-07",
|
||||
"location": {
|
||||
"id": "4",
|
||||
|
|
@ -3716,6 +3774,9 @@
|
|||
"price": {
|
||||
"type": "number",
|
||||
"format": "number"
|
||||
},
|
||||
"shopping_location": {
|
||||
"$ref": "#/components/schemas/ShoppingLocation"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -138,6 +138,20 @@ function BoolToString(bool $bool)
|
|||
return $bool ? 'true' : 'false';
|
||||
}
|
||||
|
||||
function ExternalSettingValue(string $value)
|
||||
{
|
||||
$tvalue = rtrim($value, "\r\n");
|
||||
$lvalue = strtolower($tvalue);
|
||||
if ($lvalue === "true"){
|
||||
return true;
|
||||
}
|
||||
elseif ($lvalue === "false")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return $tvalue;
|
||||
}
|
||||
|
||||
function Setting(string $name, $value)
|
||||
{
|
||||
if (!defined('GROCY_' . $name))
|
||||
|
|
@ -146,22 +160,11 @@ function Setting(string $name, $value)
|
|||
$settingOverrideFile = GROCY_DATAPATH . '/settingoverrides/' . $name . '.txt';
|
||||
if (file_exists($settingOverrideFile))
|
||||
{
|
||||
define('GROCY_' . $name, file_get_contents($settingOverrideFile));
|
||||
define('GROCY_' . $name, ExternalSettingValue(file_get_contents($settingOverrideFile)));
|
||||
}
|
||||
elseif (getenv('GROCY_' . $name) !== false) // An environment variable with the same name and prefix GROCY_ overwrites the given setting
|
||||
{
|
||||
if (strtolower(getenv('GROCY_' . $name)) === "true")
|
||||
{
|
||||
define('GROCY_' . $name, true);
|
||||
}
|
||||
elseif (strtolower(getenv('GROCY_' . $name)) === "false")
|
||||
{
|
||||
define('GROCY_' . $name, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
define('GROCY_' . $name, getenv('GROCY_' . $name));
|
||||
}
|
||||
define('GROCY_' . $name, ExternalSettingValue(getenv('GROCY_'. $name)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -345,3 +345,11 @@ msgstr ""
|
|||
|
||||
msgid "Portuguese (Portugal)"
|
||||
msgstr ""
|
||||
|
||||
# Use a in your country well known supermarket name
|
||||
msgid "DemoSupermarket1"
|
||||
msgstr ""
|
||||
|
||||
# Use a in your country well known supermarket name
|
||||
msgid "DemoSupermarket2"
|
||||
msgstr ""
|
||||
|
|
|
|||
|
|
@ -284,3 +284,9 @@ msgstr "Swedish"
|
|||
|
||||
msgid "Polish"
|
||||
msgstr "Polish"
|
||||
|
||||
msgid "DemoSupermarket1"
|
||||
msgstr "Walmart"
|
||||
|
||||
msgid "DemoSupermarket2"
|
||||
msgstr "Kroger"
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ msgstr "Products"
|
|||
msgid "Locations"
|
||||
msgstr "Locations"
|
||||
|
||||
msgid "Shopping locations"
|
||||
msgstr "Shopping locations"
|
||||
|
||||
msgid "Quantity units"
|
||||
msgstr "Quantity units"
|
||||
|
||||
|
|
@ -162,6 +165,9 @@ msgstr "Name"
|
|||
msgid "Location"
|
||||
msgstr "Location"
|
||||
|
||||
msgid "Shopping location"
|
||||
msgstr "Shopping location"
|
||||
|
||||
msgid "Min. stock amount"
|
||||
msgstr "Min. stock amount"
|
||||
|
||||
|
|
@ -201,6 +207,9 @@ msgstr "Factor purchase to stock quantity unit"
|
|||
msgid "Create location"
|
||||
msgstr "Create location"
|
||||
|
||||
msgid "Create shopping location"
|
||||
msgstr "Create shopping location"
|
||||
|
||||
msgid "Create quantity unit"
|
||||
msgstr "Create quantity unit"
|
||||
|
||||
|
|
@ -234,6 +243,9 @@ msgstr "Edit product"
|
|||
msgid "Edit location"
|
||||
msgstr "Edit location"
|
||||
|
||||
msgid "Edit shopping location"
|
||||
msgstr "Edit shopping location"
|
||||
|
||||
msgid "Record data"
|
||||
msgstr "Record data"
|
||||
|
||||
|
|
@ -306,6 +318,9 @@ msgstr "Are you sure to delete product \"%s\"?"
|
|||
msgid "Are you sure to delete location \"%s\"?"
|
||||
msgstr "Are you sure to delete location \"%s\"?"
|
||||
|
||||
msgid "Are you sure to delete shopping location \"%s\"?"
|
||||
msgstr "Are you sure to delete shopping location \"%s\"?"
|
||||
|
||||
msgid "Manage API keys"
|
||||
msgstr "Manage API keys"
|
||||
|
||||
|
|
@ -1035,6 +1050,9 @@ msgstr "Tare weight handling enabled - please weigh the whole container, the amo
|
|||
msgid "You have to select a location"
|
||||
msgstr "You have to select a location"
|
||||
|
||||
msgid "You have to select a shopping location"
|
||||
msgstr "You have to select a shopping location"
|
||||
|
||||
msgid "List"
|
||||
msgstr "List"
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@ msgstr "Suivi des piles"
|
|||
msgid "Locations"
|
||||
msgstr "Emplacements"
|
||||
|
||||
msgid "Shopping locations"
|
||||
msgstr "Commerces"
|
||||
|
||||
msgid "Quantity units"
|
||||
msgstr "Formats"
|
||||
|
||||
|
|
@ -198,6 +201,9 @@ msgstr "Nom"
|
|||
msgid "Location"
|
||||
msgstr "Emplacement"
|
||||
|
||||
msgid "Shopping location"
|
||||
msgstr "Commerce"
|
||||
|
||||
msgid "Min. stock amount"
|
||||
msgstr "Quantité minimum en stock"
|
||||
|
||||
|
|
@ -237,6 +243,9 @@ msgstr "Facteur entre la quantité à l'achat et la quantité en stock"
|
|||
msgid "Create location"
|
||||
msgstr "Créer un emplacement"
|
||||
|
||||
msgid "Create shopping location"
|
||||
msgstr "Créer un commerce"
|
||||
|
||||
msgid "Create quantity unit"
|
||||
msgstr "Créer un format"
|
||||
|
||||
|
|
@ -270,6 +279,9 @@ msgstr "Modifier le produit"
|
|||
msgid "Edit location"
|
||||
msgstr "Modifier l'emplacement"
|
||||
|
||||
msgid "Edit shopping location"
|
||||
msgstr "Modifier le commerce"
|
||||
|
||||
msgid "Record data"
|
||||
msgstr "Enregistrer les données"
|
||||
|
||||
|
|
@ -347,6 +359,9 @@ msgstr "Voulez-vous vraiment supprimer le produit \"%s\" ?"
|
|||
msgid "Are you sure to delete location \"%s\"?"
|
||||
msgstr "Voulez-vous vraiment supprimer l'emplacement \"%s\" ?"
|
||||
|
||||
msgid "Are you sure to delete shopping location \"%s\"?"
|
||||
msgstr "Voulez-vous vraiment supprimer le commerce \"%s\" ?"
|
||||
|
||||
msgid "Manage API keys"
|
||||
msgstr "Gérer les clefs API"
|
||||
|
||||
|
|
@ -1124,6 +1139,9 @@ msgstr ""
|
|||
msgid "You have to select a location"
|
||||
msgstr "Vous devez sélectionner un endroit"
|
||||
|
||||
msgid "You have to select a shopping location"
|
||||
msgstr "Vous devez sélectionner un commerce"
|
||||
|
||||
msgid "List"
|
||||
msgstr "Liste"
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ msgstr ""
|
|||
msgid "Locations"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stores"
|
||||
msgstr ""
|
||||
|
||||
msgid "Quantity units"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -214,6 +217,9 @@ msgstr ""
|
|||
msgid "Create location"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create store"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create quantity unit"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -247,6 +253,9 @@ msgstr ""
|
|||
msgid "Edit location"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit store"
|
||||
msgstr ""
|
||||
|
||||
msgid "Record data"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -319,6 +328,9 @@ msgstr ""
|
|||
msgid "Are you sure to delete location \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure to delete store \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Manage API keys"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -1022,6 +1034,9 @@ msgstr ""
|
|||
msgid "You have to select a location"
|
||||
msgstr ""
|
||||
|
||||
msgid "You have to select a store"
|
||||
msgstr ""
|
||||
|
||||
msgid "List"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -1744,3 +1759,15 @@ msgstr ""
|
|||
|
||||
msgid "Group ingredients by their product group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unknown store"
|
||||
msgstr ""
|
||||
|
||||
msgid "Store"
|
||||
msgstr ""
|
||||
|
||||
msgid "Transaction successfully undone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Default store"
|
||||
msgstr ""
|
||||
|
|
|
|||
|
|
@ -1,2 +1,30 @@
|
|||
CREATE TABLE shopping_locations (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||
);
|
||||
|
||||
ALTER TABLE stock_log
|
||||
ADD shopping_location_id INTEGER;
|
||||
|
||||
ALTER TABLE stock
|
||||
ADD shopping_location_id INTEGER;
|
||||
|
||||
ALTER TABLE products
|
||||
ADD picture_url TEXT;
|
||||
ADD shopping_location_id INTEGER;
|
||||
|
||||
DROP VIEW stock_current_locations;
|
||||
CREATE VIEW stock_current_locations
|
||||
AS
|
||||
SELECT
|
||||
1 AS id, -- Dummy, LessQL needs an id column
|
||||
s.product_id,
|
||||
SUM(s.amount) as amount,
|
||||
s.location_id AS location_id,
|
||||
l.name AS location_name,
|
||||
l.is_freezer AS location_is_freezer
|
||||
FROM stock s
|
||||
JOIN locations l
|
||||
ON s.location_id = l.id
|
||||
GROUP BY s.product_id, s.location_id, l.name;
|
||||
|
|
|
|||
2
migrations/0100.sql
Normal file
2
migrations/0100.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE products
|
||||
ADD picture_url TEXT;
|
||||
|
|
@ -259,6 +259,21 @@ input::-webkit-inner-spin-button {
|
|||
color: inherit;
|
||||
}
|
||||
|
||||
/* Barcodescanner Quagga */
|
||||
#barcodescanner-container {
|
||||
max-height: 90vw;
|
||||
}
|
||||
#livestream-container {
|
||||
max-height: 100%;
|
||||
}
|
||||
#barcodescanner-livestream video {
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
#barcodescanner-livestream canvas {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Third party component customizations - Bootstrap */
|
||||
|
||||
/* Hide the form validation feedback icons introduced in Bootstrap 4.2.0 - a colored border is enough */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,42 @@
|
|||
Grocy.Components.BarcodeScanner = { };
|
||||
|
||||
Grocy.Components.BarcodeScanner.CheckCapabilities = function()
|
||||
{
|
||||
var track = Quagga.CameraAccess.getActiveTrack();
|
||||
var capabilities = {};
|
||||
if (typeof track.getCapabilities === 'function') {
|
||||
capabilities = track.getCapabilities();
|
||||
}
|
||||
|
||||
// Check if the camera is capable to turn on a torch.
|
||||
var canTorch = typeof capabilities.torch === 'boolean' && capabilities.torch
|
||||
// Remove the torch button, if either the device can not torch or AutoTorchOn is set.
|
||||
var node = document.querySelector('.torch');
|
||||
if (node) {
|
||||
node.style.display = canTorch && !Grocy.FeatureFlags.GROCY_FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA ? 'inline-block' : 'none';
|
||||
}
|
||||
// If AutoTorchOn is set, turn on the torch.
|
||||
if (canTorch && Grocy.FeatureFlags.GROCY_FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA) {
|
||||
Grocy.Components.BarcodeScanner.TorchOn(track);
|
||||
}
|
||||
|
||||
// Reduce the height of the video, if it's heigher than then the viewport
|
||||
var bc = document.getElementById('barcodescanner-container');
|
||||
if (bc) {
|
||||
var bcAspectRatio = bc.offsetWidth / bc.offsetHeight;
|
||||
var settings = track.getSettings();
|
||||
if (bcAspectRatio > settings.aspectRatio) {
|
||||
var v = document.querySelector('#barcodescanner-livestream video')
|
||||
if (v) {
|
||||
var c = document.querySelector('#barcodescanner-livestream canvas')
|
||||
var newWidth = v.clientWidth / bcAspectRatio * settings.aspectRatio + 'px';
|
||||
v.style.width = newWidth;
|
||||
c.style.width = newWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Grocy.Components.BarcodeScanner.StartScanning = function()
|
||||
{
|
||||
Grocy.Components.BarcodeScanner.DecodedCodesCount = 0;
|
||||
|
|
@ -11,8 +48,6 @@ Grocy.Components.BarcodeScanner.StartScanning = function()
|
|||
type: "LiveStream",
|
||||
target: document.querySelector("#barcodescanner-livestream"),
|
||||
constraints: {
|
||||
width: 436,
|
||||
height: 327,
|
||||
facingMode: "environment"
|
||||
}
|
||||
},
|
||||
|
|
@ -70,6 +105,9 @@ Grocy.Components.BarcodeScanner.StartScanning = function()
|
|||
}, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
Grocy.Components.BarcodeScanner.CheckCapabilities();
|
||||
|
||||
Quagga.start();
|
||||
});
|
||||
}
|
||||
|
|
@ -84,6 +122,19 @@ Grocy.Components.BarcodeScanner.StopScanning = function()
|
|||
bootbox.hideAll();
|
||||
}
|
||||
|
||||
Grocy.Components.BarcodeScanner.TorchOn = function(track)
|
||||
{
|
||||
if (track) {
|
||||
track.applyConstraints({
|
||||
advanced: [
|
||||
{
|
||||
torch: true
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Quagga.onDetected(function(result)
|
||||
{
|
||||
$.each(result.codeResult.decodedCodes, function(id, error)
|
||||
|
|
@ -157,10 +208,10 @@ $(document).on("click", "#barcodescanner-start-button", function(e)
|
|||
buttons: {
|
||||
torch: {
|
||||
label: '<i class="far fa-lightbulb"></i>',
|
||||
className: 'btn-warning responsive-button',
|
||||
className: 'btn-warning responsive-button torch',
|
||||
callback: function()
|
||||
{
|
||||
Quagga.CameraAccess.getActiveTrack().applyConstraints({ advanced: [{ torch: true }] });
|
||||
Grocy.Components.BarcodeScanner.TorchOn(Quagga.CameraAccess.getActiveTrack());
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -123,12 +123,30 @@ Grocy.Components.ProductCard.Refresh = function(productId)
|
|||
$("#productcard-no-price-data-hint").addClass("d-none");
|
||||
|
||||
Grocy.Components.ProductCard.ReInitPriceHistoryChart();
|
||||
var datasets = {};
|
||||
var chart = Grocy.Components.ProductCard.PriceHistoryChart.data;
|
||||
priceHistoryDataPoints.forEach((dataPoint) =>
|
||||
{
|
||||
Grocy.Components.ProductCard.PriceHistoryChart.data.labels.push(moment(dataPoint.date).toDate());
|
||||
var key = __t("Unknown store");
|
||||
if (dataPoint.shopping_location)
|
||||
{
|
||||
key = dataPoint.shopping_location.name
|
||||
}
|
||||
|
||||
if (!datasets[key]) {
|
||||
datasets[key] = []
|
||||
}
|
||||
chart.labels.push(moment(dataPoint.date).toDate());
|
||||
datasets[key].push(dataPoint.price);
|
||||
|
||||
var dataset = Grocy.Components.ProductCard.PriceHistoryChart.data.datasets[0];
|
||||
dataset.data.push(dataPoint.price);
|
||||
});
|
||||
Object.keys(datasets).forEach((key) => {
|
||||
chart.datasets.push({
|
||||
data: datasets[key],
|
||||
fill: false,
|
||||
borderColor: "HSL(" + (129 * chart.datasets.length) + ",100%,50%)",
|
||||
label: key,
|
||||
});
|
||||
});
|
||||
Grocy.Components.ProductCard.PriceHistoryChart.update();
|
||||
}
|
||||
|
|
@ -160,13 +178,9 @@ Grocy.Components.ProductCard.ReInitPriceHistoryChart = function()
|
|||
labels: [ //Date objects
|
||||
// Will be populated in Grocy.Components.ProductCard.Refresh
|
||||
],
|
||||
datasets: [{
|
||||
data: [
|
||||
// Will be populated in Grocy.Components.ProductCard.Refresh
|
||||
],
|
||||
fill: false,
|
||||
borderColor: '%s7a2b8'
|
||||
}]
|
||||
datasets: [ //Datasets
|
||||
// Will be populated in Grocy.Components.ProductCard.Refresh
|
||||
]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
|
|
@ -194,7 +208,7 @@ Grocy.Components.ProductCard.ReInitPriceHistoryChart = function()
|
|||
}]
|
||||
},
|
||||
legend: {
|
||||
display: false
|
||||
display: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
68
public/viewjs/components/shoppinglocationpicker.js
Normal file
68
public/viewjs/components/shoppinglocationpicker.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
Grocy.Components.ShoppingLocationPicker = { };
|
||||
|
||||
Grocy.Components.ShoppingLocationPicker.GetPicker = function()
|
||||
{
|
||||
return $('#shopping_location_id');
|
||||
}
|
||||
|
||||
Grocy.Components.ShoppingLocationPicker.GetInputElement = function()
|
||||
{
|
||||
return $('#shopping_location_id_text_input');
|
||||
}
|
||||
|
||||
Grocy.Components.ShoppingLocationPicker.GetValue = function()
|
||||
{
|
||||
return $('#shopping_location_id').val();
|
||||
}
|
||||
|
||||
Grocy.Components.ShoppingLocationPicker.SetValue = function(value)
|
||||
{
|
||||
Grocy.Components.ShoppingLocationPicker.GetInputElement().val(value);
|
||||
Grocy.Components.ShoppingLocationPicker.GetInputElement().trigger('change');
|
||||
}
|
||||
|
||||
Grocy.Components.ShoppingLocationPicker.SetId = function(value)
|
||||
{
|
||||
Grocy.Components.ShoppingLocationPicker.GetPicker().val(value);
|
||||
Grocy.Components.ShoppingLocationPicker.GetPicker().data('combobox').refresh();
|
||||
Grocy.Components.ShoppingLocationPicker.GetInputElement().trigger('change');
|
||||
}
|
||||
|
||||
Grocy.Components.ShoppingLocationPicker.Clear = function()
|
||||
{
|
||||
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
||||
Grocy.Components.ShoppingLocationPicker.SetId(null);
|
||||
}
|
||||
|
||||
$('.shopping-location-combobox').combobox({
|
||||
appendId: '_text_input',
|
||||
bsVersion: '4',
|
||||
clearIfNoMatch: false
|
||||
});
|
||||
|
||||
var prefillByName = Grocy.Components.ShoppingLocationPicker.GetPicker().parent().data('prefill-by-name').toString();
|
||||
if (typeof prefillByName !== "undefined")
|
||||
{
|
||||
possibleOptionElement = $("#shopping_location_id option:contains(\"" + prefillByName + "\")").first();
|
||||
|
||||
if (possibleOptionElement.length > 0)
|
||||
{
|
||||
$('#shopping_location_id').val(possibleOptionElement.val());
|
||||
$('#shopping_location_id').data('combobox').refresh();
|
||||
$('#shopping_location_id').trigger('change');
|
||||
|
||||
var nextInputElement = $(Grocy.Components.ShoppingLocationPicker.GetPicker().parent().data('next-input-selector').toString());
|
||||
nextInputElement.focus();
|
||||
}
|
||||
}
|
||||
|
||||
var prefillById = Grocy.Components.ShoppingLocationPicker.GetPicker().parent().data('prefill-by-id').toString();
|
||||
if (typeof prefillById !== "undefined")
|
||||
{
|
||||
$('#shopping_location_id').val(prefillById);
|
||||
$('#shopping_location_id').data('combobox').refresh();
|
||||
$('#shopping_location_id').trigger('change');
|
||||
|
||||
var nextInputElement = $(Grocy.Components.ShoppingLocationPicker.GetPicker().parent().data('next-input-selector').toString());
|
||||
nextInputElement.focus();
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
var jsonData = { };
|
||||
jsonData.new_amount = jsonForm.new_amount;
|
||||
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
||||
jsonData.shopping_location_id = Grocy.Components.ShoppingLocationPicker.GetValue();
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
||||
|
|
@ -84,6 +85,7 @@
|
|||
$('#price').val('');
|
||||
Grocy.Components.DateTimePicker.Clear();
|
||||
Grocy.Components.ProductPicker.SetValue('');
|
||||
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
||||
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||
|
|
@ -150,6 +152,7 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
|||
}
|
||||
|
||||
$('#price').val(productDetails.last_price);
|
||||
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.last_shopping_location_id);
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
var jsonData = {};
|
||||
jsonData.amount = amount;
|
||||
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
||||
jsonData.shopping_location_id = Grocy.Components.ShoppingLocationPicker.GetValue();
|
||||
jsonData.price = price;
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
|
|
@ -99,6 +100,7 @@
|
|||
}
|
||||
Grocy.Components.DateTimePicker.Clear();
|
||||
Grocy.Components.ProductPicker.SetValue('');
|
||||
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
||||
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||
|
|
@ -138,6 +140,16 @@ if (Grocy.Components.ProductPicker !== undefined)
|
|||
function(productDetails)
|
||||
{
|
||||
$('#price').val(productDetails.last_price);
|
||||
|
||||
if (productDetails.last_shopping_location_id != null)
|
||||
{
|
||||
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.last_shopping_location_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.default_shopping_location_id);
|
||||
}
|
||||
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
||||
|
|
|
|||
69
public/viewjs/shoppinglocationform.js
Normal file
69
public/viewjs/shoppinglocationform.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
$('#save-shopping-location-button').on('click', function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
|
||||
var jsonData = $('#shoppinglocation-form').serializeJSON();
|
||||
Grocy.FrontendHelpers.BeginUiBusy("shoppinglocation-form");
|
||||
|
||||
if (Grocy.EditMode === 'create')
|
||||
{
|
||||
Grocy.Api.Post('objects/shopping_locations', jsonData,
|
||||
function(result)
|
||||
{
|
||||
Grocy.EditObjectId = result.created_object_id;
|
||||
Grocy.Components.UserfieldsForm.Save(function()
|
||||
{
|
||||
window.location.href = U('/shoppinglocations');
|
||||
});
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
Grocy.FrontendHelpers.EndUiBusy("shoppinglocation-form");
|
||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Grocy.Api.Put('objects/shopping_locations/' + Grocy.EditObjectId, jsonData,
|
||||
function(result)
|
||||
{
|
||||
Grocy.Components.UserfieldsForm.Save(function()
|
||||
{
|
||||
window.location.href = U('/shoppinglocations');
|
||||
});
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
Grocy.FrontendHelpers.EndUiBusy("shoppinglocation-form");
|
||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
$('#shoppinglocation-form input').keyup(function (event)
|
||||
{
|
||||
Grocy.FrontendHelpers.ValidateForm('shoppinglocation-form');
|
||||
});
|
||||
|
||||
$('#shoppinglocation-form input').keydown(function (event)
|
||||
{
|
||||
if (event.keyCode === 13) //Enter
|
||||
{
|
||||
event.preventDefault();
|
||||
|
||||
if (document.getElementById('shoppinglocation-form').checkValidity() === false) //There is at least one validation error
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#save-shopping-location-button').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Grocy.Components.UserfieldsForm.Load();
|
||||
$('#name').focus();
|
||||
Grocy.FrontendHelpers.ValidateForm('shoppinglocation-form');
|
||||
57
public/viewjs/shoppinglocations.js
Normal file
57
public/viewjs/shoppinglocations.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
var locationsTable = $('#shoppinglocations-table').DataTable({
|
||||
'order': [[1, 'asc']],
|
||||
'columnDefs': [
|
||||
{ 'orderable': false, 'targets': 0 },
|
||||
{ 'searchable': false, "targets": 0 }
|
||||
]
|
||||
});
|
||||
$('#shoppinglocations-table tbody').removeClass("d-none");
|
||||
locationsTable.columns.adjust().draw();
|
||||
|
||||
$("#search").on("keyup", Delay(function()
|
||||
{
|
||||
var value = $(this).val();
|
||||
if (value === "all")
|
||||
{
|
||||
value = "";
|
||||
}
|
||||
|
||||
locationsTable.search(value).draw();
|
||||
}, 200));
|
||||
|
||||
$(document).on('click', '.shoppinglocation-delete-button', function (e)
|
||||
{
|
||||
var objectName = $(e.currentTarget).attr('data-shoppinglocation-name');
|
||||
var objectId = $(e.currentTarget).attr('data-shoppinglocation-id');
|
||||
|
||||
bootbox.confirm({
|
||||
message: __t('Are you sure to delete store "%s"?', objectName),
|
||||
closeButton: false,
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: __t('Yes'),
|
||||
className: 'btn-success'
|
||||
},
|
||||
cancel: {
|
||||
label: __t('No'),
|
||||
className: 'btn-danger'
|
||||
}
|
||||
},
|
||||
callback: function(result)
|
||||
{
|
||||
if (result === true)
|
||||
{
|
||||
Grocy.Api.Delete('objects/shopping_locations/' + objectId, {},
|
||||
function(result)
|
||||
{
|
||||
window.location.href = U('/shoppinglocations');
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -166,18 +166,35 @@ function RefreshStockEntryRow(stockRowId)
|
|||
function(locationResult)
|
||||
{
|
||||
locationName = locationResult.name;
|
||||
|
||||
$('#stock-' + stockRowId + '-location').attr('data-location-id', result.location_id);
|
||||
$('#stock-' + stockRowId + '-location').text(locationName);
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
$('#stock-' + stockRowId + '-location').attr('data-location-id', result.location_id);
|
||||
$('#stock-' + stockRowId + '-location').text(locationName);
|
||||
|
||||
$('#stock-' + stockRowId + '-price').text(result.price);
|
||||
$('#stock-' + stockRowId + '-purchased-date').text(result.purchased_date);
|
||||
$('#stock-' + stockRowId + '-purchased-date-timeago').attr('datetime', result.purchased_date + ' 23:59:59');
|
||||
|
||||
var shoppingLocationName = "";
|
||||
Grocy.Api.Get("objects/shopping_locations/" + result.shopping_location_id,
|
||||
function(shoppingLocationResult)
|
||||
{
|
||||
shoppingLocationName = shoppingLocationResult.name;
|
||||
|
||||
$('#stock-' + stockRowId + '-shopping-location').attr('data-shopping-location-id', result.location_id);
|
||||
$('#stock-' + stockRowId + '-shopping-location').text(shoppingLocationName);
|
||||
},
|
||||
function (xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
|
||||
if (result.open == 1)
|
||||
{
|
||||
$('#stock-' + stockRowId + '-opened-amount').text(__t('Opened'));
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
jsonData.amount = jsonForm.amount;
|
||||
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
||||
jsonData.purchased_date = Grocy.Components.DateTimePicker2.GetValue();
|
||||
jsonData.shopping_location_id = Grocy.Components.ShoppingLocationPicker.GetValue();
|
||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||
{
|
||||
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
||||
|
|
|
|||
|
|
@ -57,6 +57,13 @@ $app->group('', function(RouteCollectorProxy $group)
|
|||
$group->get('/quantityunitpluraltesting', '\Grocy\Controllers\StockController:QuantityUnitPluralFormTesting');
|
||||
}
|
||||
|
||||
// Stock price tracking
|
||||
if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
{
|
||||
$group->get('/shoppinglocations', '\Grocy\Controllers\StockController:ShoppingLocationsList');
|
||||
$group->get('/shoppinglocation/{shoppingLocationId}', '\Grocy\Controllers\StockController:ShoppingLocationEditForm');
|
||||
}
|
||||
|
||||
// Shopping list routes
|
||||
if (GROCY_FEATURE_FLAG_SHOPPINGLIST)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ class DemoDataGeneratorService extends BaseService
|
|||
INSERT INTO locations (name) VALUES ('{$this->__t_sql('Tinned food cupboard')}'); --5
|
||||
INSERT INTO locations (name, is_freezer) VALUES ('{$this->__t_sql('Freezer')}', 1); --6
|
||||
|
||||
INSERT INTO shopping_locations (name) VALUES ('{$this->__t_sql('DemoSupermarket1')}'); --1
|
||||
INSERT INTO shopping_locations (name) VALUES ('{$this->__t_sql('DemoSupermarket2')}'); --2
|
||||
|
||||
DELETE FROM quantity_units WHERE name = '{$this->__t_sql('Glass')}';
|
||||
INSERT INTO quantity_units (id, name, name_plural) VALUES (4, '{$this->__n_sql(1, 'Glass', 'Glasses')}', '{$this->__n_sql(2, 'Glass', 'Glasses')}'); --4
|
||||
DELETE FROM quantity_units WHERE name = '{$this->__t_sql('Tin')}';
|
||||
|
|
@ -186,80 +189,80 @@ class DemoDataGeneratorService extends BaseService
|
|||
$this->getDatabaseService()->ExecuteDbStatement($sql);
|
||||
|
||||
$stockService = new StockService();
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(21, 1500, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(21, 2500, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(23, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(23, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(24, 2, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(25, 2, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(2, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-30 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(21, 1500, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(21, 2500, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(23, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(23, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(24, 2, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(25, 2, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddProduct(2, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), null, $this->NextSupermarketId());
|
||||
$stockService->AddMissingProductsToShoppingList();
|
||||
$stockService->OpenProduct(3, 1);
|
||||
$stockService->OpenProduct(6, 1);
|
||||
|
|
@ -317,6 +320,23 @@ class DemoDataGeneratorService extends BaseService
|
|||
return mt_rand(2 * 100, 25 * 100) / 100;
|
||||
}
|
||||
|
||||
private $LastSupermarketId = 1;
|
||||
private function NextSupermarketId()
|
||||
{
|
||||
$returnValue = $this->LastSupermarketId;
|
||||
|
||||
if ($this->LastSupermarketId == 1)
|
||||
{
|
||||
$this->LastSupermarketId = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->LastSupermarketId = 1;
|
||||
}
|
||||
|
||||
return $returnValue;
|
||||
}
|
||||
|
||||
private function __t_sql(string $text)
|
||||
{
|
||||
$localizedText = $this->getLocalizationService()->__t($text, null);
|
||||
|
|
|
|||
|
|
@ -127,10 +127,13 @@ class StockService extends BaseService
|
|||
$averageShelfLifeDays = intval($this->getDatabase()->stock_average_product_shelf_life()->where('id', $productId)->fetch()->average_shelf_life_days);
|
||||
|
||||
$lastPrice = null;
|
||||
$defaultShoppingLocation = null;
|
||||
$lastShoppingLocation = null;
|
||||
$lastLogRow = $this->getDatabase()->stock_log()->where('product_id = :1 AND transaction_type IN (:2, :3) AND undone = 0', $productId, self::TRANSACTION_TYPE_PURCHASE, self::TRANSACTION_TYPE_INVENTORY_CORRECTION)->orderBy('row_created_timestamp', 'DESC')->limit(1)->fetch();
|
||||
if ($lastLogRow !== null && !empty($lastLogRow))
|
||||
{
|
||||
$lastPrice = $lastLogRow->price;
|
||||
$lastShoppingLocation = $lastLogRow->shopping_location_id;
|
||||
}
|
||||
|
||||
$consumeCount = $this->getDatabase()->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->where('undone = 0 AND spoiled = 0')->sum('amount') * -1;
|
||||
|
|
@ -152,6 +155,8 @@ class StockService extends BaseService
|
|||
'quantity_unit_purchase' => $quPurchase,
|
||||
'quantity_unit_stock' => $quStock,
|
||||
'last_price' => $lastPrice,
|
||||
'last_shopping_location_id' => $lastShoppingLocation,
|
||||
'default_shopping_location_id' => $product->shopping_location_id,
|
||||
'next_best_before_date' => $nextBestBeforeDate,
|
||||
'location' => $location,
|
||||
'average_shelf_life_days' => $averageShelfLifeDays,
|
||||
|
|
@ -168,12 +173,14 @@ class StockService extends BaseService
|
|||
}
|
||||
|
||||
$returnData = array();
|
||||
$shoppingLocations = $this->getDatabase()->shopping_locations();
|
||||
$rows = $this->getDatabase()->stock_log()->where('product_id = :1 AND transaction_type IN (:2, :3) AND undone = 0', $productId, self::TRANSACTION_TYPE_PURCHASE, self::TRANSACTION_TYPE_INVENTORY_CORRECTION)->whereNOT('price', null)->orderBy('purchased_date', 'DESC');
|
||||
foreach ($rows as $row)
|
||||
{
|
||||
$returnData[] = array(
|
||||
'date' => $row->purchased_date,
|
||||
'price' => $row->price
|
||||
'price' => $row->price,
|
||||
'shopping_location' => FindObjectInArrayByPropertyValue($shoppingLocations, 'id', $row->shopping_location_id),
|
||||
);
|
||||
}
|
||||
return $returnData;
|
||||
|
|
@ -210,7 +217,7 @@ class StockService extends BaseService
|
|||
return FindAllObjectsInArrayByPropertyValue($stockEntries, 'location_id', $locationId);
|
||||
}
|
||||
|
||||
public function AddProduct(int $productId, float $amount, $bestBeforeDate, $transactionType, $purchasedDate, $price, $locationId = null, &$transactionId = null)
|
||||
public function AddProduct(int $productId, float $amount, $bestBeforeDate, $transactionType, $purchasedDate, $price, $locationId = null, $shoppingLocationId = null, &$transactionId = null)
|
||||
{
|
||||
if (!$this->ProductExists($productId))
|
||||
{
|
||||
|
|
@ -266,7 +273,8 @@ class StockService extends BaseService
|
|||
'transaction_type' => $transactionType,
|
||||
'price' => $price,
|
||||
'location_id' => $locationId,
|
||||
'transaction_id' => $transactionId
|
||||
'transaction_id' => $transactionId,
|
||||
'shopping_location_id' => $shoppingLocationId,
|
||||
));
|
||||
$logRow->save();
|
||||
|
||||
|
|
@ -279,7 +287,8 @@ class StockService extends BaseService
|
|||
'purchased_date' => $purchasedDate,
|
||||
'stock_id' => $stockId,
|
||||
'price' => $price,
|
||||
'location_id' => $locationId
|
||||
'location_id' => $locationId,
|
||||
'shopping_location_id' => $shoppingLocationId,
|
||||
));
|
||||
$stockRow->save();
|
||||
|
||||
|
|
@ -589,7 +598,7 @@ class StockService extends BaseService
|
|||
return $this->getDatabase()->lastInsertId();
|
||||
}
|
||||
|
||||
public function EditStockEntry(int $stockRowId, int $amount, $bestBeforeDate, $locationId, $price, $open, $purchasedDate)
|
||||
public function EditStockEntry(int $stockRowId, int $amount, $bestBeforeDate, $locationId, $shoppingLocationId, $price, $open, $purchasedDate)
|
||||
{
|
||||
|
||||
$stockRow = $this->getDatabase()->stock()->where('id = :1', $stockRowId)->fetch();
|
||||
|
|
@ -611,6 +620,7 @@ class StockService extends BaseService
|
|||
'price' => $stockRow->price,
|
||||
'opened_date' => $stockRow->opened_date,
|
||||
'location_id' => $stockRow->location_id,
|
||||
'shopping_location_id' => $stockRow->shopping_location_id,
|
||||
'correlation_id' => $correlationId,
|
||||
'transaction_id' => $transactionId,
|
||||
'stock_row_id' => $stockRow->id
|
||||
|
|
@ -632,6 +642,7 @@ class StockService extends BaseService
|
|||
'price' => $price,
|
||||
'best_before_date' => $bestBeforeDate,
|
||||
'location_id' => $locationId,
|
||||
'shopping_location_id' => $shoppingLocationId,
|
||||
'opened_date' => $openedDate,
|
||||
'open' => $open,
|
||||
'purchased_date' => $purchasedDate
|
||||
|
|
@ -647,6 +658,7 @@ class StockService extends BaseService
|
|||
'price' => $price,
|
||||
'opened_date' => $stockRow->opened_date,
|
||||
'location_id' => $locationId,
|
||||
'shopping_location_id' => $shoppingLocationId,
|
||||
'correlation_id' => $correlationId,
|
||||
'transaction_id' => $transactionId,
|
||||
'stock_row_id' => $stockRow->id
|
||||
|
|
@ -656,7 +668,7 @@ class StockService extends BaseService
|
|||
return $this->getDatabase()->lastInsertId();
|
||||
}
|
||||
|
||||
public function InventoryProduct(int $productId, float $newAmount, $bestBeforeDate, $locationId = null, $price = null)
|
||||
public function InventoryProduct(int $productId, float $newAmount, $bestBeforeDate, $locationId = null, $price = null, $shoppingLocationId = null)
|
||||
{
|
||||
if (!$this->ProductExists($productId))
|
||||
{
|
||||
|
|
@ -670,6 +682,11 @@ class StockService extends BaseService
|
|||
$price = $productDetails->last_price;
|
||||
}
|
||||
|
||||
if ($shoppingLocationId === null)
|
||||
{
|
||||
$shoppingLocationId = $productDetails->last_shopping_location_id;
|
||||
}
|
||||
|
||||
// Tare weight handling
|
||||
// The given amount is the new total amount including the container weight (gross)
|
||||
// So assume that the amount in stock is the amount also including the container weight
|
||||
|
|
@ -691,7 +708,7 @@ class StockService extends BaseService
|
|||
$bookingAmount = $newAmount;
|
||||
}
|
||||
|
||||
return $this->AddProduct($productId, $bookingAmount, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION, date('Y-m-d'), $price, $locationId);
|
||||
return $this->AddProduct($productId, $bookingAmount, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION, date('Y-m-d'), $price, $locationId, $shoppingLocationId);
|
||||
}
|
||||
else if ($newAmount < $productDetails->stock_amount + $containerWeight)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
@php if(!isset($nextInputSelector)) { $nextInputSelector = false; } @endphp
|
||||
@php if(empty($additionalAttributes)) { $additionalAttributes = ''; } @endphp
|
||||
@php if(empty($additionalGroupCssClasses)) { $additionalGroupCssClasses = ''; } @endphp
|
||||
@php if(empty($activateNumberPad)) { $activateNumberPad = false; } @endphp
|
||||
|
||||
<div id="datetimepicker-wrapper" class="form-group {{ $additionalGroupCssClasses }}">
|
||||
<label for="{{ $id }}">{{ $__t($label) }}
|
||||
|
|
@ -24,7 +25,7 @@
|
|||
</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group date datetimepicker @if(!empty($additionalGroupCssClasses)){{ $additionalGroupCssClasses }}@endif" id="{{ $id }}" @if(!$noNameAttribute) name="{{ $id }}" @endif data-target-input="nearest">
|
||||
<input {!! $additionalAttributes !!} type="text" @if($isRequired) @if($isRequired) required @endif @endif class="form-control datetimepicker-input @if(!empty($additionalCssClasses)){{ $additionalCssClasses }}@endif"
|
||||
<input {!! $additionalAttributes !!} type="text" @if($activateNumberPad) inputmode="numeric" @endif @if($isRequired) @if($isRequired) required @endif @endif class="form-control datetimepicker-input @if(!empty($additionalCssClasses)){{ $additionalCssClasses }}@endif"
|
||||
data-target="#{{ $id }}" data-format="{{ $format }}"
|
||||
data-init-with-now="{{ BoolToString($initWithNow) }}"
|
||||
data-init-value="{{ $initialValue }}"
|
||||
|
|
|
|||
20
views/components/shoppinglocationpicker.blade.php
Normal file
20
views/components/shoppinglocationpicker.blade.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
@push('componentScripts')
|
||||
<script src="{{ $U('/viewjs/components/shoppinglocationpicker.js', true) }}?v={{ $version }}"></script>
|
||||
@endpush
|
||||
|
||||
@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp
|
||||
@php if(empty($prefillById)) { $prefillById = ''; } @endphp
|
||||
@php if(!isset($isRequired)) { $isRequired = false; } @endphp
|
||||
@php if(empty($hint)) { $hint = ''; } @endphp
|
||||
@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp
|
||||
|
||||
<div class="form-group" data-next-input-selector="{{ $nextInputSelector }}" data-prefill-by-name="{{ $prefillByName }}" data-prefill-by-id="{{ $prefillById }}">
|
||||
<label for="shopping_location_id">{{ $__t($label) }} <span id="{{ $hintId }}" class="small text-muted">{{ $hint }}</span></label>
|
||||
<select class="form-control shopping-location-combobox" id="shopping_location_id" name="shopping_location_id" @if($isRequired) required @endif>
|
||||
<option value=""></option>
|
||||
@foreach($shoppinglocations as $shoppinglocation)
|
||||
<option value="{{ $shoppinglocation->id }}">{{ $shoppinglocation->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<div class="invalid-feedback">{{ $__t('You have to select a store') }}</div>
|
||||
</div>
|
||||
|
|
@ -50,7 +50,8 @@
|
|||
'shortcutLabel' => 'Never expires',
|
||||
'earlierThanInfoLimit' => date('Y-m-d'),
|
||||
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'),
|
||||
'additionalGroupCssClasses' => $additionalGroupCssClasses
|
||||
'additionalGroupCssClasses' => $additionalGroupCssClasses,
|
||||
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
||||
))
|
||||
@php $additionalGroupCssClasses = ''; @endphp
|
||||
|
||||
|
|
@ -66,6 +67,11 @@
|
|||
'invalidFeedback' => $__t('The price cannot be lower than %s', '0'),
|
||||
'isRequired' => false
|
||||
))
|
||||
|
||||
@include('components.shoppinglocationpicker', array(
|
||||
'label' => 'Store',
|
||||
'shoppinglocations' => $shoppinglocations
|
||||
))
|
||||
@else
|
||||
<input type="hidden" name="price" id="price" value="0">
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -243,6 +243,14 @@
|
|||
</a>
|
||||
</li>
|
||||
@endif
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
<li data-nav-for-page="shoppinglocations" data-sub-menu-of="#top-nav-manager-master-data">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/shoppinglocations') }}">
|
||||
<i class="fas fa-shopping-cart"></i>
|
||||
<span class="nav-link-text">{{ $__t('Stores') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<li data-nav-for-page="quantityunits" data-sub-menu-of="#top-nav-manager-master-data">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/quantityunits') }}">
|
||||
<i class="fas fa-balance-scale"></i>
|
||||
|
|
|
|||
|
|
@ -88,6 +88,15 @@
|
|||
<input type="hidden" name="location_id" id="location_id" value="1">
|
||||
@endif
|
||||
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
@include('components.shoppinglocationpicker', array(
|
||||
'label' => 'Default store',
|
||||
'shoppinglocations' => $shoppinglocations
|
||||
))
|
||||
@else
|
||||
<input type="hidden" name="shopping_location_id" id="shopping_location_id" value="1">
|
||||
@endif
|
||||
|
||||
@php if($mode == 'edit') { $value = $product->min_stock_amount; } else { $value = 0; } @endphp
|
||||
@include('components.numberpicker', array(
|
||||
'id' => 'min_stock_amount',
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
'nextInputSelector' => '#best_before_date .datetimepicker-input'
|
||||
))
|
||||
|
||||
|
||||
@php
|
||||
$additionalGroupCssClasses = '';
|
||||
if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||
|
|
@ -51,7 +52,8 @@
|
|||
'shortcutLabel' => 'Never expires',
|
||||
'earlierThanInfoLimit' => date('Y-m-d'),
|
||||
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'),
|
||||
'additionalGroupCssClasses' => $additionalGroupCssClasses
|
||||
'additionalGroupCssClasses' => $additionalGroupCssClasses,
|
||||
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
||||
))
|
||||
@php $additionalGroupCssClasses = ''; @endphp
|
||||
|
||||
|
|
@ -84,6 +86,10 @@
|
|||
<input class="form-check-input" type="radio" name="price-type" id="price-type-total-price" value="total-price">
|
||||
<label class="form-check-label" for="price-type-total-price">{{ $__t('Total price') }}</label>
|
||||
</div>
|
||||
@include('components.shoppinglocationpicker', array(
|
||||
'label' => 'Store',
|
||||
'shoppinglocations' => $shoppinglocations
|
||||
))
|
||||
@else
|
||||
<input type="hidden" name="price" id="price" value="0">
|
||||
@endif
|
||||
|
|
|
|||
45
views/shoppinglocationform.blade.php
Normal file
45
views/shoppinglocationform.blade.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
@extends('layout.default')
|
||||
|
||||
@if($mode == 'edit')
|
||||
@section('title', $__t('Edit store'))
|
||||
@else
|
||||
@section('title', $__t('Create store'))
|
||||
@endif
|
||||
|
||||
@section('viewJsName', 'shoppinglocationform')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-xs-12">
|
||||
<h1>@yield('title')</h1>
|
||||
|
||||
<script>Grocy.EditMode = '{{ $mode }}';</script>
|
||||
|
||||
@if($mode == 'edit')
|
||||
<script>Grocy.EditObjectId = {{ $shoppinglocation->id }};</script>
|
||||
@endif
|
||||
|
||||
<form id="shoppinglocation-form" novalidate>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">{{ $__t('Name') }}</label>
|
||||
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $shoppinglocation->name }}@endif">
|
||||
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">{{ $__t('Description') }}</label>
|
||||
<textarea class="form-control" rows="2" id="description" name="description">@if($mode == 'edit'){{ $shoppinglocation->description }}@endif</textarea>
|
||||
</div>
|
||||
|
||||
@include('components.userfieldsform', array(
|
||||
'userfields' => $userfields,
|
||||
'entity' => 'shopping_locations'
|
||||
))
|
||||
|
||||
<button id="save-shopping-location-button" class="btn btn-success">{{ $__t('Save') }}</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
73
views/shoppinglocations.blade.php
Normal file
73
views/shoppinglocations.blade.php
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
@extends('layout.default')
|
||||
|
||||
@section('title', $__t('Stores'))
|
||||
@section('activeNav', 'shoppinglocations')
|
||||
@section('viewJsName', 'shoppinglocations')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1>
|
||||
@yield('title')
|
||||
<a class="btn btn-outline-dark" href="{{ $U('/shoppinglocation/new') }}">
|
||||
<i class="fas fa-plus"></i> {{ $__t('Add') }}
|
||||
</a>
|
||||
<a class="btn btn-outline-secondary" href="{{ $U('/userfields?entity=shoppinglocations') }}">
|
||||
<i class="fas fa-sliders-h"></i> {{ $__t('Configure userfields') }}
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-xs-12 col-md-6 col-xl-3">
|
||||
<label for="search">{{ $__t('Search') }}</label> <i class="fas fa-search"></i>
|
||||
<input type="text" class="form-control" id="search">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<table id="shoppinglocations-table" class="table table-sm table-striped dt-responsive">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-right"></th>
|
||||
<th>{{ $__t('Name') }}</th>
|
||||
<th>{{ $__t('Description') }}</th>
|
||||
|
||||
@include('components.userfields_thead', array(
|
||||
'userfields' => $userfields
|
||||
))
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="d-none">
|
||||
@foreach($shoppinglocations as $shoppinglocation)
|
||||
<tr>
|
||||
<td class="fit-content border-right">
|
||||
<a class="btn btn-info btn-sm" href="{{ $U('/shoppinglocation/') }}{{ $shoppinglocation->id }}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<a class="btn btn-danger btn-sm shoppinglocation-delete-button" href="#" data-shoppinglocation-id="{{ $shoppinglocation->id }}" data-shoppinglocation-name="{{ $shoppinglocation->name }}">
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ $shoppinglocation->name }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $shoppinglocation->description }}
|
||||
</td>
|
||||
|
||||
@include('components.userfields_tbody', array(
|
||||
'userfields' => $userfields,
|
||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $shoppinglocation->id)
|
||||
))
|
||||
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
|
|
@ -35,7 +35,10 @@
|
|||
<th>{{ $__t('Amount') }}</th>
|
||||
<th>{{ $__t('Best before date') }}</th>
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)<th>{{ $__t('Location') }}</th>@endif
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)<th>{{ $__t('Price') }}</th>@endif
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
<th>{{ $__t('Store') }}</th>
|
||||
<th>{{ $__t('Price') }}</th>
|
||||
@endif
|
||||
<th>{{ $__t('Purchased date') }}</th>
|
||||
|
||||
@include('components.userfields_thead', array(
|
||||
|
|
@ -142,6 +145,11 @@
|
|||
</td>
|
||||
@endif
|
||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||
<td id="stock-{{ $stockEntry->id }}-shopping-location" data-shopping-location-id="{{ $stockEntry->shopping_location_id }}">
|
||||
@if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id) !== null)
|
||||
{{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id)->name }}
|
||||
@endif
|
||||
</td>
|
||||
<td id="stock-{{ $stockEntry->id }}-price" class="locale-number locale-number-currency" data-price-id="{{ $stockEntry->price }}">
|
||||
{{ $stockEntry->price }}
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@
|
|||
'shortcutLabel' => 'Never expires',
|
||||
'earlierThanInfoLimit' => date('Y-m-d'),
|
||||
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'),
|
||||
'additionalGroupCssClasses' => $additionalGroupCssClasses
|
||||
'additionalGroupCssClasses' => $additionalGroupCssClasses,
|
||||
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
||||
))
|
||||
@php $additionalGroupCssClasses = ''; @endphp
|
||||
|
||||
|
|
@ -65,6 +66,11 @@
|
|||
'invalidFeedback' => $__t('The price cannot be lower than %s', '0'),
|
||||
'isRequired' => false
|
||||
))
|
||||
@include('components.shoppinglocationpicker', array(
|
||||
'label' => 'Store',
|
||||
'shoppinglocations' => $shoppinglocations,
|
||||
'prefillById' => $stockEntry->shopping_location_id
|
||||
))
|
||||
@else
|
||||
<input type="hidden" name="price" id="price" value="0">
|
||||
@endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user