grocy 3.2.0 升级全解析库存阈值重构、菜谱 Grocycode 与家务调度的实战指南【免费下载链接】grocyERP beyond your fridge - Grocy is a web-based self-hosted groceries household management solution for your home项目地址: https://gitcode.com/GitHub_Trending/gr/grocy本篇文章基于 grocy 仓库中 3.2.0 发布记录逐模块解读这次版本的完整变更库存模块将开启即缺货从全局配置下沉为产品级选项菜谱成本核算改用缺货商品的最近价格并新增菜谱 Grocycode家务调度引入跳过、起始日期与 Hourly/Adaptive 周期类型同时收尾了一系列 API 参数与认证配置增强。读完你不仅清楚每个新功能的操作入口与配置项还能透过 migrations 与 services 源码理解其底层实现与升级迁移行为。版本概览与升级须知grocy 3.2.0 是一次覆盖面很广的功能增强版本涉及 Stock、Recipes、Meal plan、Chores、Calendar、Tasks、General 与 API 八个模块。绝大多数变更都带有自动迁移逻辑升级后行为不会发生意外变化这是本版升级最值得关注的一点原全局开关FEATURE_SETTING_STOCK_COUNT_OPENED_PRODUCTS_AGAINST_MINIMUM_STOCK_AMOUNT被移除其值迁移为所有现有产品的新选项Treat opened as out of stock所有已有家务Chores自动获得start_date取首次执行时间从未执行过则取当天所有Yearly周期家务自动转换为Daily 365 天间隔所有Dynamic regular周期家务自动转换为Daily。这些迁移均可在仓库的 SQL 迁移文件中逐条对应验证下文会结合源码逐一展开。Stock 库存模块Treat opened as out of stock从全局开关到产品级选项3.2.0 之前是否将已开启的库存条目计为缺货由config.php中的全局选项FEATURE_SETTING_STOCK_COUNT_OPENED_PRODUCTS_AGAINST_MINIMUM_STOCK_AMOUNT统一控制。本版本将其移除改为每个产品独立的选项Treat opened as out of stock即当某产品已有已开启opened的库存条目时是否把这些条目计为缺失用于判断该产品是否低于其最低库存量min. stock amount。升级时该配置会被迁移到所有现有产品同时新增的默认值也可以预先配置在库存设置Stock settings的 Presets for new products新产品预设一节中新增了对应默认项。仓库中的 config-dist.php 记录了这个默认用户设置DefaultUserSetting(product_presets_treat_opened_as_out_of_stock, true); // Default Treat opened as out of stock option for new products即新添加产品的该选项默认开启true保持与旧全局开关一致的默认行为。该字段也暴露在 OpenAPI 定义中见 grocy.openapi.json可通过 API 按产品读写。消费页 Grocycode 扫描预填库存数量在消费Consume页面使用/扫描库存条目 Grocycode即带库存条目 ID 的 Grocycode时数量输入框现在会自动预填该库存条目的数量这意味着可以一次性消费掉对应库存条目无需手动输入数量特别适合扫一个吃一个的流程化操作。盘点时的库存标签打印库存条目标签stock entry label现在在**盘点Inventory**页面也会打印——但仅在添加产品时生效并复用与采购页相同的 Stock entry label 选项。同时修复了一个问题此前在服务端运行标签打印机 WebHook 时即使选择了 No label无标签采购页仍会打印标签现在该场景已被正确抑制。其他修复库存概览页上默认隐藏的产品描述列中的格式化 HTML 文本现在能正确渲染修复库存条目stock entries页面上数字列与日期时间列排序不正确的问题修复从库存条目页打开消费页/对话框时初始化不完整的问题修复库存日志stock journal中缺少不存在用户对应条目即用户被删除后历史记录仍应可见的问题。Recipes 菜谱模块成本计算优化缺货原料使用最近一次价格这是本版菜谱模块最核心的行为变更。背景逻辑如下v3.0.0 之前菜谱成本仅基于每个产品的最近价格last price计算自 v3.0.0 起改为基于真实成本real costs即按默认消费规则Opened first, then first due first, then first in first out先开启、再临期、再先入先出计算这导致缺货产品没有价格成本会被低估3.2.0 的优化是缺货原料回退使用最近一次价格从而更真实地反映当前实际成本。这一逻辑在 SQL 视图recipes_pos_resolved中有直接实现证据migrations/0165.sql 中同时连接了products_oldest_stock_unit_price最旧库存价格与products_last_purchased最近采购价格两个表并用IFNULL(pop.price, IFNULL(plp.price, 0))计算每行成本优先取库存中最旧的单价否则回退到最近采购价再否则为 0——这正是缺货时用最近价格兜底的落地实现。菜谱列表与菜谱详情并排显示可关闭菜谱页右上角设置菜单新增选项Show the recipe list and the recipe side by side列表与详情并排显示默认开启因此不配置时行为不变。关闭后菜谱页的列表将全宽显示菜谱详情改为在弹窗中展示而非右侧栏。对应默认用户设置位于 config-dist.phpDefaultUserSetting(recipes_show_list_side_by_side, true); // If the recipe should be displayed next to recipe list on the recipes page菜谱 Grocycode菜谱现在也支持 Grocycode 了与其它实体产品、电池、家务的 Grocycode 机制完全一致在菜谱编辑页或菜谱页的 more/context 菜单中可下载/打印菜谱 Grocycode在任何可以选择菜谱的地方如消费、采购、膳食计划等都可以使用/扫描该 Grocycode。源码侧helpers/Grocycode.php 定义了public const RECIPE r作为菜谱前缀controllers/Api/RecipesApiController.php 的RecipePrintLabel方法会构造new Grocycode(Grocycode::RECIPE, $args[recipeId])并连同菜谱名称、详情一起组成 WebHook 数据下发到标签打印机。其他改进与修复菜谱页加载性能页面加载时间得到优化修复添加缺失菜谱原料到购物清单时若启用了 Only check if any amount is in stock只检查是否有任意数量库存选项此前未考虑单位换算unit conversions现已在 migrations/0165.sql 中通过LEFT JOIN quantity_unit_conversions_resolved接入换算系数修正修复原料为小数数量时菜谱库存满足度信息中关于购物清单数量的显示不正确。Meal plan 膳食计划膳食计划分节时间膳食计划分节meal plan sections现在可以可选地定义一个时间该时间会显示在分节头部并用于对应的日历事件。此外对应的日历事件现在也会提及分节名称。对应数据库改动在 migrations/0163.sqlALTER TABLE meal_plan_sections ADD time_info TEXT;日/周视图切换膳食计划页右上角新增日/周视图切换按钮仅在较大屏幕上显示小屏幕下仍默认日视图行为不变。同时修复了膳食计划显示总卡路里而非每份卡路里与后缀 per serving 不符的问题。Chores 家务调度家务调度是 3.2.0 改动最集中的模块涵盖了跳过机制、调度起点、周期类型重构与执行频率统计四大块。调度可跳过Skip家务概览页与家务跟踪chore tracking页新增Skip跳过按钮可跳过下一次排定的执行。被跳过的调度会在家务日志chore journal中以相应样式高亮标记。实现上migrations/0163.sql 为chores_log增加了skipped字段ALTER TABLE chores_log ADD skipped TINYINT NOT NULL DEFAULT 0 CHECK(skipped IN (0, 1));services/ChoresService.php 的TrackChore()方法接收$skipped参数若为true会检查该家务是否属于manually无调度类型——无调度的家务不允许跳过Chores without a schedule can\t be skipped随后在chores_log中写入一条skipped 1的记录。统计口径上GetChoreDetails() 在计算已跟踪次数与最近跟踪时间时都会排除skipped 0之外的记录。新增 Start date起始日期新的家务选项Start date作为调度起点用于该家务从未被跟踪过的情形。此前调度起点是第一次执行记录现在新家务可以显式设置起始日期升级迁移时所有已有家务的start_date会被设为首次跟踪时间从未跟踪过则设为当天。对应迁移在 migrations/0164.sqlALTER TABLE chores ADD start_date DATETIME; -- All existing chores get the oldest tracking time as start date UPDATE chores SET start_date (SELECT MIN(tracked_time) FROM chores_log WHERE chore_id chores.id AND undone 0 AND skipped 0); -- Any existing but not yet tracked chore get today as start date UPDATE chores SET start_date DATETIME(now, localtime) WHERE start_date IS NULL;同时该迁移还创建了 INSERT/UPDATE 触发器确保新家务在start_date为空时自动填充当天日期migrations/0164.sql。从视图chores_current可以看到当某家务从未被跟踪MAX(l.tracked_time) IS NULL时next_estimated_execution_time直接取h.start_datemigrations/0164.sql——这就是起始日期的实际调度语义。周期类型重构Yearly / Hourly / Adaptive / Dynamic regular本版对家务周期类型period type做了一次系统性调整Yearly语义变更改为在每年同一天调度锚定起始日期的月/日。此前该类型是在上次执行后满 1 年调度。若确实需要旧的每 365 天滚动行为可用Daily 周期间隔 365 替代。迁移中所有现有Yearly调度都被转换为Dailyperiod_interval period_interval * 365见 migrations/0164.sql新视图里yearly分支的 SQL 用start_date的月日部分拼接到距今 N 年的日期上实现每年同一天migrations/0164.sql。新增Hourly周期类型可配置每隔x小时执行一次家务。对应视图分支为DATETIME(MAX(l.tracked_time), || CAST(h.period_interval AS TEXT) || hour)migrations/0166.sql服务层常量见 services/ChoresService.php 的CHORE_PERIOD_TYPE_HOURLY hourly。新增Adaptive周期类型根据过去平均执行频率动态调度家务。服务层常量CHORE_PERIOD_TYPE_ADAPTIVE adaptiveservices/ChoresService.php已就位平均执行频率数据来自chores_execution_average_frequency表见下文。移除Dynamic regular因其与Daily等价。迁移中所有现有Dynamic regular调度转换为Daily间隔取period_days为空则 1并清空period_daysmigrations/0166.sql。新视图chores_current不再包含dynamic-regular分支。家务卡显示平均执行频率家务卡chorecard现在额外显示平均执行频率该家务过去平均多久执行一次。数据来源是chores_execution_average_frequency表GetChoreDetails()通过$this-DB-chores_execution_average_frequency()-where(chore_id, $choreId)-min(average_frequency_hours)取最小平均间隔单位小时并作为average_execution_frequency_hours字段返回services/ChoresService.php。前端 public/viewjs/components/chorecard.js 将其换算为人类可读的时长如每 2 天展示该字段也同步暴露给了 API见下文 API 章节。Calendar 日历与 Tasks 任务Calendar修复当存在没有截止日期due date的任务时iCal 导出会报错现已修复含无截止日期任务的日历订阅不再中断。Tasks新增任务对话框增加Save add another task保存并再添加一个任务按钮可连续快速创建多个任务无需反复关闭/重开对话框修复编辑无截止日期的任务时此前会错误显示1970-01-01。General 通用改进到期高亮与独立状态筛选家务chores、任务tasks和电池batteries三个概览页现在都有了独立的状态筛选器按状态过滤今日到期条目的表格行蓝色高亮。同时这三个页面右上角设置菜单中的 due soon即将到期天数可以设为0用于禁用该筛选/高亮。对应默认用户设置在 config-dist.phpDefaultUserSetting(chores_due_soon_days, 5); // The due soon days DefaultUserSetting(batteries_due_soon_days, 5); // The due soon days DefaultUserSetting(tasks_due_soon_days, 5); // The due soon days日期字段输入简写[/-]n[d/m/y]日期字段新增输入简写语法[/-]n[d/m/y]即相对今天的日期输入表示加、-表示减n为数字d天、m月、y年为时间单位。例如3d表示三天后-1m表示一个月前。这大幅提升了在采购、消费等页面快速录入日期如最佳食用日期的效率。认证相关LDAP 与反向代理LDAP 认证现在使用配置的LDAP_UID_ATTR来比较用户是否已存在而不是登录页输入的用户名。这避免了同一用户以不同大小写/书写方式登录时被重复创建多个用户。反向代理认证ReverseProxyAuthMiddleware新增config.php选项REVERSE_PROXY_AUTH_USE_ENV允许从环境变量而非 HTTP 头获取用户名。对应配置定义在 config-dist.phpSetting(REVERSE_PROXY_AUTH_USE_ENV, false); // Set to true if the username is passed as an environment variable中间件实现见 middleware/Auth/ReverseProxyAuthMiddleware.php当GROCY_REVERSE_PROXY_AUTH_USE_ENV为真时从$_SERVER[GROCY_REVERSE_PROXY_AUTH_HEADER]读取用户名并校验非空为假时从 HTTP 头读取。两种方式下若用户名对应仓库中的用户不存在都会自动创建用户。修复使用外部认证如 LDAP时此前登出按钮/菜单缺失的问题已解决。修复当某计量单位恰好匹配应用内某个字符串时此前会用该字符串的翻译来显示单位现已修正。其他修复与本地化相对时间显示得到优化并修复了部分语言如匈牙利语的措辞问题config.php选项DISABLE_BROWSER_BARCODE_CAMERA_SCANNING更名为FEATURE_FLAG_DISABLE_BROWSER_BARCODE_CAMERA_SCANNING默认false见 config-dist.php用于禁用浏览器摄像头扫码能力该标志被视图与前端 JS 用于条件渲染摄像头扫码组件见 views/components/camerabarcodescanner.blade.php。注意更名意味着旧config.php中的原键名不再生效升级后需同步调整新增**加泰罗尼亚语Catalan**翻译演示站点为 ca.demo.grocy.info。API 变更汇总本版的 API 变更可以整理为下表均已在 grocy.openapi.json 与对应控制器中验证变更类型端点 / 字段说明源码依据新请求参数POST /stock/shoppinglist/clear增加可选done_only仅清除给定购物清单中已完成的条目默认falsecontrollers/Api/StockApiController.php新请求参数POST /chores/{choreId}/execute增加可选skipped跳过下一次家务调度默认falsecontrollers/Api/ChoresApiController.php新响应字段GET /chores/{choreId}增加average_execution_frequency_hours过去平均执行频率小时从未执行过则为nullservices/ChoresService.php、grocy.openapi.json新端点POST /recipes/{recipeId}/printlabel在配置的标签打印机上打印菜谱 Grocycodecontrollers/Api/RecipesApiController.php修复Stock by-barcode 系列端点条码查找此前区分大小写现改为不区分—其中skipped参数在控制器中的解析逻辑为请求体包含skipped且经FILTER_VALIDATE_BOOLEAN校验为真时启用controllers/Api/ChoresApiController.php最终传入ChoresService::TrackChore()的第四个参数services/ChoresService.php。升级与迁移小结综合来看grocy 3.2.0 的升级路径非常平滑几乎所有破坏性变更都配有数据迁移库存全局开启计缺货配置迁移为产品级Treat opened as out of stock且新产品的默认值同样由旧配置推导而来家务skipped字段、start_date字段、Yearly → Daily(365)、Dynamic regular → Daily四组迁移分别落地在 migrations/0163.sql、migrations/0164.sql 与 migrations/0166.sql膳食计划分节时间通过 migrations/0163.sql 的time_info列承载配置项更名DISABLE_BROWSER_BARCODE_CAMERA_SCANNING→FEATURE_FLAG_DISABLE_BROWSER_BARCODE_CAMERA_SCANNING升级后需要手动同步config.php新增配置REVERSE_PROXY_AUTH_USE_ENV反向代理环境变量认证、product_presets_treat_opened_as_out_of_stock新产品默认选项、recipes_show_list_side_by_side菜谱并排视图默认开启。如果需要在本仓库中继续深挖推荐从 services/ChoresService.php家务调度核心、migrations/0164.sql调度起点与 Yearly 语义以及 migrations/0165.sql菜谱成本核算入手这三个文件基本覆盖了本版最实质的功能重构。【免费下载链接】grocyERP beyond your fridge - Grocy is a web-based self-hosted groceries household management solution for your home项目地址: https://gitcode.com/GitHub_Trending/gr/grocy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考