mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 09:39:57 +00:00
Qu factor purchase to stock & Product Barcode Details (#801)
* Puchase add qu_factor_to_stock * qu_factor_purchase_to_stock for stock edit * product barcodes with QU and Stores * remove product barcode tags * migrations/0103 add value and factor_puchase_amount to stock_current and stock_current_location_content * Remove unused method * StockService#GetProductDetails: include stock_value * productcard: include stock_value * Add Purchase Factor to Stock Overview * update demo data with stock qu_factor_purchase_to_stock * recipes_pos_resolved update * avg_price and oldest_price in product details * add average price to product card * hint for recipe costs not included if not in stock * Round value and factor_purchas_amount. Include currency for stock value * Add factor_purchase_amount to product card stock amount * Allow editing qu_factor_purchase_to_stock for stock entries * fix update qu_factor_purchase_to_stock for Transfers * Add barcode to existing product update to add to product_barcodes table * Add barcode to new product workflow update to add to product_barcodes table * *** Price now saved as 1 QU to stock in stock tables *** * remove column product barcode and use product_barcodes * Allow products to be deactivated instead of deleted * Embedded barcode and qu-conversion with page reload on change * Save current product barcode into new product_barcodes table * Embedded popup for product group add/edit * barcode scanner added to product barcodes input * Edit product qu_stock is unavailable after first purchase * StockOverview: Filters break when columns are reordered so for now just disable colReorder * view stockoverview.blade: display product_group column * Review Co-authored-by: Bernd Bestel <bernd@berrnd.de>
This commit is contained in:
parent
d1e395b45e
commit
e8845fe2e8
@ -23,6 +23,18 @@ class StockApiController extends BaseApiController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function ProductBarcodeDetails(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return $this->ApiResponse($response, $this->getDatabase()->product_barcodes()->where('barcode = :1', $args['barcode'])->fetch());
|
||||||
|
}
|
||||||
|
catch (\Exception $ex)
|
||||||
|
{
|
||||||
|
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function ProductDetailsByBarcode(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
public function ProductDetailsByBarcode(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -88,13 +100,19 @@ class StockApiController extends BaseApiController
|
|||||||
$shoppingLocationId = $requestBody['shopping_location_id'];
|
$shoppingLocationId = $requestBody['shopping_location_id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$quFactorPurchaseToStock = null;
|
||||||
|
if (array_key_exists('qu_factor_purchase_to_stock', $requestBody) && is_numeric($requestBody['qu_factor_purchase_to_stock']))
|
||||||
|
{
|
||||||
|
$quFactorPurchaseToStock = $requestBody['qu_factor_purchase_to_stock'];
|
||||||
|
}
|
||||||
|
|
||||||
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
|
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
|
||||||
if (array_key_exists('transaction_type', $requestBody) && !empty($requestBody['transactiontype']))
|
if (array_key_exists('transaction_type', $requestBody) && !empty($requestBody['transactiontype']))
|
||||||
{
|
{
|
||||||
$transactionType = $requestBody['transactiontype'];
|
$transactionType = $requestBody['transactiontype'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$bookingId = $this->getStockService()->AddProduct($args['productId'], $requestBody['amount'], $bestBeforeDate, $transactionType, date('Y-m-d'), $price, $locationId, $shoppingLocationId);
|
$bookingId = $this->getStockService()->AddProduct($args['productId'], $requestBody['amount'], $bestBeforeDate, $transactionType, date('Y-m-d'), $price, $quFactorPurchaseToStock, $locationId, $shoppingLocationId);
|
||||||
return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId));
|
return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId));
|
||||||
}
|
}
|
||||||
catch (\Exception $ex)
|
catch (\Exception $ex)
|
||||||
@ -156,7 +174,7 @@ class StockApiController extends BaseApiController
|
|||||||
$shoppingLocationId = $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']);
|
$bookingId = $this->getStockService()->EditStockEntry($args['entryId'], $requestBody['amount'], $bestBeforeDate, $locationId, $shoppingLocationId, $price, $requestBody['open'], $requestBody['purchased_date'], $requestBody['qu_factor_purchase_to_stock']);
|
||||||
return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId));
|
return $this->ApiResponse($response, $this->getDatabase()->stock_log($bookingId));
|
||||||
}
|
}
|
||||||
catch (\Exception $ex)
|
catch (\Exception $ex)
|
||||||
|
@ -16,7 +16,7 @@ class StockController extends BaseController
|
|||||||
$nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_expring_soon_days'];
|
$nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_expring_soon_days'];
|
||||||
|
|
||||||
return $this->renderPage($response, 'stockoverview', [
|
return $this->renderPage($response, 'stockoverview', [
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||||
'currentStock' => $this->getStockService()->GetCurrentStock(true),
|
'currentStock' => $this->getStockService()->GetCurrentStock(true),
|
||||||
@ -36,7 +36,7 @@ class StockController extends BaseController
|
|||||||
$nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_expring_soon_days'];
|
$nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_expring_soon_days'];
|
||||||
|
|
||||||
return $this->renderPage($response, 'stockentries', [
|
return $this->renderPage($response, 'stockentries', [
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||||
@ -50,8 +50,12 @@ class StockController extends BaseController
|
|||||||
|
|
||||||
public function Purchase(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
public function Purchase(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
|
$sql = 'select group_concat(barcode) barcodes, product_id from product_barcodes group by product_id';
|
||||||
|
$productBarcodes = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||||
|
|
||||||
return $this->renderPage($response, 'purchase', [
|
return $this->renderPage($response, 'purchase', [
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
|
'barcodes' => $productBarcodes,
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
||||||
]);
|
]);
|
||||||
@ -59,8 +63,12 @@ class StockController extends BaseController
|
|||||||
|
|
||||||
public function Consume(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
public function Consume(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
|
$sql = 'select group_concat(barcode) barcodes, product_id from product_barcodes group by product_id';
|
||||||
|
$productBarcodes = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||||
|
|
||||||
return $this->renderPage($response, 'consume', [
|
return $this->renderPage($response, 'consume', [
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
|
'barcodes' => $productBarcodes,
|
||||||
'recipes' => $this->getDatabase()->recipes()->orderBy('name'),
|
'recipes' => $this->getDatabase()->recipes()->orderBy('name'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
||||||
]);
|
]);
|
||||||
@ -68,8 +76,12 @@ class StockController extends BaseController
|
|||||||
|
|
||||||
public function Transfer(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
public function Transfer(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
|
$sql = 'select group_concat(barcode) barcodes, product_id from product_barcodes group by product_id';
|
||||||
|
$productBarcodes = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||||
|
|
||||||
return $this->renderPage($response, 'transfer', [
|
return $this->renderPage($response, 'transfer', [
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
|
'barcodes' => $productBarcodes,
|
||||||
'recipes' => $this->getDatabase()->recipes()->orderBy('name'),
|
'recipes' => $this->getDatabase()->recipes()->orderBy('name'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
||||||
]);
|
]);
|
||||||
@ -77,8 +89,12 @@ class StockController extends BaseController
|
|||||||
|
|
||||||
public function Inventory(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
public function Inventory(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
|
$sql = 'select group_concat(barcode) barcodes, product_id from product_barcodes group by product_id';
|
||||||
|
$productBarcodes = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||||
|
|
||||||
return $this->renderPage($response, 'inventory', [
|
return $this->renderPage($response, 'inventory', [
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
|
'barcodes' => $productBarcodes,
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
||||||
]);
|
]);
|
||||||
@ -88,7 +104,7 @@ class StockController extends BaseController
|
|||||||
{
|
{
|
||||||
return $this->renderPage($response, 'stockentryform', [
|
return $this->renderPage($response, 'stockentryform', [
|
||||||
'stockEntry' => $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch(),
|
'stockEntry' => $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch(),
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
'locations' => $this->getDatabase()->locations()->orderBy('name')
|
||||||
]);
|
]);
|
||||||
@ -104,7 +120,7 @@ class StockController extends BaseController
|
|||||||
|
|
||||||
return $this->renderPage($response, 'shoppinglist', [
|
return $this->renderPage($response, 'shoppinglist', [
|
||||||
'listItems' => $this->getDatabase()->shopping_list()->where('shopping_list_id = :1', $listId),
|
'listItems' => $this->getDatabase()->shopping_list()->where('shopping_list_id = :1', $listId),
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
||||||
'missingProducts' => $this->getStockService()->GetMissingProducts(),
|
'missingProducts' => $this->getStockService()->GetMissingProducts(),
|
||||||
'productGroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
'productGroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
||||||
@ -158,7 +174,7 @@ class StockController extends BaseController
|
|||||||
{
|
{
|
||||||
return $this->renderPage($response, 'productgroups', [
|
return $this->renderPage($response, 'productgroups', [
|
||||||
'productGroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
'productGroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('product_groups'),
|
'userfields' => $this->getUserfieldsService()->GetFields('product_groups'),
|
||||||
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('product_groups')
|
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('product_groups')
|
||||||
]);
|
]);
|
||||||
@ -179,11 +195,12 @@ class StockController extends BaseController
|
|||||||
{
|
{
|
||||||
return $this->renderPage($response, 'productform', [
|
return $this->renderPage($response, 'productform', [
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||||
|
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||||
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||||
'products' => $this->getDatabase()->products()->where('parent_product_id IS NULL')->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('parent_product_id IS NULL and active = 1')->orderBy('name'),
|
||||||
'isSubProductOfOthers' => false,
|
'isSubProductOfOthers' => false,
|
||||||
'mode' => 'create'
|
'mode' => 'create'
|
||||||
]);
|
]);
|
||||||
@ -195,11 +212,12 @@ class StockController extends BaseController
|
|||||||
return $this->renderPage($response, 'productform', [
|
return $this->renderPage($response, 'productform', [
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||||
|
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name'),
|
||||||
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name'),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||||
'products' => $this->getDatabase()->products()->where('id != :1 AND parent_product_id IS NULL', $product->id)->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('id != :1 AND parent_product_id IS NULL and active = 1', $product->id)->orderBy('name'),
|
||||||
'isSubProductOfOthers' => $this->getDatabase()->products()->where('parent_product_id = :1', $product->id)->count() !== 0,
|
'isSubProductOfOthers' => $this->getDatabase()->products()->where('parent_product_id = :1', $product->id)->count() !== 0,
|
||||||
'mode' => 'edit',
|
'mode' => 'edit',
|
||||||
'quConversions' => $this->getDatabase()->quantity_unit_conversions()
|
'quConversions' => $this->getDatabase()->quantity_unit_conversions()
|
||||||
@ -296,7 +314,7 @@ class StockController extends BaseController
|
|||||||
if ($args['itemId'] == 'new')
|
if ($args['itemId'] == 'new')
|
||||||
{
|
{
|
||||||
return $this->renderPage($response, 'shoppinglistitemform', [
|
return $this->renderPage($response, 'shoppinglistitemform', [
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name'),
|
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name'),
|
||||||
'mode' => 'create'
|
'mode' => 'create'
|
||||||
]);
|
]);
|
||||||
@ -305,7 +323,7 @@ class StockController extends BaseController
|
|||||||
{
|
{
|
||||||
return $this->renderPage($response, 'shoppinglistitemform', [
|
return $this->renderPage($response, 'shoppinglistitemform', [
|
||||||
'listItem' => $this->getDatabase()->shopping_list($args['itemId']),
|
'listItem' => $this->getDatabase()->shopping_list($args['itemId']),
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name'),
|
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name'),
|
||||||
'mode' => 'edit'
|
'mode' => 'edit'
|
||||||
]);
|
]);
|
||||||
@ -339,7 +357,7 @@ class StockController extends BaseController
|
|||||||
return $this->renderPage($response, 'stockjournal', [
|
return $this->renderPage($response, 'stockjournal', [
|
||||||
'stockLog' => $this->getDatabase()->stock_log()->orderBy('row_created_timestamp', 'DESC'),
|
'stockLog' => $this->getDatabase()->stock_log()->orderBy('row_created_timestamp', 'DESC'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name')
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -347,13 +365,41 @@ class StockController extends BaseController
|
|||||||
public function LocationContentSheet(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
public function LocationContentSheet(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
return $this->renderPage($response, 'locationcontentsheet', [
|
return $this->renderPage($response, 'locationcontentsheet', [
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||||
'currentStockLocationContent' => $this->getStockService()->GetCurrentStockLocationContent()
|
'currentStockLocationContent' => $this->getStockService()->GetCurrentStockLocationContent()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function ProductBarcodesEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
|
{
|
||||||
|
$product = null;
|
||||||
|
if (isset($request->getQueryParams()['product']))
|
||||||
|
{
|
||||||
|
$product = $this->getDatabase()->products($request->getQueryParams()['product']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($args['productBarcodeId'] == 'new')
|
||||||
|
{
|
||||||
|
return $this->renderPage($response, 'productbarcodesform', [
|
||||||
|
'mode' => 'create',
|
||||||
|
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
||||||
|
'product' => $product,
|
||||||
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $this->renderPage($response, 'productbarcodesform', [
|
||||||
|
'mode' => 'edit',
|
||||||
|
'barcode' => $this->getDatabase()->product_barcodes($args['productBarcodeId']),
|
||||||
|
'product' => $product,
|
||||||
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function QuantityUnitConversionEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
public function QuantityUnitConversionEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
$product = null;
|
$product = null;
|
||||||
|
@ -2703,6 +2703,57 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/productbarcodedetails/{barcode}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Executes a product barcode details lookoup via the configured plugin with the given barcode",
|
||||||
|
"tags": [
|
||||||
|
"Product"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "barcode",
|
||||||
|
"required": true,
|
||||||
|
"description": "The barcode to lookup up",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "add",
|
||||||
|
"required": false,
|
||||||
|
"description": "When true, the product is added to the database on a successful lookup and the new product id is in included in the response",
|
||||||
|
"schema": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "An ProductBarcodeDetails object or null, when nothing was found for the given barcode",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProductBarcodeDetailsResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "The operation was not successful (possible errors are: Plugin error)",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/GenericErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/recipes/{recipeId}/add-not-fulfilled-products-to-shoppinglist": {
|
"/recipes/{recipeId}/add-not-fulfilled-products-to-shoppinglist": {
|
||||||
"post": {
|
"post": {
|
||||||
"summary": "Adds all missing products for the given recipe to the shopping list",
|
"summary": "Adds all missing products for the given recipe to the shopping list",
|
||||||
@ -3374,6 +3425,7 @@
|
|||||||
"enum": [
|
"enum": [
|
||||||
"products",
|
"products",
|
||||||
"chores",
|
"chores",
|
||||||
|
"product_barcodes",
|
||||||
"batteries",
|
"batteries",
|
||||||
"locations",
|
"locations",
|
||||||
"quantity_units",
|
"quantity_units",
|
||||||
@ -3399,6 +3451,7 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
"products",
|
"products",
|
||||||
|
"product_barcodes",
|
||||||
"chores",
|
"chores",
|
||||||
"batteries",
|
"batteries",
|
||||||
"locations",
|
"locations",
|
||||||
@ -3748,6 +3801,9 @@
|
|||||||
"product": {
|
"product": {
|
||||||
"$ref": "#/components/schemas/Product"
|
"$ref": "#/components/schemas/Product"
|
||||||
},
|
},
|
||||||
|
"product_barcodes": {
|
||||||
|
"$ref": "#/components/schemas/ProductBarcodeDetailsResponse"
|
||||||
|
},
|
||||||
"quantity_unit_purchase": {
|
"quantity_unit_purchase": {
|
||||||
"$ref": "#/components/schemas/QuantityUnit"
|
"$ref": "#/components/schemas/QuantityUnit"
|
||||||
},
|
},
|
||||||
@ -3776,6 +3832,14 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"format": "number"
|
"format": "number"
|
||||||
},
|
},
|
||||||
|
"avg_price": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "number"
|
||||||
|
},
|
||||||
|
"oldest_price": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "number"
|
||||||
|
},
|
||||||
"last_shopping_location_id": {
|
"last_shopping_location_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -3813,6 +3877,15 @@
|
|||||||
"not_check_stock_fulfillment_for_recipes": "0",
|
"not_check_stock_fulfillment_for_recipes": "0",
|
||||||
"last_shopping_location_id": null
|
"last_shopping_location_id": null
|
||||||
},
|
},
|
||||||
|
"product_barcodes": [
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"product_id": "13",
|
||||||
|
"barcode": "01321230213",
|
||||||
|
"qu_factor_purchase_to_stock": "10.0",
|
||||||
|
"shopping_location_id": "2"
|
||||||
|
}
|
||||||
|
],
|
||||||
"last_purchased": null,
|
"last_purchased": null,
|
||||||
"last_used": null,
|
"last_used": null,
|
||||||
"stock_amount": "2",
|
"stock_amount": "2",
|
||||||
@ -3834,6 +3907,8 @@
|
|||||||
"plural_forms": null
|
"plural_forms": null
|
||||||
},
|
},
|
||||||
"last_price": null,
|
"last_price": null,
|
||||||
|
"avg_price": null,
|
||||||
|
"oldest_price": null,
|
||||||
"last_shopping_location_id": null,
|
"last_shopping_location_id": null,
|
||||||
"next_best_before_date": "2019-07-07",
|
"next_best_before_date": "2019-07-07",
|
||||||
"location": {
|
"location": {
|
||||||
@ -3862,6 +3937,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ProductBarcodeDetailsResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"product_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"barcode": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"qu_factor_purchase_to_stock": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "number"
|
||||||
|
},
|
||||||
|
"barcode": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Can contain multiple barcodes separated by comma"
|
||||||
|
},
|
||||||
|
"shopping_location_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"ExternalBarcodeLookupResponse": {
|
"ExternalBarcodeLookupResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -1810,3 +1810,33 @@ msgstr ""
|
|||||||
|
|
||||||
msgid "Save & return to recipes"
|
msgid "Save & return to recipes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Stock value"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Average price"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Active"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Barcodes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Barcode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Create Barcode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Barcode for product"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Edit Barcode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Not enough in stock (not included in costs), %s ingredient missing"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Based on the prices of the default consume rule which is \"First expiring first, then first in first out\""
|
||||||
|
msgstr ""
|
||||||
|
171
migrations/0103.sql
Normal file
171
migrations/0103.sql
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
ALTER TABLE stock_log
|
||||||
|
ADD qu_factor_purchase_to_stock REAL NOT NULL DEFAULT 1.0;
|
||||||
|
|
||||||
|
ALTER TABLE stock
|
||||||
|
ADD qu_factor_purchase_to_stock REAL NOT NULL DEFAULT 1.0;
|
||||||
|
|
||||||
|
UPDATE stock
|
||||||
|
SET qu_factor_purchase_to_stock = (SELECT qu_factor_purchase_to_stock FROM products WHERE product_id = id);
|
||||||
|
|
||||||
|
UPDATE stock_log
|
||||||
|
SET qu_factor_purchase_to_stock = (SELECT qu_factor_purchase_to_stock FROM products WHERE product_id = id);
|
||||||
|
|
||||||
|
--Price is now going forward to be saved as 1 QU Stock
|
||||||
|
UPDATE stock
|
||||||
|
SET price = ROUND(price / qu_factor_purchase_to_stock, 2);
|
||||||
|
|
||||||
|
UPDATE stock_log
|
||||||
|
SET price = ROUND(price / qu_factor_purchase_to_stock, 2);
|
||||||
|
|
||||||
|
CREATE TABLE product_barcodes (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
product_id INT NOT NULL,
|
||||||
|
barcode TEXT NOT NULL UNIQUE,
|
||||||
|
qu_factor_purchase_to_stock REAL NOT NULL DEFAULT 1,
|
||||||
|
shopping_location_id INTEGER,
|
||||||
|
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Convert product table to new product_barcodes table
|
||||||
|
INSERT INTO product_barcodes
|
||||||
|
(product_id, barcode, qu_factor_purchase_to_stock, shopping_location_id)
|
||||||
|
WITH barcodes_splitted(id, barcode, str, qu_factor_purchase_to_stock, shopping_location_id) AS (
|
||||||
|
SELECT id as product_id, '', barcode || ',', qu_factor_purchase_to_stock, shopping_location_id
|
||||||
|
FROM products
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
id as product_id,
|
||||||
|
SUBSTR(str, 0, instr(str, ',')),
|
||||||
|
SUBSTR(str, instr(str, ',') + 1),
|
||||||
|
qu_factor_purchase_to_stock,
|
||||||
|
shopping_location_id
|
||||||
|
FROM barcodes_splitted
|
||||||
|
WHERE str != ''
|
||||||
|
)
|
||||||
|
SELECT id as product_id, barcode, qu_factor_purchase_to_stock, shopping_location_id
|
||||||
|
FROM barcodes_splitted
|
||||||
|
WHERE barcode != '';
|
||||||
|
|
||||||
|
PRAGMA legacy_alter_table = ON;
|
||||||
|
ALTER TABLE products RENAME TO products_old;
|
||||||
|
|
||||||
|
-- Remove barcode column
|
||||||
|
-- Reorder columns
|
||||||
|
CREATE TABLE products (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
description TEXT,
|
||||||
|
product_group_id INTEGER,
|
||||||
|
active TINYINT NOT NULL DEFAULT 1,
|
||||||
|
location_id INTEGER NOT NULL,
|
||||||
|
shopping_location_id INTEGER,
|
||||||
|
qu_id_purchase INTEGER NOT NULL,
|
||||||
|
qu_id_stock INTEGER NOT NULL,
|
||||||
|
qu_factor_purchase_to_stock REAL NOT NULL,
|
||||||
|
min_stock_amount INTEGER NOT NULL DEFAULT 0,
|
||||||
|
default_best_before_days INTEGER NOT NULL DEFAULT 0,
|
||||||
|
default_best_before_days_after_open INTEGER NOT NULL DEFAULT 0,
|
||||||
|
default_best_before_days_after_freezing INTEGER NOT NULL DEFAULT 0,
|
||||||
|
default_best_before_days_after_thawing INTEGER NOT NULL DEFAULT 0,
|
||||||
|
picture_file_name TEXT,
|
||||||
|
allow_partial_units_in_stock TINYINT NOT NULL DEFAULT 0,
|
||||||
|
enable_tare_weight_handling TINYINT NOT NULL DEFAULT 0,
|
||||||
|
tare_weight REAL NOT NULL DEFAULT 0,
|
||||||
|
not_check_stock_fulfillment_for_recipes TINYINT DEFAULT 0,
|
||||||
|
parent_product_id INT,
|
||||||
|
calories INTEGER,
|
||||||
|
cumulate_min_stock_amount_of_sub_products TINYINT DEFAULT 0,
|
||||||
|
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO products
|
||||||
|
(id, name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount, default_best_before_days, row_created_timestamp, product_group_id, picture_file_name, default_best_before_days_after_open, allow_partial_units_in_stock, enable_tare_weight_handling, tare_weight, not_check_stock_fulfillment_for_recipes, parent_product_id, calories, cumulate_min_stock_amount_of_sub_products, default_best_before_days_after_freezing, default_best_before_days_after_thawing, shopping_location_id)
|
||||||
|
SELECT id, name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount,default_best_before_days, row_created_timestamp, product_group_id, picture_file_name, default_best_before_days_after_open, allow_partial_units_in_stock, enable_tare_weight_handling, tare_weight, not_check_stock_fulfillment_for_recipes, parent_product_id, calories, cumulate_min_stock_amount_of_sub_products, default_best_before_days_after_freezing, default_best_before_days_after_thawing, shopping_location_id
|
||||||
|
FROM products_old;
|
||||||
|
|
||||||
|
DROP TABLE products_old;
|
||||||
|
|
||||||
|
DROP VIEW stock_current_location_content;
|
||||||
|
CREATE VIEW stock_current_location_content
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
IFNULL(s.location_id, p.location_id) AS location_id,
|
||||||
|
s.product_id,
|
||||||
|
SUM(s.amount) AS amount,
|
||||||
|
ROUND(SUM(s.amount / s.qu_factor_purchase_to_stock),2) as factor_purchase_amount,
|
||||||
|
ROUND(SUM(IFNULL(s.price, 0) * s.amount), 2) AS value,
|
||||||
|
MIN(s.best_before_date) AS best_before_date,
|
||||||
|
IFNULL((SELECT SUM(amount) FROM stock WHERE product_id = s.product_id AND location_id = s.location_id AND open = 1), 0) AS amount_opened
|
||||||
|
FROM stock s
|
||||||
|
JOIN products p
|
||||||
|
ON s.product_id = p.id
|
||||||
|
AND p.active = 1
|
||||||
|
GROUP BY IFNULL(s.location_id, p.location_id), s.product_id;
|
||||||
|
|
||||||
|
DROP VIEW stock_current;
|
||||||
|
CREATE VIEW stock_current
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
pr.parent_product_id AS product_id,
|
||||||
|
IFNULL((SELECT SUM(amount) FROM stock WHERE product_id = pr.parent_product_id), 0) AS amount,
|
||||||
|
IFNULL(ROUND((SELECT SUM(amount / qu_factor_purchase_to_stock) FROM stock WHERE product_id = pr.parent_product_id), 2), 0) as factor_purchase_amount,
|
||||||
|
SUM(s.amount) * IFNULL(qucr.factor, 1) AS amount_aggregated,
|
||||||
|
IFNULL(ROUND((SELECT SUM(IFNULL(price,0) * amount) FROM stock WHERE product_id = pr.parent_product_id), 2), 0) AS value,
|
||||||
|
MIN(s.best_before_date) AS best_before_date,
|
||||||
|
IFNULL((SELECT SUM(amount) FROM stock WHERE product_id = pr.parent_product_id AND open = 1), 0) AS amount_opened,
|
||||||
|
IFNULL((SELECT SUM(amount) FROM stock WHERE product_id IN (SELECT sub_product_id FROM products_resolved WHERE parent_product_id = pr.parent_product_id) AND open = 1), 0) * IFNULL(qucr.factor, 1) AS amount_opened_aggregated,
|
||||||
|
CASE WHEN p_sub.parent_product_id IS NOT NULL THEN 1 ELSE 0 END AS is_aggregated_amount
|
||||||
|
FROM products_resolved pr
|
||||||
|
JOIN stock s
|
||||||
|
ON pr.sub_product_id = s.product_id
|
||||||
|
JOIN products p_parent
|
||||||
|
ON pr.parent_product_id = p_parent.id
|
||||||
|
AND p_parent.active = 1
|
||||||
|
JOIN products p_sub
|
||||||
|
ON pr.sub_product_id = p_sub.id
|
||||||
|
AND p_sub.active = 1
|
||||||
|
LEFT JOIN quantity_unit_conversions_resolved qucr
|
||||||
|
ON pr.sub_product_id = qucr.product_id
|
||||||
|
AND p_sub.qu_id_stock = qucr.from_qu_id
|
||||||
|
AND p_parent.qu_id_stock = qucr.to_qu_id
|
||||||
|
GROUP BY pr.parent_product_id
|
||||||
|
HAVING SUM(s.amount) > 0
|
||||||
|
|
||||||
|
UNION
|
||||||
|
|
||||||
|
-- This is the same as above but sub products not rolled up (no QU conversion and column is_aggregated_amount = 0 here)
|
||||||
|
SELECT
|
||||||
|
pr.sub_product_id AS product_id,
|
||||||
|
SUM(s.amount) AS amount,
|
||||||
|
ROUND(SUM(s.amount / s.qu_factor_purchase_to_stock), 2) as factor_purchase_amount,
|
||||||
|
SUM(s.amount) AS amount_aggregated,
|
||||||
|
ROUND(SUM(IFNULL(s.price, 0) * s.amount), 2) AS value,
|
||||||
|
MIN(s.best_before_date) AS best_before_date,
|
||||||
|
IFNULL((SELECT SUM(amount) FROM stock WHERE product_id = s.product_id AND open = 1), 0) AS amount_opened,
|
||||||
|
IFNULL((SELECT SUM(amount) FROM stock WHERE product_id = s.product_id AND open = 1), 0) AS amount_opened_aggregated,
|
||||||
|
0 AS is_aggregated_amount
|
||||||
|
FROM products_resolved pr
|
||||||
|
JOIN stock s
|
||||||
|
ON pr.sub_product_id = s.product_id
|
||||||
|
WHERE pr.parent_product_id != pr.sub_product_id
|
||||||
|
GROUP BY pr.sub_product_id
|
||||||
|
HAVING SUM(s.amount) > 0;
|
||||||
|
|
||||||
|
DROP VIEW products_resolved;
|
||||||
|
CREATE VIEW products_resolved AS
|
||||||
|
SELECT
|
||||||
|
p.parent_product_id parent_product_id,
|
||||||
|
p.id as sub_product_id
|
||||||
|
FROM products p
|
||||||
|
WHERE p.parent_product_id IS NOT NULL
|
||||||
|
AND p.active = 1
|
||||||
|
|
||||||
|
UNION
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
p.id parent_product_id,
|
||||||
|
p.id as sub_product_id
|
||||||
|
FROM products p
|
||||||
|
WHERE p.parent_product_id IS NULL
|
||||||
|
AND p.active = 1;
|
185
migrations/0104.sql
Normal file
185
migrations/0104.sql
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
-- Deprecate unused view to instead use products_last_purchased
|
||||||
|
DROP VIEW products_current_price;
|
||||||
|
|
||||||
|
CREATE VIEW products_last_purchased
|
||||||
|
AS
|
||||||
|
select
|
||||||
|
1 AS id, -- Dummy, LessQL needs an id column
|
||||||
|
sl.product_id,
|
||||||
|
sl.amount,
|
||||||
|
sl.best_before_date,
|
||||||
|
sl.purchased_date,
|
||||||
|
sl.price,
|
||||||
|
sl.qu_factor_purchase_to_stock,
|
||||||
|
sl.location_id,
|
||||||
|
sl.shopping_location_id
|
||||||
|
from stock_log sl
|
||||||
|
JOIN (
|
||||||
|
SELECT
|
||||||
|
s1.product_id,
|
||||||
|
MAX(s1.id) max_stock_id
|
||||||
|
FROM stock_log s1
|
||||||
|
JOIN (
|
||||||
|
SELECT
|
||||||
|
s.product_id,
|
||||||
|
MAX(s.purchased_date) max_purchased_date
|
||||||
|
FROM stock_log s
|
||||||
|
WHERE undone = 0
|
||||||
|
AND transaction_type in ('purchase', 'stock-edit-new', 'inventory-correction')
|
||||||
|
GROUP BY s.product_id) sp2
|
||||||
|
ON s1.product_id = sp2.product_id
|
||||||
|
AND s1.purchased_date = sp2.max_purchased_date
|
||||||
|
WHERE undone = 0
|
||||||
|
AND transaction_type in ('purchase', 'stock-edit-new', 'inventory-correction')
|
||||||
|
GROUP BY s1.product_id) sp3
|
||||||
|
ON sl.product_id = sp3.product_id
|
||||||
|
AND sl.id = sp3.max_stock_id;
|
||||||
|
|
||||||
|
CREATE VIEW products_average_price
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
1 AS id, -- Dummy, LessQL needs an id column
|
||||||
|
s.product_id,
|
||||||
|
round(sum(s.amount * s.price) / sum(s.amount), 2) as price
|
||||||
|
FROM stock s
|
||||||
|
GROUP BY s.product_id;
|
||||||
|
|
||||||
|
CREATE VIEW products_oldest_stock_unit_price
|
||||||
|
AS
|
||||||
|
-- Find oldest best_before_date then oldest purchased_date then make sure to return one stock row using max
|
||||||
|
SELECT
|
||||||
|
1 AS id, -- Dummy, LessQL needs an id column
|
||||||
|
sw.product_id,
|
||||||
|
sw.amount,
|
||||||
|
sw.best_before_date,
|
||||||
|
sw.purchased_date,
|
||||||
|
sw.price, sw.qu_factor_purchase_to_stock,
|
||||||
|
sw.location_id,
|
||||||
|
sw.shopping_location_id
|
||||||
|
FROM stock sw
|
||||||
|
JOIN (
|
||||||
|
SELECT
|
||||||
|
s1.product_id,
|
||||||
|
MIN(s1.id) min_stock_id
|
||||||
|
FROM stock s1
|
||||||
|
JOIN (
|
||||||
|
SELECT
|
||||||
|
s.product_id,
|
||||||
|
sp.oldest_date,
|
||||||
|
MIN(s.purchased_date) min_purchased_date
|
||||||
|
FROM stock s
|
||||||
|
JOIN (
|
||||||
|
SELECT
|
||||||
|
product_id,
|
||||||
|
MIN(best_before_date) as oldest_date
|
||||||
|
FROM stock
|
||||||
|
GROUP BY product_id) sp
|
||||||
|
ON s.product_id = sp.product_id
|
||||||
|
AND s.best_before_date = sp.oldest_date
|
||||||
|
GROUP BY s.product_id, sp.oldest_date) sp2
|
||||||
|
ON s1.product_id = sp2.product_id
|
||||||
|
AND s1.best_before_date = sp2.oldest_date
|
||||||
|
AND s1.purchased_date = sp2.min_purchased_date
|
||||||
|
GROUP BY s1.product_id) sp3
|
||||||
|
ON sw.product_id = sp3.product_id
|
||||||
|
AND sw.id = sp3.min_stock_id;
|
||||||
|
|
||||||
|
DROP VIEW recipes_pos_resolved;
|
||||||
|
CREATE VIEW recipes_pos_resolved
|
||||||
|
AS
|
||||||
|
|
||||||
|
-- Multiplication by 1.0 to force conversion to float (REAL)
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
r.id AS recipe_id,
|
||||||
|
rp.id AS recipe_pos_id,
|
||||||
|
rp.product_id AS product_id,
|
||||||
|
rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) AS recipe_amount,
|
||||||
|
IFNULL(sc.amount_aggregated, 0) AS stock_amount,
|
||||||
|
CASE WHEN IFNULL(sc.amount_aggregated, 0) >= CASE WHEN rp.only_check_single_unit_in_stock = 1 THEN 1 ELSE rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) END THEN 1 ELSE 0 END AS need_fulfilled,
|
||||||
|
CASE WHEN IFNULL(sc.amount_aggregated, 0) - CASE WHEN rp.only_check_single_unit_in_stock = 1 THEN 1 ELSE rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) END < 0 THEN ABS(IFNULL(sc.amount_aggregated, 0) - (CASE WHEN rp.only_check_single_unit_in_stock = 1 THEN 1 ELSE rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) END)) ELSE 0 END AS missing_amount,
|
||||||
|
IFNULL(sl.amount, 0) * p.qu_factor_purchase_to_stock AS amount_on_shopping_list,
|
||||||
|
CASE WHEN IFNULL(sc.amount_aggregated, 0) + (CASE WHEN r.not_check_shoppinglist = 1 THEN 0 ELSE IFNULL(sl.amount, 0) END * p.qu_factor_purchase_to_stock) >= CASE WHEN rp.only_check_single_unit_in_stock = 1 THEN 1 ELSE rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) END THEN 1 ELSE 0 END AS need_fulfilled_with_shopping_list,
|
||||||
|
rp.qu_id,
|
||||||
|
(CASE WHEN rp.only_check_single_unit_in_stock = 1 THEN 1 ELSE (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) END) * rp.amount * pop.price * rp.price_factor AS costs,
|
||||||
|
CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN 0 ELSE 1 END AS is_nested_recipe_pos,
|
||||||
|
rp.ingredient_group,
|
||||||
|
pg.name as product_group,
|
||||||
|
rp.id, -- Just a dummy id column
|
||||||
|
r.type as recipe_type,
|
||||||
|
rnr.includes_recipe_id as child_recipe_id,
|
||||||
|
rp.note,
|
||||||
|
rp.variable_amount AS recipe_variable_amount,
|
||||||
|
rp.only_check_single_unit_in_stock,
|
||||||
|
rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * IFNULL(p.calories, 0) AS calories,
|
||||||
|
p.active AS product_active
|
||||||
|
FROM recipes r
|
||||||
|
JOIN recipes_nestings_resolved rnr
|
||||||
|
ON r.id = rnr.recipe_id
|
||||||
|
JOIN recipes rnrr
|
||||||
|
ON rnr.includes_recipe_id = rnrr.id
|
||||||
|
JOIN recipes_pos rp
|
||||||
|
ON rnr.includes_recipe_id = rp.recipe_id
|
||||||
|
JOIN products p
|
||||||
|
ON rp.product_id = p.id
|
||||||
|
LEFT JOIN product_groups pg
|
||||||
|
ON p.product_group_id = pg.id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT product_id, SUM(amount) AS amount
|
||||||
|
FROM shopping_list
|
||||||
|
GROUP BY product_id) sl
|
||||||
|
ON rp.product_id = sl.product_id
|
||||||
|
LEFT JOIN stock_current sc
|
||||||
|
ON rp.product_id = sc.product_id
|
||||||
|
LEFT JOIN products_oldest_stock_unit_price pop
|
||||||
|
ON rp.product_id = pop.product_id
|
||||||
|
WHERE rp.not_check_stock_fulfillment = 0
|
||||||
|
|
||||||
|
UNION
|
||||||
|
|
||||||
|
-- Just add all recipe positions which should not be checked against stock with fulfilled need
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
r.id AS recipe_id,
|
||||||
|
rp.id AS recipe_pos_id,
|
||||||
|
rp.product_id AS product_id,
|
||||||
|
rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) AS recipe_amount,
|
||||||
|
IFNULL(sc.amount_aggregated, 0) AS stock_amount,
|
||||||
|
1 AS need_fulfilled,
|
||||||
|
0 AS missing_amount,
|
||||||
|
IFNULL(sl.amount, 0) * p.qu_factor_purchase_to_stock AS amount_on_shopping_list,
|
||||||
|
1 AS need_fulfilled_with_shopping_list,
|
||||||
|
rp.qu_id,
|
||||||
|
(CASE WHEN rp.only_check_single_unit_in_stock = 1 THEN 1 ELSE (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) END) * rp.amount * IFNULL(pop.price, 0) * rp.price_factor AS costs,
|
||||||
|
CASE WHEN rnr.recipe_id = rnr.includes_recipe_id THEN 0 ELSE 1 END AS is_nested_recipe_pos,
|
||||||
|
rp.ingredient_group,
|
||||||
|
pg.name as product_group,
|
||||||
|
rp.id, -- Just a dummy id column
|
||||||
|
r.type as recipe_type,
|
||||||
|
rnr.includes_recipe_id as child_recipe_id,
|
||||||
|
rp.note,
|
||||||
|
rp.variable_amount AS recipe_variable_amount,
|
||||||
|
rp.only_check_single_unit_in_stock,
|
||||||
|
rp.amount * (r.desired_servings*1.0 / r.base_servings*1.0) * (rnr.includes_servings*1.0 / CASE WHEN rnr.recipe_id != rnr.includes_recipe_id THEN rnrr.base_servings*1.0 ELSE 1 END) * IFNULL(p.calories, 0) AS calories,
|
||||||
|
p.active AS product_active
|
||||||
|
FROM recipes r
|
||||||
|
JOIN recipes_nestings_resolved rnr
|
||||||
|
ON r.id = rnr.recipe_id
|
||||||
|
JOIN recipes rnrr
|
||||||
|
ON rnr.includes_recipe_id = rnrr.id
|
||||||
|
JOIN recipes_pos rp
|
||||||
|
ON rnr.includes_recipe_id = rp.recipe_id
|
||||||
|
JOIN products p
|
||||||
|
ON rp.product_id = p.id
|
||||||
|
LEFT JOIN product_groups pg
|
||||||
|
ON p.product_group_id = pg.id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT product_id, SUM(amount) AS amount
|
||||||
|
FROM shopping_list
|
||||||
|
GROUP BY product_id) sl
|
||||||
|
ON rp.product_id = sl.product_id
|
||||||
|
LEFT JOIN stock_current sc
|
||||||
|
ON rp.product_id = sc.product_id
|
||||||
|
LEFT JOIN products_oldest_stock_unit_price pop
|
||||||
|
ON rp.product_id = pop.product_id
|
||||||
|
WHERE rp.not_check_stock_fulfillment = 1;
|
@ -6,11 +6,24 @@ Grocy.Components.ProductCard.Refresh = function(productId)
|
|||||||
function(productDetails)
|
function(productDetails)
|
||||||
{
|
{
|
||||||
var stockAmount = productDetails.stock_amount || '0';
|
var stockAmount = productDetails.stock_amount || '0';
|
||||||
|
var stockFactorPurchaseAmount = productDetails.stock_factor_purchase_amount || '0';
|
||||||
|
var stockValue = productDetails.stock_value || '0';
|
||||||
var stockAmountOpened = productDetails.stock_amount_opened || '0';
|
var stockAmountOpened = productDetails.stock_amount_opened || '0';
|
||||||
$('#productcard-product-name').text(productDetails.product.name);
|
$('#productcard-product-name').text(productDetails.product.name);
|
||||||
$('#productcard-product-description').html(productDetails.product.description);
|
$('#productcard-product-description').html(productDetails.product.description);
|
||||||
$('#productcard-product-stock-amount').text(stockAmount);
|
$('#productcard-product-stock-amount').text(stockAmount);
|
||||||
$('#productcard-product-stock-qu-name').text(__n(stockAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural));
|
$('#productcard-product-stock-qu-name').text(__n(stockAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural));
|
||||||
|
if (productDetails.last_qu_factor_purchase_to_stock > 1)
|
||||||
|
{
|
||||||
|
$('#productcard-product-stock-factor-purchase-amount').text('(' + stockFactorPurchaseAmount);
|
||||||
|
$('#productcard-product-stock-factor-purchase-qu-name').text(__n(stockFactorPurchaseAmount, productDetails.quantity_unit_purchase.name, productDetails.quantity_unit_purchase.name_plural) + ')');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#productcard-product-stock-factor-purchase-amount').text('');
|
||||||
|
$('#productcard-product-stock-factor-purchase-qu-name').text('');
|
||||||
|
}
|
||||||
|
$('#productcard-product-stock-value').text(stockValue + ' ' + Grocy.Currency);
|
||||||
$('#productcard-product-last-purchased').text((productDetails.last_purchased || '2999-12-31').substring(0, 10));
|
$('#productcard-product-last-purchased').text((productDetails.last_purchased || '2999-12-31').substring(0, 10));
|
||||||
$('#productcard-product-last-purchased-timeago').attr("datetime", productDetails.last_purchased || '2999-12-31');
|
$('#productcard-product-last-purchased-timeago').attr("datetime", productDetails.last_purchased || '2999-12-31');
|
||||||
$('#productcard-product-last-used').text((productDetails.last_used || '2999-12-31').substring(0, 10));
|
$('#productcard-product-last-used').text((productDetails.last_used || '2999-12-31').substring(0, 10));
|
||||||
@ -80,13 +93,29 @@ Grocy.Components.ProductCard.Refresh = function(productId)
|
|||||||
|
|
||||||
if (productDetails.last_price !== null)
|
if (productDetails.last_price !== null)
|
||||||
{
|
{
|
||||||
$('#productcard-product-last-price').text(Number.parseFloat(productDetails.last_price).toLocaleString() + ' ' + Grocy.Currency + ' per ' + productDetails.quantity_unit_purchase.name);
|
if (productDetails.last_qu_factor_purchase_to_stock > 1)
|
||||||
|
{
|
||||||
|
$('#productcard-product-last-price').text(Number.parseFloat(productDetails.last_price).toLocaleString() + ' ' + Grocy.Currency + ' per 1 ' + productDetails.quantity_unit_purchase.name + ' of ' + productDetails.last_qu_factor_purchase_to_stock + ' ' + productDetails.quantity_unit_stock.name_plural);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#productcard-product-last-price').text(Number.parseFloat(productDetails.last_price).toLocaleString() + ' ' + Grocy.Currency + ' per ' + productDetails.quantity_unit_purchase.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$('#productcard-product-last-price').text(__t('Unknown'));
|
$('#productcard-product-last-price').text(__t('Unknown'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (productDetails.avg_price !== null)
|
||||||
|
{
|
||||||
|
$('#productcard-product-average-price').text(Number.parseFloat(productDetails.avg_price).toLocaleString() + ' ' + Grocy.Currency);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#productcard-product-average-price').text(__t('Unknown'));
|
||||||
|
}
|
||||||
|
|
||||||
if (productDetails.product.picture_file_name !== null && !productDetails.product.picture_file_name.isEmpty())
|
if (productDetails.product.picture_file_name !== null && !productDetails.product.picture_file_name.isEmpty())
|
||||||
{
|
{
|
||||||
$("#productcard-product-picture").removeClass("d-none");
|
$("#productcard-product-picture").removeClass("d-none");
|
||||||
|
@ -132,6 +132,7 @@ $('#product_id_text_input').on('blur', function(e)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
$('#product_id').attr("barcode", "null");
|
||||||
|
|
||||||
var input = $('#product_id_text_input').val().toString();
|
var input = $('#product_id_text_input').val().toString();
|
||||||
var possibleOptionElement = $("#product_id option[data-additional-searchdata*=\"" + input + ",\"]").first();
|
var possibleOptionElement = $("#product_id option[data-additional-searchdata*=\"" + input + ",\"]").first();
|
||||||
@ -139,6 +140,7 @@ $('#product_id_text_input').on('blur', function(e)
|
|||||||
if (GetUriParam('addbarcodetoselection') === undefined && input.length > 0 && possibleOptionElement.length > 0)
|
if (GetUriParam('addbarcodetoselection') === undefined && input.length > 0 && possibleOptionElement.length > 0)
|
||||||
{
|
{
|
||||||
$('#product_id').val(possibleOptionElement.val());
|
$('#product_id').val(possibleOptionElement.val());
|
||||||
|
$('#product_id').attr("barcode", input);
|
||||||
$('#product_id').data('combobox').refresh();
|
$('#product_id').data('combobox').refresh();
|
||||||
$('#product_id').trigger('change');
|
$('#product_id').trigger('change');
|
||||||
}
|
}
|
||||||
|
@ -44,17 +44,12 @@
|
|||||||
var addBarcode = GetUriParam('addbarcodetoselection');
|
var addBarcode = GetUriParam('addbarcodetoselection');
|
||||||
if (addBarcode !== undefined)
|
if (addBarcode !== undefined)
|
||||||
{
|
{
|
||||||
var existingBarcodes = productDetails.product.barcode || '';
|
var jsonDataBarcode = {};
|
||||||
if (existingBarcodes.length === 0)
|
jsonDataBarcode.barcode = addBarcode;
|
||||||
{
|
jsonDataBarcode.product_id = jsonForm.product_id;
|
||||||
productDetails.product.barcode = addBarcode;
|
jsonDataBarcode.qu_factor_purchase_to_stock = productDetails.product.qu_factor_purchase_to_stock;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
productDetails.product.barcode += ',' + addBarcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Grocy.Api.Put('objects/products/' + productDetails.product.id, productDetails.product,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function(result)
|
function(result)
|
||||||
{
|
{
|
||||||
$("#flow-info-addbarcodetoselection").addClass("d-none");
|
$("#flow-info-addbarcodetoselection").addClass("d-none");
|
||||||
@ -63,7 +58,8 @@
|
|||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -37,17 +37,13 @@
|
|||||||
var addBarcode = GetUriParam('addbarcodetoselection');
|
var addBarcode = GetUriParam('addbarcodetoselection');
|
||||||
if (addBarcode !== undefined)
|
if (addBarcode !== undefined)
|
||||||
{
|
{
|
||||||
var existingBarcodes = productDetails.product.barcode || '';
|
var jsonDataBarcode = {};
|
||||||
if (existingBarcodes.length === 0)
|
jsonDataBarcode.barcode = addBarcode;
|
||||||
{
|
jsonDataBarcode.product_id = jsonForm.product_id;
|
||||||
productDetails.product.barcode = addBarcode;
|
jsonDataBarcode.qu_factor_purchase_to_stock = productDetails.product.qu_factor_purchase_to_stock;
|
||||||
}
|
jsonDataBarcode.shopping_location_id = jsonForm.shopping_location_id;
|
||||||
else
|
|
||||||
{
|
|
||||||
productDetails.product.barcode += ',' + addBarcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Grocy.Api.Put('objects/products/' + productDetails.product.id, productDetails.product,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function(result)
|
function(result)
|
||||||
{
|
{
|
||||||
$("#flow-info-addbarcodetoselection").addClass("d-none");
|
$("#flow-info-addbarcodetoselection").addClass("d-none");
|
||||||
@ -56,7 +52,8 @@
|
|||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
||||||
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -180,6 +180,11 @@ var calendar = $("#calendar").fullCalendar({
|
|||||||
productDetails.last_price = 0;
|
productDetails.last_price = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (productDetails.last_qu_factor_purchase_to_stock === null)
|
||||||
|
{
|
||||||
|
productDetails.last_qu_factor_purchase_to_stock = 1;
|
||||||
|
}
|
||||||
|
|
||||||
element.attr("data-product-details", event.productDetails);
|
element.attr("data-product-details", event.productDetails);
|
||||||
|
|
||||||
var productOrderMissingButtonDisabledClasses = "disabled";
|
var productOrderMissingButtonDisabledClasses = "disabled";
|
||||||
@ -205,7 +210,7 @@ var calendar = $("#calendar").fullCalendar({
|
|||||||
var costsAndCaloriesPerServing = ""
|
var costsAndCaloriesPerServing = ""
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
{
|
{
|
||||||
costsAndCaloriesPerServing = '<h5 class="small text-truncate"><span class="locale-number locale-number-currency">' + productDetails.last_price / productDetails.product.qu_factor_purchase_to_stock * mealPlanEntry.product_amount + '</span> / <span class="locale-number locale-number-generic">' + productDetails.product.calories * mealPlanEntry.product_amount + '</span> kcal ' + '<h5>';
|
costsAndCaloriesPerServing = '<h5 class="small text-truncate"><span class="locale-number locale-number-currency">' + productDetails.last_price / productDetails.last_qu_factor_purchase_to_stock * mealPlanEntry.product_amount + '</span> / <span class="locale-number locale-number-generic">' + productDetails.product.calories * mealPlanEntry.product_amount + '</span> kcal ' + '<h5>';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
65
public/viewjs/productbarcodesform.js
Normal file
65
public/viewjs/productbarcodesform.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
$('#save-barcode-button').on('click', function(e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var jsonData = $('#barcode-form').serializeJSON();
|
||||||
|
Grocy.FrontendHelpers.BeginUiBusy("barcode-form");
|
||||||
|
|
||||||
|
if (Grocy.EditMode === 'create')
|
||||||
|
{
|
||||||
|
Grocy.Api.Post('objects/product_barcodes', jsonData,
|
||||||
|
function(result)
|
||||||
|
{
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
Grocy.FrontendHelpers.EndUiBusy("barcode-form");
|
||||||
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Grocy.Api.Put('objects/product_barcodes/' + Grocy.EditObjectId, jsonData,
|
||||||
|
function(result)
|
||||||
|
{
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
Grocy.FrontendHelpers.EndUiBusy("barcode-form");
|
||||||
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.parent.postMessage(WindowMessageBag("ProductBarcodesChanged"), U("/product/" + GetUriParam("product")));
|
||||||
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), U("/product/" + GetUriParam("product")));
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#barcode').on('change', function(e)
|
||||||
|
{
|
||||||
|
Grocy.FrontendHelpers.ValidateForm('barcode-form');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#qu_factor_purchase_to_stock').on('change', function(e)
|
||||||
|
{
|
||||||
|
Grocy.FrontendHelpers.ValidateForm('barcode-form');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#barcode-form input').keydown(function(event)
|
||||||
|
{
|
||||||
|
if (event.keyCode === 13) //Enter
|
||||||
|
{
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (document.getElementById('barcode-form').checkValidity() === false) //There is at least one validation error
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#save-barcode-button').click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Grocy.FrontendHelpers.ValidateForm('barcode-form');
|
@ -42,6 +42,26 @@
|
|||||||
function(result)
|
function(result)
|
||||||
{
|
{
|
||||||
Grocy.EditObjectId = result.created_object_id;
|
Grocy.EditObjectId = result.created_object_id;
|
||||||
|
|
||||||
|
if (prefillBarcode !== undefined)
|
||||||
|
{
|
||||||
|
var jsonDataBarcode = {};
|
||||||
|
jsonDataBarcode.barcode = prefillBarcode;
|
||||||
|
jsonDataBarcode.product_id = result.created_object_id;
|
||||||
|
jsonDataBarcode.qu_factor_purchase_to_stock = jsonData.qu_factor_purchase_to_stock;
|
||||||
|
jsonDataBarcode.shopping_location_id = jsonData.shopping_location_id;
|
||||||
|
|
||||||
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
|
function(result)
|
||||||
|
{
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
Grocy.FrontendHelpers.EndUiBusy("barcode-form");
|
||||||
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
Grocy.Components.UserfieldsForm.Save(function()
|
Grocy.Components.UserfieldsForm.Save(function()
|
||||||
{
|
{
|
||||||
if (jsonData.hasOwnProperty("picture_file_name") && !Grocy.DeleteProductPictureOnSave)
|
if (jsonData.hasOwnProperty("picture_file_name") && !Grocy.DeleteProductPictureOnSave)
|
||||||
@ -166,32 +186,19 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#barcode-taginput').tagsManager({
|
Grocy.Api.Get('stock/products/' + Grocy.EditObjectId,
|
||||||
'hiddenTagListName': 'barcode',
|
function(productDetails)
|
||||||
'tagsContainer': '#barcode-taginput-container',
|
{
|
||||||
'tagClass': 'badge badge-secondary',
|
if (productDetails.last_purchased == null)
|
||||||
'delimiters': [13, 44]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (Grocy.EditMode === 'edit')
|
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/products/' + Grocy.EditObjectId,
|
|
||||||
function (product)
|
|
||||||
{
|
{
|
||||||
if (product.barcode !== null && product.barcode.length > 0)
|
$('#qu_id_stock').removeAttr("disabled");
|
||||||
{
|
|
||||||
product.barcode.split(',').forEach(function(item)
|
|
||||||
{
|
|
||||||
$('#barcode-taginput').tagsManager('pushTag', item);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(xhr)
|
|
||||||
{
|
|
||||||
console.error(xhr);
|
|
||||||
}
|
}
|
||||||
);
|
},
|
||||||
}
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
var prefillName = GetUriParam('prefillname');
|
var prefillName = GetUriParam('prefillname');
|
||||||
if (prefillName !== undefined)
|
if (prefillName !== undefined)
|
||||||
@ -201,16 +208,6 @@ if (prefillName !== undefined)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var prefillBarcode = GetUriParam('prefillbarcode');
|
var prefillBarcode = GetUriParam('prefillbarcode');
|
||||||
if (prefillBarcode !== undefined)
|
|
||||||
{
|
|
||||||
$('#barcode-taginput').tagsManager('pushTag', prefillBarcode);
|
|
||||||
$('#name').focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#barcode-taginput").on("blur", function(e)
|
|
||||||
{
|
|
||||||
$("#barcode-taginput").tagsManager("pushTag", $("#barcode-taginput").val());
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.input-group-qu').on('change', function(e)
|
$('.input-group-qu').on('change', function(e)
|
||||||
{
|
{
|
||||||
@ -249,12 +246,34 @@ $('#product-form input').keyup(function(event)
|
|||||||
{
|
{
|
||||||
$("#qu-conversion-add-button").removeClass("disabled");
|
$("#qu-conversion-add-button").removeClass("disabled");
|
||||||
}
|
}
|
||||||
|
if (document.getElementById('product-form').checkValidity() === false) //There is at least one validation error
|
||||||
|
{
|
||||||
|
$("#barcode-add-button").addClass("disabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (prefillBarcode === undefined)
|
||||||
|
{
|
||||||
|
$("#barcode-add-button").removeClass("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#product-form select').change(function(event)
|
$('#product-form select').change(function(event)
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.ValidateForm('product-form');
|
Grocy.FrontendHelpers.ValidateForm('product-form');
|
||||||
|
|
||||||
|
if (document.getElementById('product-form').checkValidity() === false) //There is at least one validation error
|
||||||
|
{
|
||||||
|
$("#barcode-add-button").addClass("disabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (prefillBarcode === undefined)
|
||||||
|
{
|
||||||
|
$("#barcode-add-button").removeClass("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (document.getElementById('product-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('product-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
$("#qu-conversion-add-button").addClass("disabled");
|
$("#qu-conversion-add-button").addClass("disabled");
|
||||||
@ -365,6 +384,17 @@ var quConversionsTable = $('#qu-conversions-table').DataTable({
|
|||||||
$('#qu-conversions-table tbody').removeClass("d-none");
|
$('#qu-conversions-table tbody').removeClass("d-none");
|
||||||
quConversionsTable.columns.adjust().draw();
|
quConversionsTable.columns.adjust().draw();
|
||||||
|
|
||||||
|
var barcodeTable = $('#barcode-table').DataTable({
|
||||||
|
'order': [[1, 'asc']],
|
||||||
|
"orderFixed": [[1, 'asc']],
|
||||||
|
'columnDefs': [
|
||||||
|
{ 'orderable': false, 'targets': 0 },
|
||||||
|
{ 'searchable': false, "targets": 0 }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
$('#barcode-table tbody').removeClass("d-none");
|
||||||
|
barcodeTable.columns.adjust().draw();
|
||||||
|
|
||||||
Grocy.Components.UserfieldsForm.Load();
|
Grocy.Components.UserfieldsForm.Load();
|
||||||
$("#name").trigger("keyup");
|
$("#name").trigger("keyup");
|
||||||
$('#name').focus();
|
$('#name').focus();
|
||||||
@ -412,17 +442,44 @@ $(document).on('click', '.qu-conversion-delete-button', function(e)
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '.qu-conversion-edit-button', function (e)
|
$(document).on('click', '.barcode-delete-button', function(e)
|
||||||
{
|
{
|
||||||
var id = $(e.currentTarget).attr('data-qu-conversion-id');
|
var objectId = $(e.currentTarget).attr('data-barcode-id');
|
||||||
Grocy.ProductEditFormRedirectUri = U("/quantityunitconversion/" + id.toString() + "?product=editobjectid");
|
var productId = $(e.currentTarget).attr('data-product-id');
|
||||||
$('#save-product-button').click();
|
var barcode = $(e.currentTarget).attr('data-barcode');
|
||||||
});
|
var productBarcode = $(e.currentTarget).attr('data-product-barcode');
|
||||||
|
|
||||||
$("#qu-conversion-add-button").on("click", function(e)
|
bootbox.confirm({
|
||||||
{
|
message: __t('Are you sure to remove this barcode?'),
|
||||||
Grocy.ProductEditFormRedirectUri = U("/quantityunitconversion/new?product=editobjectid");
|
closeButton: false,
|
||||||
$('#save-product-button').click();
|
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/product_barcodes/' + objectId, { },
|
||||||
|
function(result)
|
||||||
|
{
|
||||||
|
Grocy.ProductEditFormRedirectUri = "reload";
|
||||||
|
$('#save-product-button').click();
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#qu_id_purchase').blur(function(e)
|
$('#qu_id_purchase').blur(function(e)
|
||||||
@ -436,12 +493,12 @@ $('#qu_id_purchase').blur(function(e)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("Grocy.BarcodeScanned", function(e, barcode, target)
|
$(window).on("message", function(e)
|
||||||
{
|
{
|
||||||
if (target != "#barcode-taginput")
|
var data = e.originalEvent.data;
|
||||||
|
|
||||||
|
if (data.Message === "ProductBarcodesChanged" || data.Message === "ProductQUConversionChanged")
|
||||||
{
|
{
|
||||||
return;
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#barcode-taginput").tagsManager("pushTag", barcode);
|
|
||||||
});
|
});
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
Grocy.EditObjectId = result.created_object_id;
|
Grocy.EditObjectId = result.created_object_id;
|
||||||
Grocy.Components.UserfieldsForm.Save(function()
|
Grocy.Components.UserfieldsForm.Save(function()
|
||||||
{
|
{
|
||||||
window.location.href = U('/productgroups');
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), U("/productgroups"));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr)
|
||||||
@ -30,7 +30,7 @@
|
|||||||
{
|
{
|
||||||
Grocy.Components.UserfieldsForm.Save(function()
|
Grocy.Components.UserfieldsForm.Save(function()
|
||||||
{
|
{
|
||||||
window.location.href = U('/productgroups');
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), U("/productgroups"));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr)
|
||||||
|
@ -55,3 +55,12 @@ $(document).on('click', '.product-group-delete-button', function(e)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
$(window).on("message", function(e)
|
||||||
|
{
|
||||||
|
var data = e.originalEvent.data;
|
||||||
|
|
||||||
|
if (data.Message === "CloseAllModals")
|
||||||
|
{
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -49,7 +49,7 @@ $(document).on('click', '.product-delete-button', function (e)
|
|||||||
if (stockAmount.toString() == "0")
|
if (stockAmount.toString() == "0")
|
||||||
{
|
{
|
||||||
bootbox.confirm({
|
bootbox.confirm({
|
||||||
message: __t('Are you sure to delete product "%s"?', objectName),
|
message: __t('Are you sure you want to deactivate this product "%s"?', objectName),
|
||||||
closeButton: false,
|
closeButton: false,
|
||||||
buttons: {
|
buttons: {
|
||||||
confirm: {
|
confirm: {
|
||||||
@ -65,7 +65,9 @@ $(document).on('click', '.product-delete-button', function (e)
|
|||||||
{
|
{
|
||||||
if (result === true)
|
if (result === true)
|
||||||
{
|
{
|
||||||
Grocy.Api.Delete('objects/products/' + objectId, {},
|
jsonData = {};
|
||||||
|
jsonData.active = 0;
|
||||||
|
Grocy.Api.Put('objects/products/' + objectId, jsonData,
|
||||||
function (result)
|
function (result)
|
||||||
{
|
{
|
||||||
window.location.href = U('/products');
|
window.location.href = U('/products');
|
||||||
@ -82,8 +84,8 @@ $(document).on('click', '.product-delete-button', function (e)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
bootbox.alert({
|
bootbox.alert({
|
||||||
title: __t('Delete not possible'),
|
title: __t('Deactivation not possible'),
|
||||||
message: __t('This product cannot be deleted because it is in stock, please remove the stock amount first.') + '<br><br>' + __t('Stock amount') + ': ' + stockAmount + ' ' + __n(stockAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural),
|
message: __t('This product cannot be deactivated because it is in stock, please remove the stock amount first.') + '<br><br>' + __t('Stock amount') + ': ' + stockAmount + ' ' + __n(stockAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural),
|
||||||
closeButton: false
|
closeButton: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,13 @@
|
|||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function(productDetails)
|
function(productDetails)
|
||||||
{
|
{
|
||||||
var amount = jsonForm.amount * productDetails.product.qu_factor_purchase_to_stock;
|
var amount = jsonForm.amount * jsonForm.qu_factor_purchase_to_stock;
|
||||||
|
|
||||||
var price = "";
|
var price = "";
|
||||||
if (!jsonForm.price.toString().isEmpty())
|
if (!jsonForm.price.toString().isEmpty())
|
||||||
{
|
{
|
||||||
price = parseFloat(jsonForm.price).toFixed(2);
|
// price is saved as 1 QU to stock
|
||||||
|
price = parseFloat(jsonForm.price / amount).toFixed(2);
|
||||||
|
|
||||||
if ($("input[name='price-type']:checked").val() == "total-price")
|
if ($("input[name='price-type']:checked").val() == "total-price")
|
||||||
{
|
{
|
||||||
@ -37,6 +38,7 @@
|
|||||||
{
|
{
|
||||||
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
||||||
}
|
}
|
||||||
|
jsonData.qu_factor_purchase_to_stock = jsonForm.qu_factor_purchase_to_stock;
|
||||||
|
|
||||||
Grocy.Api.Post('stock/products/' + jsonForm.product_id + '/add', jsonData,
|
Grocy.Api.Post('stock/products/' + jsonForm.product_id + '/add', jsonData,
|
||||||
function(result)
|
function(result)
|
||||||
@ -49,17 +51,13 @@
|
|||||||
var addBarcode = GetUriParam('addbarcodetoselection');
|
var addBarcode = GetUriParam('addbarcodetoselection');
|
||||||
if (addBarcode !== undefined)
|
if (addBarcode !== undefined)
|
||||||
{
|
{
|
||||||
var existingBarcodes = productDetails.product.barcode || '';
|
var jsonDataBarcode = {};
|
||||||
if (existingBarcodes.length === 0)
|
jsonDataBarcode.barcode = addBarcode;
|
||||||
{
|
jsonDataBarcode.product_id = jsonForm.product_id;
|
||||||
productDetails.product.barcode = addBarcode;
|
jsonDataBarcode.qu_factor_purchase_to_stock = jsonForm.qu_factor_purchase_to_stock;
|
||||||
}
|
jsonDataBarcode.shopping_location_id = jsonForm.shopping_location_id;
|
||||||
else
|
|
||||||
{
|
|
||||||
productDetails.product.barcode += ',' + addBarcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Grocy.Api.Put('objects/products/' + productDetails.product.id, productDetails.product,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function(result)
|
function(result)
|
||||||
{
|
{
|
||||||
$("#flow-info-addbarcodetoselection").addClass("d-none");
|
$("#flow-info-addbarcodetoselection").addClass("d-none");
|
||||||
@ -69,7 +67,7 @@
|
|||||||
function(xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
||||||
console.error(xhr);
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -140,13 +138,66 @@ if (Grocy.Components.ProductPicker !== undefined)
|
|||||||
{
|
{
|
||||||
Grocy.Components.ProductCard.Refresh(productId);
|
Grocy.Components.ProductCard.Refresh(productId);
|
||||||
|
|
||||||
|
if (document.getElementById("product_id").getAttribute("barcode") != "null")
|
||||||
|
{
|
||||||
|
Grocy.Api.Get('productbarcodedetails/' + document.getElementById("product_id").getAttribute("barcode"),
|
||||||
|
function(resultBarcode)
|
||||||
|
{
|
||||||
|
if (resultBarcode != null)
|
||||||
|
{
|
||||||
|
$('#product_id').attr("barcode-qu-factor-purchase-to-stock", resultBarcode.qu_factor_purchase_to_stock);
|
||||||
|
$('#product_id').attr("barcode-shopping-location-id", resultBarcode.shopping_location_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#product_id').attr("barcode-qu-factor-purchase-to-stock", "null");
|
||||||
|
$('#product_id').attr("barcode-shopping-location-id", "null");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#product_id').attr("barcode-qu-factor-purchase-to-stock", "null");
|
||||||
|
$('#product_id').attr("barcode-shopping-location-id", "null");
|
||||||
|
}
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(productDetails)
|
function(productDetails)
|
||||||
{
|
{
|
||||||
$('#price').val(parseFloat(productDetails.last_price).toLocaleString({ minimumFractionDigits: 2, maximumFractionDigits: 2 }));
|
|
||||||
|
|
||||||
|
$('#price').val(parseFloat(productDetails.last_price).toLocaleString({ minimumFractionDigits: 2, maximumFractionDigits: 2 }));
|
||||||
|
|
||||||
|
var qu_factor_purchase_to_stock = null;
|
||||||
|
var barcode_shopping_location_id = null;
|
||||||
|
|
||||||
|
if (document.getElementById("product_id").getAttribute("barcode") != "null" && document.getElementById("product_id").getAttribute("barcode-qu-factor-purchase-to-stock") != "null")
|
||||||
|
{
|
||||||
|
qu_factor_purchase_to_stock = document.getElementById("product_id").getAttribute("barcode-qu-factor-purchase-to-stock");
|
||||||
|
barcode_shopping_location_id = document.getElementById("product_id").getAttribute("barcode-shopping-location-id");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (productDetails.last_qu_factor_purchase_to_stock != null)
|
||||||
|
{
|
||||||
|
qu_factor_purchase_to_stock = productDetails.last_qu_factor_purchase_to_stock;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qu_factor_purchase_to_stock = productDetails.product.qu_factor_purchase_to_stock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) {
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) {
|
||||||
if (productDetails.last_shopping_location_id != null)
|
if (barcode_shopping_location_id != null)
|
||||||
|
{
|
||||||
|
Grocy.Components.ShoppingLocationPicker.SetId(barcode_shopping_location_id);
|
||||||
|
}
|
||||||
|
else if (productDetails.last_shopping_location_id != null)
|
||||||
{
|
{
|
||||||
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.last_shopping_location_id);
|
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.last_shopping_location_id);
|
||||||
}
|
}
|
||||||
@ -161,15 +212,22 @@ if (Grocy.Components.ProductPicker !== undefined)
|
|||||||
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#amount_qu_unit').attr("qu-factor-purchase-to-stock", productDetails.product.qu_factor_purchase_to_stock);
|
$('#amount_qu_unit').attr("qu-factor-purchase-to-stock", qu_factor_purchase_to_stock);
|
||||||
|
$('#amount_qu_unit').attr("quantity-unit-purchase-name", productDetails.quantity_unit_purchase.name);
|
||||||
$('#amount_qu_unit').attr("quantity-unit-stock-name", productDetails.quantity_unit_stock.name);
|
$('#amount_qu_unit').attr("quantity-unit-stock-name", productDetails.quantity_unit_stock.name);
|
||||||
if (productDetails.product.qu_id_purchase === productDetails.product.qu_id_stock)
|
$('#amount_qu_unit').attr("quantity-unit-stock-name-plural", productDetails.quantity_unit_stock.name_plural);
|
||||||
|
$('#qu_factor_purchase_to_stock').val(qu_factor_purchase_to_stock);
|
||||||
|
|
||||||
|
|
||||||
|
if (qu_factor_purchase_to_stock == 1)
|
||||||
{
|
{
|
||||||
$('#amount_qu_unit').text(productDetails.quantity_unit_purchase.name);
|
$('#amount_qu_unit').text(productDetails.quantity_unit_purchase.name);
|
||||||
|
$('#group-qu_factor_purchase_to_stock').addClass('d-none');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$('#amount_qu_unit').text(productDetails.quantity_unit_purchase.name + " (" + __t("will be multiplied by a factor of %1$s to get %2$s", parseFloat(productDetails.product.qu_factor_purchase_to_stock).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: 2 }), __n(2, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural)) + ")");
|
$('#amount_qu_unit').text(productDetails.quantity_unit_purchase.name + " (" + __t("will be multiplied by a factor of %1$s to get %2$s", parseFloat(qu_factor_purchase_to_stock).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: 2 }), __n(2, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural)) + ")");
|
||||||
|
$('#group-qu_factor_purchase_to_stock').removeClass('d-none');
|
||||||
}
|
}
|
||||||
|
|
||||||
var priceTypeUnitPrice = $("#price-type-unit-price");
|
var priceTypeUnitPrice = $("#price-type-unit-price");
|
||||||
@ -193,7 +251,7 @@ if (Grocy.Components.ProductPicker !== undefined)
|
|||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1)
|
||||||
{
|
{
|
||||||
var minAmount = parseFloat(productDetails.product.tare_weight) / productDetails.product.qu_factor_purchase_to_stock + parseFloat(productDetails.stock_amount);
|
var minAmount = parseFloat(productDetails.product.tare_weight) / qu_factor_purchase_to_stock + parseFloat(productDetails.stock_amount);
|
||||||
$("#amount").attr("min", minAmount);
|
$("#amount").attr("min", minAmount);
|
||||||
$("#amount").attr("step", "0.0001");
|
$("#amount").attr("step", "0.0001");
|
||||||
$("#amount").parent().find(".invalid-feedback").text(__t('The amount cannot be lower than %s', minAmount.toLocaleString()));
|
$("#amount").parent().find(".invalid-feedback").text(__t('The amount cannot be lower than %s', minAmount.toLocaleString()));
|
||||||
@ -339,6 +397,15 @@ $('#amount').on('change', function(e)
|
|||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#qu_factor_purchase_to_stock').on('change', function(e)
|
||||||
|
{
|
||||||
|
var value = $(e.target).val();
|
||||||
|
$('#amount_qu_unit').attr("qu-factor-purchase-to-stock", value);
|
||||||
|
$('#amount_qu_unit').text(document.getElementById("amount_qu_unit").getAttribute("quantity-unit-purchase-name") + " (" + __t("will be multiplied by a factor of %1$s to get %2$s", parseFloat(value).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: 2 }), __n(2, document.getElementById("amount_qu_unit").getAttribute("quantity-unit-stock-name"), document.getElementById("amount_qu_unit").getAttribute("quantity-unit-stock-name-plural")) + ")"));
|
||||||
|
refreshPriceHint();
|
||||||
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
|
});
|
||||||
|
|
||||||
if (GetUriParam("flow") === "shoppinglistitemtostock")
|
if (GetUriParam("flow") === "shoppinglistitemtostock")
|
||||||
{
|
{
|
||||||
$('#amount').val(parseFloat(GetUriParam("amount")).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: 4 }));
|
$('#amount').val(parseFloat(GetUriParam("amount")).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: 4 }));
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
window.location.href = U("/product/" + GetUriParam("product"));
|
window.parent.postMessage(WindowMessageBag("ProductQUConversionChanged"), U("/product/" + GetUriParam("product")));
|
||||||
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), U("/product/" + GetUriParam("product")));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -54,7 +55,8 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
window.location.href = U("/product/" + GetUriParam("product"));
|
window.parent.postMessage(WindowMessageBag("ProductQUConversionChanged"), U("/product/" + GetUriParam("product")));
|
||||||
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), U("/product/" + GetUriParam("product")));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -79,7 +81,8 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
window.location.href = U("/product/" + GetUriParam("product"));
|
window.parent.postMessage(WindowMessageBag("ProductQUConversionChanged"), U("/product/" + GetUriParam("product")));
|
||||||
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), U("/product/" + GetUriParam("product")));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -177,6 +177,7 @@ function RefreshStockEntryRow(stockRowId)
|
|||||||
);
|
);
|
||||||
|
|
||||||
$('#stock-' + stockRowId + '-price').text(result.price);
|
$('#stock-' + stockRowId + '-price').text(result.price);
|
||||||
|
$('#stock-' + stockRowId + '-qu-factor-purchase-to-stock').text(result.qu_factor_purchase_to_stock);
|
||||||
$('#stock-' + stockRowId + '-purchased-date').text(result.purchased_date);
|
$('#stock-' + stockRowId + '-purchased-date').text(result.purchased_date);
|
||||||
$('#stock-' + stockRowId + '-purchased-date-timeago').attr('datetime', result.purchased_date + ' 23:59:59');
|
$('#stock-' + stockRowId + '-purchased-date-timeago').attr('datetime', result.purchased_date + ' 23:59:59');
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
jsonData.location_id = 1;
|
jsonData.location_id = 1;
|
||||||
}
|
}
|
||||||
jsonData.price = price;
|
jsonData.price = price;
|
||||||
|
jsonData.qu_factor_purchase_to_stock = jsonForm.qu_factor_purchase_to_stock;
|
||||||
|
console.log(jsonForm);
|
||||||
|
console.log(jsonData);
|
||||||
|
|
||||||
jsonData.open = $("#open").is(":checked");
|
jsonData.open = $("#open").is(":checked");
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
var stockOverviewTable = $('#stock-overview-table').DataTable({
|
var stockOverviewTable = $('#stock-overview-table').DataTable({
|
||||||
'order': [[3, 'asc']],
|
'order': [[4, 'asc']],
|
||||||
|
'colReorder': false,
|
||||||
'columnDefs': [
|
'columnDefs': [
|
||||||
{ 'orderable': false, 'targets': 0 },
|
{ 'orderable': false, 'targets': 0 },
|
||||||
{ 'searchable': false, "targets": 0 },
|
{ 'searchable': false, "targets": 0 },
|
||||||
{ 'visible': false, 'targets': 4 },
|
{ 'searchable': false, "targets": 0 },
|
||||||
{ 'visible': false, 'targets': 5 },
|
{ 'visible': false, 'targets': 5 },
|
||||||
{ 'visible': false, 'targets': 6 }
|
{ 'visible': false, 'targets': 6 }
|
||||||
],
|
],
|
||||||
@ -19,7 +20,7 @@ $("#location-filter").on("change", function()
|
|||||||
value = "";
|
value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
stockOverviewTable.column(4).search(value).draw();
|
stockOverviewTable.column(5).search(value).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#product-group-filter").on("change", function()
|
$("#product-group-filter").on("change", function()
|
||||||
@ -30,7 +31,7 @@ $("#product-group-filter").on("change", function()
|
|||||||
value = "";
|
value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
stockOverviewTable.column(6).search(value).draw();
|
stockOverviewTable.column(2).search(value).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#status-filter").on("change", function()
|
$("#status-filter").on("change", function()
|
||||||
@ -44,7 +45,7 @@ $("#status-filter").on("change", function()
|
|||||||
// Transfer CSS classes of selected element to dropdown element (for background)
|
// Transfer CSS classes of selected element to dropdown element (for background)
|
||||||
$(this).attr("class", $("#" + $(this).attr("id") + " option[value='" + value + "']").attr("class") + " form-control");
|
$(this).attr("class", $("#" + $(this).attr("id") + " option[value='" + value + "']").attr("class") + " form-control");
|
||||||
|
|
||||||
stockOverviewTable.column(5).search(value).draw();
|
stockOverviewTable.column(6).search(value).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".status-filter-message").on("click", function()
|
$(".status-filter-message").on("click", function()
|
||||||
@ -252,7 +253,7 @@ function RefreshProductRow(productId)
|
|||||||
$('#product-' + productId + '-qu-name').text(__n(result.stock_amount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural));
|
$('#product-' + productId + '-qu-name').text(__n(result.stock_amount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural));
|
||||||
$('#product-' + productId + '-amount').text(result.stock_amount);
|
$('#product-' + productId + '-amount').text(result.stock_amount);
|
||||||
$('#product-' + productId + '-consume-all-button').attr('data-consume-amount', result.stock_amount);
|
$('#product-' + productId + '-consume-all-button').attr('data-consume-amount', result.stock_amount);
|
||||||
|
$('#product-' + productId + '-factor-purchase-amount').text(__t('( %s', result.stock_factor_purchase_amount));
|
||||||
$('#product-' + productId + '-next-best-before-date').text(result.next_best_before_date);
|
$('#product-' + productId + '-next-best-before-date').text(result.next_best_before_date);
|
||||||
$('#product-' + productId + '-next-best-before-date-timeago').attr('datetime', result.next_best_before_date);
|
$('#product-' + productId + '-next-best-before-date-timeago').attr('datetime', result.next_best_before_date);
|
||||||
|
|
||||||
|
@ -30,17 +30,12 @@
|
|||||||
|
|
||||||
if (addBarcode !== undefined)
|
if (addBarcode !== undefined)
|
||||||
{
|
{
|
||||||
var existingBarcodes = productDetails.product.barcode || '';
|
var jsonDataBarcode = {};
|
||||||
if (existingBarcodes.length === 0)
|
jsonDataBarcode.barcode = addBarcode;
|
||||||
{
|
jsonDataBarcode.product_id = jsonForm.product_id;
|
||||||
productDetails.product.barcode = addBarcode;
|
jsonDataBarcode.qu_factor_purchase_to_stock = productDetails.product.qu_factor_purchase_to_stock;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
productDetails.product.barcode += ',' + addBarcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Grocy.Api.Put('objects/products/' + productDetails.product.id, productDetails.product,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function(result)
|
function(result)
|
||||||
{
|
{
|
||||||
$("#flow-info-addbarcodetoselection").addClass("d-none");
|
$("#flow-info-addbarcodetoselection").addClass("d-none");
|
||||||
@ -49,7 +44,8 @@
|
|||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr)
|
||||||
{
|
{
|
||||||
console.error(xhr);
|
Grocy.FrontendHelpers.EndUiBusy("transfer-form");
|
||||||
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ $app->group('', function(RouteCollectorProxy $group)
|
|||||||
$group->get('/stockentry/{entryId}', '\Grocy\Controllers\StockController:StockEntryEditForm');
|
$group->get('/stockentry/{entryId}', '\Grocy\Controllers\StockController:StockEntryEditForm');
|
||||||
$group->get('/products', '\Grocy\Controllers\StockController:ProductsList');
|
$group->get('/products', '\Grocy\Controllers\StockController:ProductsList');
|
||||||
$group->get('/product/{productId}', '\Grocy\Controllers\StockController:ProductEditForm');
|
$group->get('/product/{productId}', '\Grocy\Controllers\StockController:ProductEditForm');
|
||||||
|
$group->get('/productbarcodes/{productBarcodeId}', '\Grocy\Controllers\StockController:ProductBarcodesEditForm');
|
||||||
$group->get('/stocksettings', '\Grocy\Controllers\StockController:StockSettings');
|
$group->get('/stocksettings', '\Grocy\Controllers\StockController:StockSettings');
|
||||||
$group->get('/locations', '\Grocy\Controllers\StockController:LocationsList');
|
$group->get('/locations', '\Grocy\Controllers\StockController:LocationsList');
|
||||||
$group->get('/location/{locationId}', '\Grocy\Controllers\StockController:LocationEditForm');
|
$group->get('/location/{locationId}', '\Grocy\Controllers\StockController:LocationEditForm');
|
||||||
@ -199,6 +200,7 @@ $app->group('/api', function(RouteCollectorProxy $group)
|
|||||||
$group->get('/stock/transactions/{transactionId}', '\Grocy\Controllers\StockApiController:StockTransactions');
|
$group->get('/stock/transactions/{transactionId}', '\Grocy\Controllers\StockApiController:StockTransactions');
|
||||||
$group->post('/stock/transactions/{transactionId}/undo', '\Grocy\Controllers\StockApiController:UndoTransaction');
|
$group->post('/stock/transactions/{transactionId}/undo', '\Grocy\Controllers\StockApiController:UndoTransaction');
|
||||||
$group->get('/stock/barcodes/external-lookup/{barcode}', '\Grocy\Controllers\StockApiController:ExternalBarcodeLookup');
|
$group->get('/stock/barcodes/external-lookup/{barcode}', '\Grocy\Controllers\StockApiController:ExternalBarcodeLookup');
|
||||||
|
$group->get('/productbarcodedetails/{barcode}', '\Grocy\Controllers\StockApiController:ProductBarcodeDetails');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shopping list
|
// Shopping list
|
||||||
|
@ -96,7 +96,7 @@ class DemoDataGeneratorService extends BaseService
|
|||||||
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id, calories) VALUES ('{$this->__t_sql('Milk')}', 2, 10, 10, 1, 6, 1); --23
|
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id, calories) VALUES ('{$this->__t_sql('Milk')}', 2, 10, 10, 1, 6, 1); --23
|
||||||
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id, parent_product_id) VALUES ('{$this->__t_sql('Milk Chocolate')}', 4, 3, 3, 1, 1, 2); --24
|
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id, parent_product_id) VALUES ('{$this->__t_sql('Milk Chocolate')}', 4, 3, 3, 1, 1, 2); --24
|
||||||
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id, parent_product_id) VALUES ('{$this->__t_sql('Dark Chocolate')}', 4, 3, 3, 1, 1, 2); --25
|
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id, parent_product_id) VALUES ('{$this->__t_sql('Dark Chocolate')}', 4, 3, 3, 1, 1, 2); --25
|
||||||
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id, barcode) VALUES ('{$this->__t_sql('Waffle rolls')}', 4, 3, 3, 1, 1, '22111289'); --26
|
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id) VALUES ('{$this->__t_sql('Waffle rolls')}', 4, 3, 3, 1, 1); --26
|
||||||
UPDATE products SET calories = 123 WHERE IFNULL(calories, 0) = 0;
|
UPDATE products SET calories = 123 WHERE IFNULL(calories, 0) = 0;
|
||||||
|
|
||||||
/* Prevent invalid quantity unit assignments */
|
/* Prevent invalid quantity unit assignments */
|
||||||
@ -189,80 +189,80 @@ class DemoDataGeneratorService extends BaseService
|
|||||||
$this->getDatabaseService()->ExecuteDbStatement($sql);
|
$this->getDatabaseService()->ExecuteDbStatement($sql);
|
||||||
|
|
||||||
$stockService = new StockService();
|
$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(), null, $this->NextSupermarketId());
|
$stockService->AddProduct(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(3, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(4, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 10, null, 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('-20 days')), $this->RandomPrice(), 10, null, 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('-30 days')), $this->RandomPrice(), 10, null, 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('-40 days')), $this->RandomPrice(), 10, null, 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(5, 1, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 10, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(6, 1, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(7, 1, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(8, 1, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(9, 1, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(10, 1, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(11, 1, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(12, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(13, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(14, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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('-20 days')), $this->RandomPrice(), 1.0, null, 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('-30 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(15, 1, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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, 1500, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), 1.0, null, 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(21, 2500, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), 1.0, null, 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('-10 days')), $this->RandomPrice(), 1.0, null, 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(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice(), 1.0, null, 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('-40 days')), $this->RandomPrice(), 1.0, null, 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(23, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice(), 1.0, null, 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(24, 2, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), 1.0, null, 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(25, 2, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), 1.0, null, 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->AddProduct(2, 1, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice(), 1.0, null, null, $this->NextSupermarketId());
|
||||||
$stockService->AddMissingProductsToShoppingList();
|
$stockService->AddMissingProductsToShoppingList();
|
||||||
$stockService->OpenProduct(3, 1);
|
$stockService->OpenProduct(3, 1);
|
||||||
$stockService->OpenProduct(6, 1);
|
$stockService->OpenProduct(6, 1);
|
||||||
|
@ -25,7 +25,7 @@ class StockService extends BaseService
|
|||||||
$missingProductsView = 'stock_missing_products';
|
$missingProductsView = 'stock_missing_products';
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = 'SELECT * FROM stock_current WHERE best_before_date IS NOT NULL UNION SELECT id, 0, 0, null, 0, 0, 0 FROM ' . $missingProductsView . ' WHERE id NOT IN (SELECT product_id FROM stock_current)';
|
$sql = 'SELECT * FROM stock_current WHERE best_before_date IS NOT NULL UNION SELECT id, 0, 0, 0, 0, null, 0, 0, 0 FROM ' . $missingProductsView . ' WHERE id NOT IN (SELECT product_id FROM stock_current)';
|
||||||
}
|
}
|
||||||
$currentStockMapped = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_OBJ);
|
$currentStockMapped = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_OBJ);
|
||||||
|
|
||||||
@ -51,12 +51,6 @@ class StockService extends BaseService
|
|||||||
return $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
return $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetCurrentProductPrices()
|
|
||||||
{
|
|
||||||
$sql = 'SELECT * FROM products_current_price';
|
|
||||||
return $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetMissingProducts()
|
public function GetMissingProducts()
|
||||||
{
|
{
|
||||||
$sql = 'SELECT * FROM stock_missing_products_including_opened';
|
$sql = 'SELECT * FROM stock_missing_products_including_opened';
|
||||||
@ -75,7 +69,7 @@ class StockService extends BaseService
|
|||||||
|
|
||||||
public function GetProductIdFromBarcode(string $barcode)
|
public function GetProductIdFromBarcode(string $barcode)
|
||||||
{
|
{
|
||||||
$potentialProduct = $this->getDatabase()->products()->where("',' || barcode || ',' LIKE '%,' || :1 || ',%' AND IFNULL(barcode, '') != ''", $barcode)->limit(1)->fetch();
|
$potentialProduct = $this->getDatabase()->product_barcodes()->where("barcode = :1", $barcode)->fetch();
|
||||||
|
|
||||||
if ($potentialProduct === null)
|
if ($potentialProduct === null)
|
||||||
{
|
{
|
||||||
@ -102,7 +96,7 @@ class StockService extends BaseService
|
|||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
throw new \Exception('Product does not exist');
|
throw new \Exception('Product does not exist or is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
$stockCurrentRow = FindObjectinArrayByPropertyValue($this->GetCurrentStock(), 'product_id', $productId);
|
$stockCurrentRow = FindObjectinArrayByPropertyValue($this->GetCurrentStock(), 'product_id', $productId);
|
||||||
@ -111,6 +105,8 @@ class StockService extends BaseService
|
|||||||
{
|
{
|
||||||
$stockCurrentRow = new \stdClass();
|
$stockCurrentRow = new \stdClass();
|
||||||
$stockCurrentRow->amount = 0;
|
$stockCurrentRow->amount = 0;
|
||||||
|
$stockCurrentRow->factor_purchase_amount = 0;
|
||||||
|
$stockCurrentRow->value = 0;
|
||||||
$stockCurrentRow->amount_opened = 0;
|
$stockCurrentRow->amount_opened = 0;
|
||||||
$stockCurrentRow->amount_aggregated = 0;
|
$stockCurrentRow->amount_aggregated = 0;
|
||||||
$stockCurrentRow->amount_opened_aggregated = 0;
|
$stockCurrentRow->amount_opened_aggregated = 0;
|
||||||
@ -118,23 +114,20 @@ class StockService extends BaseService
|
|||||||
}
|
}
|
||||||
|
|
||||||
$product = $this->getDatabase()->products($productId);
|
$product = $this->getDatabase()->products($productId);
|
||||||
$productLastPurchased = $this->getDatabase()->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_PURCHASE)->where('undone', 0)->max('purchased_date');
|
$productBarcodes = $this->getDatabase()->product_barcodes()->where('product_id', $productId)->fetchAll();
|
||||||
|
$productLastPurchased = $this->getDatabase()->products_last_purchased()->where('product_id', $productId)->fetch();
|
||||||
$productLastUsed = $this->getDatabase()->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->where('undone', 0)->max('used_date');
|
$productLastUsed = $this->getDatabase()->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->where('undone', 0)->max('used_date');
|
||||||
$nextBestBeforeDate = $this->getDatabase()->stock()->where('product_id', $productId)->min('best_before_date');
|
$nextBestBeforeDate = $this->getDatabase()->stock()->where('product_id', $productId)->min('best_before_date');
|
||||||
$quPurchase = $this->getDatabase()->quantity_units($product->qu_id_purchase);
|
$quPurchase = $this->getDatabase()->quantity_units($product->qu_id_purchase);
|
||||||
$quStock = $this->getDatabase()->quantity_units($product->qu_id_stock);
|
$quStock = $this->getDatabase()->quantity_units($product->qu_id_stock);
|
||||||
$location = $this->getDatabase()->locations($product->location_id);
|
$location = $this->getDatabase()->locations($product->location_id);
|
||||||
$averageShelfLifeDays = intval($this->getDatabase()->stock_average_product_shelf_life()->where('id', $productId)->fetch()->average_shelf_life_days);
|
$averageShelfLifeDays = intval($this->getDatabase()->stock_average_product_shelf_life()->where('id', $productId)->fetch()->average_shelf_life_days);
|
||||||
|
$lastPrice = $productLastPurchased->price;
|
||||||
$lastPrice = null;
|
$lastQuFactorPurchaseToStock = $productLastPurchased->qu_factor_purchase_to_stock;
|
||||||
|
$avgPrice = $this->getDatabase()->products_average_price()->where('product_id', $productId)->fetch();
|
||||||
|
$oldestPrice = $this->getDatabase()->products_oldest_stock_unit_price()->where('product_id', $productId)->fetch();
|
||||||
$defaultShoppingLocation = null;
|
$defaultShoppingLocation = null;
|
||||||
$lastShoppingLocation = null;
|
$lastShoppingLocation = $productLastPurchased->shopping_location_id;
|
||||||
$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;
|
$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;
|
||||||
$consumeCountSpoiled = $this->getDatabase()->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->where('undone = 0 AND spoiled = 1')->sum('amount') * -1;
|
$consumeCountSpoiled = $this->getDatabase()->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->where('undone = 0 AND spoiled = 1')->sum('amount') * -1;
|
||||||
@ -146,15 +139,21 @@ class StockService extends BaseService
|
|||||||
|
|
||||||
return array(
|
return array(
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'last_purchased' => $productLastPurchased,
|
'product_barcodes' => $productBarcodes,
|
||||||
|
'last_purchased' => $productLastPurchased->purchased_date,
|
||||||
'last_used' => $productLastUsed,
|
'last_used' => $productLastUsed,
|
||||||
'stock_amount' => $stockCurrentRow->amount,
|
'stock_amount' => $stockCurrentRow->amount,
|
||||||
|
'stock_factor_purchase_amount' => $stockCurrentRow->factor_purchase_amount,
|
||||||
|
'stock_value' => $stockCurrentRow->value,
|
||||||
'stock_amount_opened' => $stockCurrentRow->amount_opened,
|
'stock_amount_opened' => $stockCurrentRow->amount_opened,
|
||||||
'stock_amount_aggregated' => $stockCurrentRow->amount_aggregated,
|
'stock_amount_aggregated' => $stockCurrentRow->amount_aggregated,
|
||||||
'stock_amount_opened_aggregated' => $stockCurrentRow->amount_opened_aggregated,
|
'stock_amount_opened_aggregated' => $stockCurrentRow->amount_opened_aggregated,
|
||||||
'quantity_unit_purchase' => $quPurchase,
|
'quantity_unit_purchase' => $quPurchase,
|
||||||
'quantity_unit_stock' => $quStock,
|
'quantity_unit_stock' => $quStock,
|
||||||
'last_price' => $lastPrice,
|
'last_price' => $lastPrice,
|
||||||
|
'last_qu_factor_purchase_to_stock' => $lastQuFactorPurchaseToStock,
|
||||||
|
'avg_price' => $avgPrice->price,
|
||||||
|
'oldest_price' => $oldestPrice->price,
|
||||||
'last_shopping_location_id' => $lastShoppingLocation,
|
'last_shopping_location_id' => $lastShoppingLocation,
|
||||||
'default_shopping_location_id' => $product->shopping_location_id,
|
'default_shopping_location_id' => $product->shopping_location_id,
|
||||||
'next_best_before_date' => $nextBestBeforeDate,
|
'next_best_before_date' => $nextBestBeforeDate,
|
||||||
@ -169,7 +168,7 @@ class StockService extends BaseService
|
|||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
throw new \Exception('Product does not exist');
|
throw new \Exception('Product does not exist or is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
$returnData = array();
|
$returnData = array();
|
||||||
@ -217,11 +216,11 @@ class StockService extends BaseService
|
|||||||
return FindAllObjectsInArrayByPropertyValue($stockEntries, 'location_id', $locationId);
|
return FindAllObjectsInArrayByPropertyValue($stockEntries, 'location_id', $locationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function AddProduct(int $productId, float $amount, $bestBeforeDate, $transactionType, $purchasedDate, $price, $locationId = null, $shoppingLocationId = null, &$transactionId = null)
|
public function AddProduct(int $productId, float $amount, $bestBeforeDate, $transactionType, $purchasedDate, $price, $quFactorPurchaseToStock, $locationId = null, $shoppingLocationId = null, &$transactionId = null)
|
||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
throw new \Exception('Product does not exist');
|
throw new \Exception('Product does not exist or is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tare weight handling
|
// Tare weight handling
|
||||||
@ -275,6 +274,7 @@ class StockService extends BaseService
|
|||||||
'location_id' => $locationId,
|
'location_id' => $locationId,
|
||||||
'transaction_id' => $transactionId,
|
'transaction_id' => $transactionId,
|
||||||
'shopping_location_id' => $shoppingLocationId,
|
'shopping_location_id' => $shoppingLocationId,
|
||||||
|
'qu_factor_purchase_to_stock' => $quFactorPurchaseToStock,
|
||||||
));
|
));
|
||||||
$logRow->save();
|
$logRow->save();
|
||||||
|
|
||||||
@ -289,6 +289,7 @@ class StockService extends BaseService
|
|||||||
'price' => $price,
|
'price' => $price,
|
||||||
'location_id' => $locationId,
|
'location_id' => $locationId,
|
||||||
'shopping_location_id' => $shoppingLocationId,
|
'shopping_location_id' => $shoppingLocationId,
|
||||||
|
'qu_factor_purchase_to_stock' => $quFactorPurchaseToStock,
|
||||||
));
|
));
|
||||||
$stockRow->save();
|
$stockRow->save();
|
||||||
|
|
||||||
@ -304,7 +305,7 @@ class StockService extends BaseService
|
|||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
throw new \Exception('Product does not exist');
|
throw new \Exception('Product does not exist or is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($locationId !== null && !$this->LocationExists($locationId))
|
if ($locationId !== null && !$this->LocationExists($locationId))
|
||||||
@ -423,7 +424,7 @@ class StockService extends BaseService
|
|||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
throw new \Exception('Product does not exist');
|
throw new \Exception('Product does not exist or is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->LocationExists($locationIdFrom))
|
if (!$this->LocationExists($locationIdFrom))
|
||||||
@ -509,6 +510,7 @@ class StockService extends BaseService
|
|||||||
'stock_id' => $stockEntry->stock_id,
|
'stock_id' => $stockEntry->stock_id,
|
||||||
'transaction_type' => self::TRANSACTION_TYPE_TRANSFER_FROM,
|
'transaction_type' => self::TRANSACTION_TYPE_TRANSFER_FROM,
|
||||||
'price' => $stockEntry->price,
|
'price' => $stockEntry->price,
|
||||||
|
'qu_factor_purchase_to_stock' => $stockEntry->qu_factor_purchase_to_stock,
|
||||||
'opened_date' => $stockEntry->opened_date,
|
'opened_date' => $stockEntry->opened_date,
|
||||||
'location_id' => $stockEntry->location_id,
|
'location_id' => $stockEntry->location_id,
|
||||||
'correlation_id' => $correlationId,
|
'correlation_id' => $correlationId,
|
||||||
@ -524,6 +526,7 @@ class StockService extends BaseService
|
|||||||
'stock_id' => $stockEntry->stock_id,
|
'stock_id' => $stockEntry->stock_id,
|
||||||
'transaction_type' => self::TRANSACTION_TYPE_TRANSFER_TO,
|
'transaction_type' => self::TRANSACTION_TYPE_TRANSFER_TO,
|
||||||
'price' => $stockEntry->price,
|
'price' => $stockEntry->price,
|
||||||
|
'qu_factor_purchase_to_stock' => $stockEntry->qu_factor_purchase_to_stock,
|
||||||
'opened_date' => $stockEntry->opened_date,
|
'opened_date' => $stockEntry->opened_date,
|
||||||
'location_id' => $locationIdTo,
|
'location_id' => $locationIdTo,
|
||||||
'correlation_id' => $correlationId,
|
'correlation_id' => $correlationId,
|
||||||
@ -550,6 +553,7 @@ class StockService extends BaseService
|
|||||||
'stock_id' => $stockEntry->stock_id,
|
'stock_id' => $stockEntry->stock_id,
|
||||||
'transaction_type' => self::TRANSACTION_TYPE_TRANSFER_FROM,
|
'transaction_type' => self::TRANSACTION_TYPE_TRANSFER_FROM,
|
||||||
'price' => $stockEntry->price,
|
'price' => $stockEntry->price,
|
||||||
|
'qu_factor_purchase_to_stock' => $stockEntry->qu_factor_purchase_to_stock,
|
||||||
'opened_date' => $stockEntry->opened_date,
|
'opened_date' => $stockEntry->opened_date,
|
||||||
'location_id' => $stockEntry->location_id,
|
'location_id' => $stockEntry->location_id,
|
||||||
'correlation_id' => $correlationId,
|
'correlation_id' => $correlationId,
|
||||||
@ -565,6 +569,7 @@ class StockService extends BaseService
|
|||||||
'stock_id' => $stockEntry->stock_id,
|
'stock_id' => $stockEntry->stock_id,
|
||||||
'transaction_type' => self::TRANSACTION_TYPE_TRANSFER_TO,
|
'transaction_type' => self::TRANSACTION_TYPE_TRANSFER_TO,
|
||||||
'price' => $stockEntry->price,
|
'price' => $stockEntry->price,
|
||||||
|
'qu_factor_purchase_to_stock' => $stockEntry->qu_factor_purchase_to_stock,
|
||||||
'opened_date' => $stockEntry->opened_date,
|
'opened_date' => $stockEntry->opened_date,
|
||||||
'location_id' => $locationIdTo,
|
'location_id' => $locationIdTo,
|
||||||
'correlation_id' => $correlationId,
|
'correlation_id' => $correlationId,
|
||||||
@ -584,6 +589,7 @@ class StockService extends BaseService
|
|||||||
'best_before_date' => $newBestBeforeDate,
|
'best_before_date' => $newBestBeforeDate,
|
||||||
'purchased_date' => $stockEntry->purchased_date,
|
'purchased_date' => $stockEntry->purchased_date,
|
||||||
'stock_id' => $stockEntry->stock_id,
|
'stock_id' => $stockEntry->stock_id,
|
||||||
|
'qu_factor_purchase_to_stock' => $stockEntry->qu_factor_purchase_to_stock,
|
||||||
'price' => $stockEntry->price,
|
'price' => $stockEntry->price,
|
||||||
'location_id' => $locationIdTo,
|
'location_id' => $locationIdTo,
|
||||||
'open' => $stockEntry->open,
|
'open' => $stockEntry->open,
|
||||||
@ -598,7 +604,7 @@ class StockService extends BaseService
|
|||||||
return $this->getDatabase()->lastInsertId();
|
return $this->getDatabase()->lastInsertId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function EditStockEntry(int $stockRowId, float $amount, $bestBeforeDate, $locationId, $shoppingLocationId, $price, $open, $purchasedDate)
|
public function EditStockEntry(int $stockRowId, float $amount, $bestBeforeDate, $locationId, $shoppingLocationId, $price, $open, $purchasedDate, $quFactorPurchaseToStock)
|
||||||
{
|
{
|
||||||
|
|
||||||
$stockRow = $this->getDatabase()->stock()->where('id = :1', $stockRowId)->fetch();
|
$stockRow = $this->getDatabase()->stock()->where('id = :1', $stockRowId)->fetch();
|
||||||
@ -621,6 +627,7 @@ class StockService extends BaseService
|
|||||||
'opened_date' => $stockRow->opened_date,
|
'opened_date' => $stockRow->opened_date,
|
||||||
'location_id' => $stockRow->location_id,
|
'location_id' => $stockRow->location_id,
|
||||||
'shopping_location_id' => $stockRow->shopping_location_id,
|
'shopping_location_id' => $stockRow->shopping_location_id,
|
||||||
|
'qu_factor_purchase_to_stock' => $stockRow->qu_factor_purchase_to_stock,
|
||||||
'correlation_id' => $correlationId,
|
'correlation_id' => $correlationId,
|
||||||
'transaction_id' => $transactionId,
|
'transaction_id' => $transactionId,
|
||||||
'stock_row_id' => $stockRow->id
|
'stock_row_id' => $stockRow->id
|
||||||
@ -645,6 +652,7 @@ class StockService extends BaseService
|
|||||||
'shopping_location_id' => $shoppingLocationId,
|
'shopping_location_id' => $shoppingLocationId,
|
||||||
'opened_date' => $openedDate,
|
'opened_date' => $openedDate,
|
||||||
'open' => $open,
|
'open' => $open,
|
||||||
|
'qu_factor_purchase_to_stock' => $quFactorPurchaseToStock,
|
||||||
'purchased_date' => $purchasedDate
|
'purchased_date' => $purchasedDate
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -659,6 +667,7 @@ class StockService extends BaseService
|
|||||||
'opened_date' => $stockRow->opened_date,
|
'opened_date' => $stockRow->opened_date,
|
||||||
'location_id' => $locationId,
|
'location_id' => $locationId,
|
||||||
'shopping_location_id' => $shoppingLocationId,
|
'shopping_location_id' => $shoppingLocationId,
|
||||||
|
'qu_factor_purchase_to_stock' => $stockRow->qu_factor_purchase_to_stock,
|
||||||
'correlation_id' => $correlationId,
|
'correlation_id' => $correlationId,
|
||||||
'transaction_id' => $transactionId,
|
'transaction_id' => $transactionId,
|
||||||
'stock_row_id' => $stockRow->id
|
'stock_row_id' => $stockRow->id
|
||||||
@ -672,7 +681,7 @@ class StockService extends BaseService
|
|||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
throw new \Exception('Product does not exist');
|
throw new \Exception('Product does not exist or is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
$productDetails = (object)$this->GetProductDetails($productId);
|
$productDetails = (object)$this->GetProductDetails($productId);
|
||||||
@ -728,7 +737,7 @@ class StockService extends BaseService
|
|||||||
{
|
{
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
throw new \Exception('Product does not exist');
|
throw new \Exception('Product does not exist or is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
$productStockAmountUnopened = $this->getDatabase()->stock()->where('product_id = :1 AND open = 0', $productId)->sum('amount');
|
$productStockAmountUnopened = $this->getDatabase()->stock()->where('product_id = :1 AND open = 0', $productId)->sum('amount');
|
||||||
@ -908,7 +917,7 @@ class StockService extends BaseService
|
|||||||
|
|
||||||
if (!$this->ProductExists($productId))
|
if (!$this->ProductExists($productId))
|
||||||
{
|
{
|
||||||
throw new \Exception('Product does not exist');
|
throw new \Exception('Product does not exist or is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
$alreadyExistingEntry = $this->getDatabase()->shopping_list()->where('product_id = :1 AND shopping_list_id = :2', $productId, $listId)->fetch();
|
$alreadyExistingEntry = $this->getDatabase()->shopping_list()->where('product_id = :1 AND shopping_list_id = :2', $productId, $listId)->fetch();
|
||||||
@ -934,7 +943,7 @@ class StockService extends BaseService
|
|||||||
|
|
||||||
private function ProductExists($productId)
|
private function ProductExists($productId)
|
||||||
{
|
{
|
||||||
$productRow = $this->getDatabase()->products()->where('id = :1', $productId)->fetch();
|
$productRow = $this->getDatabase()->products()->where('id = :1 and active = 1', $productId)->fetch();
|
||||||
return $productRow !== null;
|
return $productRow !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1145,6 +1154,7 @@ class StockService extends BaseService
|
|||||||
'best_before_date' => $logRow->best_before_date,
|
'best_before_date' => $logRow->best_before_date,
|
||||||
'purchased_date' => $logRow->purchased_date,
|
'purchased_date' => $logRow->purchased_date,
|
||||||
'price' => $logRow->price,
|
'price' => $logRow->price,
|
||||||
|
'qu_factor_purchase_to_stock' => $logRow->qu_factor_purchase_to_stock,
|
||||||
'location_id' => $logRow->location_id,
|
'location_id' => $logRow->location_id,
|
||||||
'open' => $open,
|
'open' => $open,
|
||||||
'opened_date' => $openedDate
|
'opened_date' => $openedDate
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
@php if(!isset($isRequired)) { $isRequired = true; } @endphp
|
@php if(!isset($isRequired)) { $isRequired = true; } @endphp
|
||||||
@php if(!isset($noNameAttribute)) { $noNameAttribute = false; } @endphp
|
@php if(!isset($noNameAttribute)) { $noNameAttribute = false; } @endphp
|
||||||
|
|
||||||
<div class="form-group {{ $additionalGroupCssClasses }}">
|
<div id="group-{{ $id }}" class="form-group {{ $additionalGroupCssClasses }}">
|
||||||
<label for="{{ $id }}">
|
<label for="{{ $id }}">
|
||||||
{{ $__t($label) }}
|
{{ $__t($label) }}
|
||||||
<i class="fas fa-question-circle" id="{{ $hintId }}" data-toggle="tooltip" title="{{ $hint }}"></i>{!! $additionalHtmlContextHelp !!}</label>
|
<i class="fas fa-question-circle" id="{{ $hintId }}" data-toggle="tooltip" title="{{ $hint }}"></i>{!! $additionalHtmlContextHelp !!}</label>
|
||||||
|
@ -21,12 +21,16 @@
|
|||||||
<a class="collapsed" data-toggle="collapse" href="#productcard-product-description">{{ $__t('Show more') }}</a>
|
<a class="collapsed" data-toggle="collapse" href="#productcard-product-description">{{ $__t('Show more') }}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<strong>{{ $__t('Stock amount') . ' / ' . $__t('Quantity unit') }}:</strong> <span id="productcard-product-stock-amount" class="locale-number locale-number-quantity-amount"></span> <span id="productcard-product-stock-qu-name"></span> <span id="productcard-product-stock-opened-amount" class="small font-italic locale-number locale-number-quantity-amount"></span>
|
<strong>{{ $__t('Stock amount') }}:</strong> <span id="productcard-product-stock-amount" class="locale-number locale-number-quantity-amount"></span> <span id="productcard-product-stock-qu-name"></span>
|
||||||
|
<span id="productcard-product-stock-factor-purchase-amount" class="locale-number locale-number-quantity-amount"></span> <span id="productcard-product-stock-factor-purchase-qu-name"></span>
|
||||||
|
<span id="productcard-product-stock-opened-amount" class="small font-italic locale-number locale-number-quantity-amount"></span><br>
|
||||||
|
<strong>{{ $__t('Stock value') }}:</strong> <span id="productcard-product-stock-value" class="locale-number locale-number-currency"></span>
|
||||||
<span id="productcard-aggregated-amounts" class="pl-2 text-secondary d-none"><i class="fas fa-custom-sigma-sign"></i> <span id="productcard-product-stock-amount-aggregated" class="locale-number locale-number-quantity-amount"></span> <span id="productcard-product-stock-qu-name-aggregated"></span> <span id="productcard-product-stock-opened-amount-aggregated locale-number locale-number-quantity-amount" class="small font-italic"></span></span><br>
|
<span id="productcard-aggregated-amounts" class="pl-2 text-secondary d-none"><i class="fas fa-custom-sigma-sign"></i> <span id="productcard-product-stock-amount-aggregated" class="locale-number locale-number-quantity-amount"></span> <span id="productcard-product-stock-qu-name-aggregated"></span> <span id="productcard-product-stock-opened-amount-aggregated locale-number locale-number-quantity-amount" class="small font-italic"></span></span><br>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)<strong>{{ $__t('Default location') }}:</strong> <span id="productcard-product-location"></span><br>@endif
|
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)<strong>{{ $__t('Default location') }}:</strong> <span id="productcard-product-location"></span><br>@endif
|
||||||
<strong>{{ $__t('Last purchased') }}:</strong> <span id="productcard-product-last-purchased"></span> <time id="productcard-product-last-purchased-timeago" class="timeago timeago-contextual"></time><br>
|
<strong>{{ $__t('Last purchased') }}:</strong> <span id="productcard-product-last-purchased"></span> <time id="productcard-product-last-purchased-timeago" class="timeago timeago-contextual"></time><br>
|
||||||
<strong>{{ $__t('Last used') }}:</strong> <span id="productcard-product-last-used"></span> <time id="productcard-product-last-used-timeago" class="timeago timeago-contextual"></time><br>
|
<strong>{{ $__t('Last used') }}:</strong> <span id="productcard-product-last-used"></span> <time id="productcard-product-last-used-timeago" class="timeago timeago-contextual"></time><br>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)<strong>{{ $__t('Last price') }}:</strong> <span id="productcard-product-last-price"></span><br>@endif
|
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)<strong>{{ $__t('Last price') }}:</strong> <span id="productcard-product-last-price"></span><br>@endif
|
||||||
|
@if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)<strong>{{ $__t('Average price') }}:</strong> <span id="productcard-product-average-price"></span><br>@endif
|
||||||
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)<strong>{{ $__t('Average shelf life') }}:</strong> <span id="productcard-product-average-shelf-life"></span><br>@endif
|
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)<strong>{{ $__t('Average shelf life') }}:</strong> <span id="productcard-product-average-shelf-life"></span><br>@endif
|
||||||
<strong>{{ $__t('Spoil rate') }}:</strong> <span id="productcard-product-spoil-rate"></span>
|
<strong>{{ $__t('Spoil rate') }}:</strong> <span id="productcard-product-spoil-rate"></span>
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<select class="form-control product-combobox barcodescanner-input" id="product_id" name="product_id" @if($isRequired) required @endif @if($disabled) disabled @endif data-target="@productpicker">
|
<select class="form-control product-combobox barcodescanner-input" id="product_id" name="product_id" @if($isRequired) required @endif @if($disabled) disabled @endif data-target="@productpicker">
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
@foreach($products as $product)
|
@foreach($products as $product)
|
||||||
<option data-additional-searchdata="{{ $product->barcode }}@if(!empty($product->barcode)),@endif" value="{{ $product->id }}">{{ $product->name }}</option>
|
<option data-additional-searchdata="{{ FindObjectInArrayByPropertyValue($barcodes, 'product_id', $product->id)->barcodes }}," value="{{ $product->id }}">{{ $product->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
<div class="invalid-feedback">{{ $__t('You have to select a product') }}</div>
|
<div class="invalid-feedback">{{ $__t('You have to select a product') }}</div>
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', array(
|
||||||
'products' => $products,
|
'products' => $products,
|
||||||
|
'barcodes' => $barcodes,
|
||||||
'nextInputSelector' => '#amount',
|
'nextInputSelector' => '#amount',
|
||||||
'disallowAddProductWorkflows' => true
|
'disallowAddProductWorkflows' => true
|
||||||
))
|
))
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', array(
|
||||||
'products' => $products,
|
'products' => $products,
|
||||||
|
'barcodes' => $barcodes,
|
||||||
'nextInputSelector' => '#new_amount'
|
'nextInputSelector' => '#new_amount'
|
||||||
))
|
))
|
||||||
|
|
||||||
|
71
views/productbarcodesform.blade.php
Normal file
71
views/productbarcodesform.blade.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
@extends('layout.default')
|
||||||
|
|
||||||
|
@if($mode == 'edit')
|
||||||
|
@section('title', $__t('Edit Barcode'))
|
||||||
|
@else
|
||||||
|
@section('title', $__t('Create Barcode'))
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@section('viewJsName', 'productbarcodesform')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<h2 class="title">@yield('title')</h2>
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6 col-xs-12">
|
||||||
|
|
||||||
|
<h3 class="text-muted">{{ $__t('Barcode for product') }} <strong>{{ $product->name }}</strong></h3>
|
||||||
|
|
||||||
|
<script>Grocy.EditMode = '{{ $mode }}';</script>
|
||||||
|
|
||||||
|
@if($mode == 'edit')
|
||||||
|
<script>Grocy.EditObjectId = {{ $barcode->id }};</script>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<form id="barcode-form" novalidate>
|
||||||
|
|
||||||
|
<input type="hidden" name="product_id" value="{{ $product->id }}">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">{{ $__t('Barcode') }}<i class="fas fa-barcode"></i></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control barcodescanner-input" required id="barcode" name="barcode" value="@if($mode == 'edit'){{ $barcode->barcode }}@endif" data-target="#scanned_barcode">
|
||||||
|
@include('components.barcodescanner')
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@php if($mode == 'edit') { $value = $barcode->qu_factor_purchase_to_stock; } else { $value = 1; } @endphp
|
||||||
|
@include('components.numberpicker', array(
|
||||||
|
'id' => 'qu_factor_purchase_to_stock',
|
||||||
|
'label' => 'Factor purchase to stock quantity unit',
|
||||||
|
'min' => 1,
|
||||||
|
'value' => $value,
|
||||||
|
'isRequired' => true,
|
||||||
|
'invalidFeedback' => $__t('The amount cannot be lower than %s', '1'),
|
||||||
|
'additionalCssClasses' => 'input-group-qu',
|
||||||
|
))
|
||||||
|
|
||||||
|
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="shopping_location_id_id">{{ $__t('Default store') }}</label>
|
||||||
|
<select class="form-control" id="shopping_location_id" name="shopping_location_id">
|
||||||
|
<option></option>
|
||||||
|
@foreach($shoppinglocations as $store)
|
||||||
|
<option @if($mode == 'edit' && $store->id == $product->shopping_location_id) selected="selected" @endif value="{{ $store->id }}">{{ $store->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<input type="hidden" name="shopping_location_id" id="shopping_location_id" value="1">
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<button id="save-barcode-button" class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@stop
|
@ -46,6 +46,14 @@
|
|||||||
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="hidden" name="active" value="1">
|
||||||
|
<input @if($mode == 'create') checked @elseif($mode == 'edit' && $product->active == 1) checked @endif class="form-check-input" type="checkbox" id="active" name="active" value="1">
|
||||||
|
<label class="form-check-label" for="active">{{ $__t('Active') }}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@php $prefillById = ''; if($mode=='edit') { $prefillById = $product->parent_product_id; } @endphp
|
@php $prefillById = ''; if($mode=='edit') { $prefillById = $product->parent_product_id; } @endphp
|
||||||
@php
|
@php
|
||||||
$hint = '';
|
$hint = '';
|
||||||
@ -56,7 +64,6 @@
|
|||||||
@endphp
|
@endphp
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', array(
|
||||||
'products' => $products,
|
'products' => $products,
|
||||||
'nextInputSelector' => '#barcode-taginput',
|
|
||||||
'prefillById' => $prefillById,
|
'prefillById' => $prefillById,
|
||||||
'disallowAllProductWorkflows' => true,
|
'disallowAllProductWorkflows' => true,
|
||||||
'isRequired' => false,
|
'isRequired' => false,
|
||||||
@ -70,14 +77,6 @@
|
|||||||
<textarea class="form-control wysiwyg-editor" id="description" name="description">@if($mode == 'edit'){{ $product->description }}@endif</textarea>
|
<textarea class="form-control wysiwyg-editor" id="description" name="description">@if($mode == 'edit'){{ $product->description }}@endif</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group tm-group">
|
|
||||||
<label for="barcode-taginput">{{ $__t('Barcode(s)') }} <i class="fas fa-barcode"></i></label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control tm-input barcodescanner-input" id="barcode-taginput" data-target="#barcode-taginput">
|
|
||||||
</div>
|
|
||||||
<div id="barcode-taginput-container"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="location_id">{{ $__t('Default location') }}</label>
|
<label for="location_id">{{ $__t('Default location') }}</label>
|
||||||
@ -171,7 +170,8 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="qu_id_stock">{{ $__t('Quantity unit stock') }}</label>
|
<label for="qu_id_stock">{{ $__t('Quantity unit stock') }}</label>
|
||||||
<select required class="form-control input-group-qu" id="qu_id_stock" name="qu_id_stock">
|
<i class="fas fa-question-circle" data-toggle="tooltip" title="Quantity unit stock cannot be changed after first purchase"></i>
|
||||||
|
<select required class="form-control input-group-qu" id="qu_id_stock" name="qu_id_stock" @if($mode == 'edit') disabled @endif>
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($quantityunits as $quantityunit)
|
@foreach($quantityunits as $quantityunit)
|
||||||
<option @if($mode == 'edit' && $quantityunit->id == $product->qu_id_stock) selected="selected" @endif value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">{{ $quantityunit->name }}</option>
|
<option @if($mode == 'edit' && $quantityunit->id == $product->qu_id_stock) selected="selected" @endif value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">{{ $quantityunit->name }}</option>
|
||||||
@ -295,7 +295,7 @@
|
|||||||
<div class="col-lg-6 col-xs-12">
|
<div class="col-lg-6 col-xs-12">
|
||||||
<h2>
|
<h2>
|
||||||
{{ $__t('QU conversions') }}
|
{{ $__t('QU conversions') }}
|
||||||
<a id="qu-conversion-add-button" class="btn btn-outline-dark" href="#">
|
<a class="btn btn-outline-dark show-as-dialog-link" type="button" href="{{ $U('/quantityunitconversion/new?embedded&product=' . $product->id ) }}">
|
||||||
<i class="fas fa-plus"></i> {{ $__t('Add') }}
|
<i class="fas fa-plus"></i> {{ $__t('Add') }}
|
||||||
</a>
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
@ -316,7 +316,7 @@
|
|||||||
@if($quConversion->product_id == $product->id || $quConversion->product_id == null)
|
@if($quConversion->product_id == $product->id || $quConversion->product_id == null)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-sm btn-info qu-conversion-edit-button @if($quConversion->product_id == null) disabled @endif" href="#" data-qu-conversion-id="{{ $quConversion->id }}">
|
<a class="btn btn-sm btn-info show-as-dialog-link @if($quConversion->product_id == null) disabled @endif" href="{{ $U('/quantityunitconversion/' . $quConversion->id . '?embedded&product=' . $product->id ) }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-danger qu-conversion-delete-button @if($quConversion->product_id == null) disabled @endif" href="#" data-qu-conversion-id="{{ $quConversion->id }}">
|
<a class="btn btn-sm btn-danger qu-conversion-delete-button @if($quConversion->product_id == null) disabled @endif" href="#" data-qu-conversion-id="{{ $quConversion->id }}">
|
||||||
@ -346,6 +346,55 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
{{ $__t('Barcodes') }}
|
||||||
|
<a class="btn btn-outline-dark show-as-dialog-link" type="button" href="{{ $U('/productbarcodes/new?embedded&product=' . $product->id ) }}">
|
||||||
|
<i class="fas fa-plus"></i> {{ $__t('Add') }}
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
<h5 id="barcode-headline-info" class="text-muted font-italic"></h5>
|
||||||
|
<table id="barcode-table" class="table table-sm table-striped dt-responsive">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="border-right"></th>
|
||||||
|
<th>{{ $__t('Barcode') }}</th>
|
||||||
|
<th>{{ $__t('Factor purchase to stock quantity unit') }}</th>
|
||||||
|
<th>{{ $__t('Store') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="d-none">
|
||||||
|
@if($mode == "edit")
|
||||||
|
@foreach($barcodes as $barcode)
|
||||||
|
@if($barcode->product_id == $product->id || $barcode->product_id == null)
|
||||||
|
<tr>
|
||||||
|
<td class="fit-content border-right">
|
||||||
|
<a class="btn btn-sm btn-info show-as-dialog-link @if($barcode->product_id == null) disabled @endif" href="{{ $U('/productbarcodes/' . $barcode->id . '?embedded&product=' . $product->id ) }}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-sm btn-danger barcode-delete-button @if($barcode->product_id == null) disabled @endif" href="#" data-barcode-id="{{ $barcode->id }}" data-barcode="{{ $barcode->barcode }}" data-product-barcode="{{ $product->barcode }}" data-product-id="{{ $product->id }}">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ $barcode->barcode }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="locale-number locale-number-quantity-amount">{{ $barcode->qu_factor_purchase_to_stock }}</span>
|
||||||
|
</td>
|
||||||
|
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
|
<td id="barcode-shopping-location">
|
||||||
|
@if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $barcode->shopping_location_id) !== null)
|
||||||
|
{{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $barcode->shopping_location_id)->name }}
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
@endif
|
||||||
|
</tr>
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
<div class="pt-5">
|
<div class="pt-5">
|
||||||
<label class="mt-2">{{ $__t('Picture') }}</label>
|
<label class="mt-2">{{ $__t('Picture') }}</label>
|
||||||
<button id="delete-current-product-picture-button" class="btn btn-sm btn-danger @if(empty($product->picture_file_name)) disabled @endif"><i class="fas fa-trash"></i> {{ $__t('Delete') }}</button>
|
<button id="delete-current-product-picture-button" class="btn btn-sm btn-danger @if(empty($product->picture_file_name)) disabled @endif"><i class="fas fa-trash"></i> {{ $__t('Delete') }}</button>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<div class="row mt-3">
|
<div class="row mt-3">
|
||||||
<div class="col-xs-12 col-md-2 col-xl-1">
|
<div class="col-xs-12 col-md-2 col-xl-1">
|
||||||
<a class="btn btn-primary btn-sm responsive-button w-100 mb-3" href="{{ $U('/productgroup/new') }}">
|
<a class="btn btn-primary btn-sm responsive-button w-100 mb-3 show-as-dialog-link" href="{{ $U('/productgroup/new?embedded') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -55,7 +55,7 @@
|
|||||||
@foreach($productGroups as $productGroup)
|
@foreach($productGroups as $productGroup)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm" href="{{ $U('/productgroup/') }}{{ $productGroup->id }}">
|
<a class="btn btn-info btn-sm show-as-dialog-link" href="{{ $U('/productgroup/') }}{{ $productGroup->id }}?embedded">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm product-group-delete-button" href="#" data-group-id="{{ $productGroup->id }}" data-group-name="{{ $productGroup->name }}">
|
<a class="btn btn-danger btn-sm product-group-delete-button" href="#" data-group-id="{{ $productGroup->id }}" data-group-name="{{ $productGroup->name }}">
|
||||||
|
@ -81,12 +81,12 @@
|
|||||||
<a class="btn btn-info btn-sm" href="{{ $U('/product/') }}{{ $product->id }}">
|
<a class="btn btn-info btn-sm" href="{{ $U('/product/') }}{{ $product->id }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm product-delete-button" href="#" data-product-id="{{ $product->id }}" data-product-name="{{ $product->name }}">
|
<a class="btn btn-danger btn-sm product-delete-button @if($product->active == 0) disabled @endif" href="#" data-product-id="{{ $product->id }}" data-product-name="{{ $product->name }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $product->name }}@if(!empty($product->picture_file_name)) <i class="fas fa-image text-muted"></i>@endif
|
@if($product->active == 0) (deactivated) @endif {{ $product->name }}@if(!empty($product->picture_file_name)) <i class="fas fa-image text-muted"></i>@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
||||||
{{ FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name }}
|
{{ FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name }}
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', array(
|
||||||
'products' => $products,
|
'products' => $products,
|
||||||
|
'barcodes' => $barcodes,
|
||||||
'nextInputSelector' => '#amount'
|
'nextInputSelector' => '#amount'
|
||||||
))
|
))
|
||||||
|
|
||||||
@ -96,6 +97,16 @@
|
|||||||
<input type="hidden" name="price" id="price" value="0">
|
<input type="hidden" name="price" id="price" value="0">
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@include('components.numberpicker', array(
|
||||||
|
'id' => 'qu_factor_purchase_to_stock',
|
||||||
|
'label' => 'Factor purchase to stock quantity unit',
|
||||||
|
'min' => 1,
|
||||||
|
'additionalGroupCssClasses' => 'd-none',
|
||||||
|
'invalidFeedback' => $__t('The amount cannot be lower than %s', '1'),
|
||||||
|
'additionalCssClasses' => 'input-group-qu',
|
||||||
|
'additionalHtmlElements' => '<p id="qu-conversion-info" class="form-text text-muted small d-none"></p>'
|
||||||
|
))
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
@include('components.locationpicker', array(
|
@include('components.locationpicker', array(
|
||||||
'locations' => $locations,
|
'locations' => $locations,
|
||||||
|
@ -134,7 +134,7 @@
|
|||||||
<h5 class="card-title mb-1">{{ $recipe->name }}</h5>
|
<h5 class="card-title mb-1">{{ $recipe->name }}</h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
@if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
|
@if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
|
||||||
<span class="timeago-contextual">@if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1){{ $__t('Enough in stock') }}@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1){{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count, 'Not enough in stock, %s ingredient missing but already on the shopping list', 'Not enough in stock, %s ingredients missing but already on the shopping list') }}@else{{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count, 'Not enough in stock, %s ingredient missing', 'Not enough in stock, %s ingredients missing') }}@endif</span>
|
<span class="timeago-contextual">@if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1){{ $__t('Enough in stock') }}@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1){{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count, 'Not enough in stock, %s ingredient missing but already on the shopping list', 'Not enough in stock, %s ingredients missing but already on the shopping list') }}@else{{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count, 'Not enough in stock (not included in costs), %s ingredient missing', 'Not enough in stock (not included in costs), %s ingredients missing') }}@endif</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -250,7 +250,7 @@
|
|||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<label>{{ $__t('Costs') }} </label>
|
<label>{{ $__t('Costs') }} </label>
|
||||||
<i class="fas fa-question-circle" data-toggle="tooltip" title="{{ $__t('Based on the prices of the last purchase per product') }}"></i>
|
<i class="fas fa-question-circle" data-toggle="tooltip" title="{{ $__t('Based on the prices of the default consume rule which is "First expiring first, then first in first out"') }}"></i>
|
||||||
<h3 class="locale-number locale-number-currency pt-0">{{ $costs }}</h3>
|
<h3 class="locale-number locale-number-currency pt-0">{{ $costs }}</h3>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@ -310,6 +310,9 @@
|
|||||||
<h6 class="mb-2 mt-2 @if($hasIngredientGroups) ml-3 @else ml-1 @endif"><strong>{{ $selectedRecipePosition->product_group }}</strong></h6>
|
<h6 class="mb-2 mt-2 @if($hasIngredientGroups) ml-3 @else ml-1 @endif"><strong>{{ $selectedRecipePosition->product_group }}</strong></h6>
|
||||||
@endif
|
@endif
|
||||||
<li class="list-group-item px-0 @if($hasIngredientGroups && $hasProductGroups) ml-4 @elseif($hasIngredientGroups || $hasProductGroups) ml-2 @else ml-0 @endif">
|
<li class="list-group-item px-0 @if($hasIngredientGroups && $hasProductGroups) ml-4 @elseif($hasIngredientGroups || $hasProductGroups) ml-2 @else ml-0 @endif">
|
||||||
|
@if($selectedRecipePosition->product_active == 0)
|
||||||
|
<div class="small text-muted font-italic">{{ $__t('Deactivated Product') }}</div>
|
||||||
|
@endif
|
||||||
@php
|
@php
|
||||||
$product = FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id);
|
$product = FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id);
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
||||||
@ -327,7 +330,7 @@
|
|||||||
@endif
|
@endif
|
||||||
{{ $__n($selectedRecipePosition->recipe_amount, FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name_plural) }} {{ FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id)->name }}
|
{{ $__n($selectedRecipePosition->recipe_amount, FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name_plural) }} {{ FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id)->name }}
|
||||||
@if($selectedRecipePosition->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif($selectedRecipePosition->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
|
@if($selectedRecipePosition->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif($selectedRecipePosition->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
|
||||||
<span class="timeago-contextual">@if(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->need_fulfilled == 1) {{ $__t('Enough in stock') }} @else {{ $__t('Not enough in stock, %1$s missing, %2$s already on shopping list', round(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->missing_amount, 2), round(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->amount_on_shopping_list, 2)) }} @endif</span>
|
<span class="timeago-contextual">@if(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->need_fulfilled == 1) {{ $__t('Enough in stock') }} @else {{ $__t('Not enough in stock (not included in costs), %1$s missing, %2$s already on shopping list', round(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->missing_amount, 2), round(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->amount_on_shopping_list, 2)) }} @endif</span>
|
||||||
|
|
||||||
@if(!empty($selectedRecipePosition->recipe_variable_amount))
|
@if(!empty($selectedRecipePosition->recipe_variable_amount))
|
||||||
<div class="small text-muted font-italic">{{ $__t('Variable amount') }}</div>
|
<div class="small text-muted font-italic">{{ $__t('Variable amount') }}</div>
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
<th>{{ $__t('Store') }}</th>
|
<th>{{ $__t('Store') }}</th>
|
||||||
<th>{{ $__t('Price') }}</th>
|
<th>{{ $__t('Price') }}</th>
|
||||||
@endif
|
@endif
|
||||||
|
<th>{{ $__t('Factor purchase to stock') }}</th>
|
||||||
<th>{{ $__t('Purchased date') }}</th>
|
<th>{{ $__t('Purchased date') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', array(
|
||||||
@ -158,6 +159,9 @@
|
|||||||
{{ $stockEntry->price }}
|
{{ $stockEntry->price }}
|
||||||
</td>
|
</td>
|
||||||
@endif
|
@endif
|
||||||
|
<td id="stock-{{ $stockEntry->id }}-qu-factor-purchase-to-stock">
|
||||||
|
{{ $stockEntry->qu_factor_purchase_to_stock }}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span id="stock-{{ $stockEntry->id }}-purchased-date">{{ $stockEntry->purchased_date }}</span>
|
<span id="stock-{{ $stockEntry->id }}-purchased-date">{{ $stockEntry->purchased_date }}</span>
|
||||||
<time id="stock-{{ $stockEntry->id }}-purchased-date-timeago" class="timeago timeago-contextual" datetime="{{ $stockEntry->purchased_date }} 23:59:59"></time>
|
<time id="stock-{{ $stockEntry->id }}-purchased-date-timeago" class="timeago timeago-contextual" datetime="{{ $stockEntry->purchased_date }} 23:59:59"></time>
|
||||||
|
@ -60,6 +60,16 @@
|
|||||||
'additionalHtmlContextHelp' => '<div id="tare-weight-handling-info" class="text-small text-info font-italic d-none">' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '</div>'
|
'additionalHtmlContextHelp' => '<div id="tare-weight-handling-info" class="text-small text-info font-italic d-none">' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '</div>'
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@include('components.numberpicker', array(
|
||||||
|
'id' => 'qu_factor_purchase_to_stock',
|
||||||
|
'label' => 'Factor purchase to stock quantity unit',
|
||||||
|
'value' => $stockEntry->qu_factor_purchase_to_stock,
|
||||||
|
'min' => 1,
|
||||||
|
'invalidFeedback' => $__t('The amount cannot be lower than %s', '1'),
|
||||||
|
'additionalCssClasses' => 'input-group-qu',
|
||||||
|
'additionalHtmlElements' => '<p id="qu-conversion-info" class="form-text text-muted small d-none"></p>'
|
||||||
|
))
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', array(
|
||||||
'id' => 'price',
|
'id' => 'price',
|
||||||
|
@ -104,11 +104,11 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"></th>
|
<th class="border-right"></th>
|
||||||
<th>{{ $__t('Product') }}</th>
|
<th>{{ $__t('Product') }}</th>
|
||||||
|
<th>{{ $__t('Product group') }}</th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">{{ $__t('Next best before date') }}</th>
|
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">{{ $__t('Next best before date') }}</th>
|
||||||
<th class="d-none">Hidden location</th>
|
<th class="d-none">Hidden location</th>
|
||||||
<th class="d-none">Hidden status</th>
|
<th class="d-none">Hidden status</th>
|
||||||
<th class="d-none">Hidden product group</th>
|
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', array(
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields
|
||||||
@ -206,9 +206,16 @@
|
|||||||
<td class="product-name-cell cursor-link" data-product-id="{{ $currentStockEntry->product_id }}">
|
<td class="product-name-cell cursor-link" data-product-id="{{ $currentStockEntry->product_id }}">
|
||||||
{{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }}
|
{{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }}
|
||||||
</td>
|
</td>
|
||||||
|
@php $productGroup = FindObjectInArrayByPropertyValue($productGroups, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->product_group_id) @endphp
|
||||||
|
<td>
|
||||||
|
@if($productGroup !== null){{ $productGroup->name }}@endif
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-amount" class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__n($currentStockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural) }}</span>
|
<span id="product-{{ $currentStockEntry->product_id }}-amount" class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__n($currentStockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural) }}</span>
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-opened-amount" class="small font-italic">@if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif</span>
|
<span id="product-{{ $currentStockEntry->product_id }}-opened-amount" class="small font-italic">@if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif</span>
|
||||||
|
@if($currentStockEntry->amount != $currentStockEntry->factor_purchase_amount)
|
||||||
|
<span id="product-{{ $currentStockEntry->product_id }}-factor-purchase-amount" class="locale-number locale-number-quantity-amount">({{ $currentStockEntry->factor_purchase_amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-purchase-name">{{ $__n($currentStockEntry->factor_purchase_amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_purchase)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_purchase)->name_plural) }})</span>
|
||||||
|
@endif
|
||||||
@if($currentStockEntry->is_aggregated_amount == 1)
|
@if($currentStockEntry->is_aggregated_amount == 1)
|
||||||
<span class="pl-1 text-secondary">
|
<span class="pl-1 text-secondary">
|
||||||
<i class="fas fa-custom-sigma-sign"></i> <span id="product-{{ $currentStockEntry->product_id }}-amount-aggregated" class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount_aggregated }}</span> {{ $__n($currentStockEntry->amount_aggregated, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural) }}
|
<i class="fas fa-custom-sigma-sign"></i> <span id="product-{{ $currentStockEntry->product_id }}-amount-aggregated" class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount_aggregated }}</span> {{ $__n($currentStockEntry->amount_aggregated, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural) }}
|
||||||
@ -236,10 +243,6 @@
|
|||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
@if($currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $currentStockEntry->amount > 0) expired @elseif($currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime("+$nextXDays days")) && $currentStockEntry->amount > 0) expiring @endif @if(FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) belowminstockamount @endif
|
@if($currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $currentStockEntry->amount > 0) expired @elseif($currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime("+$nextXDays days")) && $currentStockEntry->amount > 0) expiring @endif @if(FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) belowminstockamount @endif
|
||||||
</td>
|
</td>
|
||||||
@php $productGroup = FindObjectInArrayByPropertyValue($productGroups, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->product_group_id) @endphp
|
|
||||||
<td class="d-none">
|
|
||||||
@if($productGroup !== null){{ $productGroup->name }}@endif
|
|
||||||
</td>
|
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', array(
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', array(
|
||||||
'products' => $products,
|
'products' => $products,
|
||||||
|
'barcodes' => $barcodes,
|
||||||
'nextInputSelector' => '#location_id_from',
|
'nextInputSelector' => '#location_id_from',
|
||||||
'disallowAddProductWorkflows' => true
|
'disallowAddProductWorkflows' => true
|
||||||
))
|
))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user