* fix: permission check for `get_task_html` and `get_timesheet_html`
* fix(project): enabled project access control for users without `Projects User` Role
* fix(portal): validate user permissions for project portal
* fix: patch to add docshare for the project users
* fix(patch): selecting correct column on the query
* fix(project): grant access to all the current users for new project
* fix(portal): fixed condition to display timesheets on project
* test(portal): add access control tests for project user
* fix(project): using `frappe.has_permission` instead of `self.has_permission` to validate user permissions
* fix(project): granting docshare access for every ProjectUser
Roles for an User can be removed any time or an User Permission can be added which might restrict the access to the Project.
* fix(patch): create docshare documents for non-cancelled projects and users who have no docshare documents
* test(project): removed `test_control_access_does_not_touch_users_with_real_permission`
* fix: skip redundant reposting of dependent items
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: use earliest cascade datetime and batch repost item lookup
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix: name every conflicting voucher in the reserved batch error
* fix: exclude fully-delivered reservations from the conflict message
* fix: round outstanding qty guard consistently with the conflict gate
validate_reserved_batches compared the voucher's own qty against the
remaining batch qty, so delivering one order's reserved unit threw
Reserved Batch Conflict whenever the remainder exactly matched another
order's reservation. Compare the remaining batch qty against the
aggregated outstanding reserved qty (qty - delivered_qty) of other
vouchers instead, excluding reservations the voucher itself delivers.
erpnext.accounts.dashboard_fixtures and erpnext.buying.dashboard_fixtures
were removed in 2020 when dashboards were exported to JSON fixtures.
The assets module's dashboard_fixtures.py was left behind unreferenced;
its dashboard, charts and number cards already exist as exported JSON.
StockReservation.transfer_reservation_entries_to() created the transferred SREs without copying stock_uom, in both the entries_to_reserve dict and the extra-items fallback. get_items_to_reserve() already selects the item's stock_uom, so entry.stock_uom is used.
On sites with a global default stock_uom (e.g. "Nos"), frappe's _set_defaults() backfilled the blank field, so the transfer silently stored the wrong UOM for any item whose stock UOM is not the default. On sites without that default the SRE's validate_mandatory() raised "Stock UOM is required", aborting Work Order submission for the Subcontracting Inward Order / Production Plan flows.
(cherry picked from commit 5991ecfa3d)
make_all_scorecards' dedup query used strict bounds, so a single-day
period (supplier created on a month's last day -> start == end under
"Per Month") never matched its own window and was re-created on every
call. The daily refresh_scorecards job would insert a duplicate
submitted period each day for such suppliers, and
test_make_all_scorecards_is_idempotent fails on any date where
nowdate() - 75 days lands on a month end — both nightly server suites
went red on 2026-07-14 (75 days after April 30).
Inclusive bounds cannot false-match adjacent periods: each next period
starts at end_date + 1, so closed intervals never touch.