Compare commits

..

45 Commits

Author SHA1 Message Date
Frappe PR Bot
d47aa4917a chore(release): Bumped to Version 16.23.1
## [16.23.1](https://github.com/frappe/erpnext/compare/v16.23.0...v16.23.1) (2026-06-19)

### Bug Fixes

* type def in get_linked_payments (backport [#56100](https://github.com/frappe/erpnext/issues/56100)) ([#56133](https://github.com/frappe/erpnext/issues/56133)) ([6569fa2](6569fa2b9f))
2026-06-19 08:39:21 +00:00
mergify[bot]
6569fa2b9f fix: type def in get_linked_payments (backport #56100) (#56133)
fix: type def in get_linked_payments (#56100)

(cherry picked from commit 8e21af0a63)

Co-authored-by: Nikhil Kothari <nik.kothari22@live.com>
2026-06-19 08:37:40 +00:00
Frappe PR Bot
b1ca423e11 chore(release): Bumped to Version 16.23.0
# [16.23.0](https://github.com/frappe/erpnext/compare/v16.22.0...v16.23.0) (2026-06-16)

### Bug Fixes

* **accounts:** removed whitelist on `get_balance_on` (backport [#55956](https://github.com/frappe/erpnext/issues/55956)) ([#55965](https://github.com/frappe/erpnext/issues/55965)) ([5cdb481](5cdb481bdf))
* adapt Product Bundle queries to v16 schema ([b1895e9](b1895e9a9a))
* add permission checks in accounts whitelisted methods ([b9eb52b](b9eb52b171))
* added doctype filter validation for sales person wise transaction summary report (backport [#55812](https://github.com/frappe/erpnext/issues/55812)) ([#55818](https://github.com/frappe/erpnext/issues/55818)) ([c06046d](c06046df8f))
* apply user permissions to receivable/payable reports ([b05abbc](b05abbc53b))
* **banking:** miscellaneous bug fixes (backport [#55492](https://github.com/frappe/erpnext/issues/55492)) ([#55979](https://github.com/frappe/erpnext/issues/55979)) ([3243e42](3243e4237a))
* **bom:** allow zero qty for secondary items (Co-Product, By-Product, Scrap, Additional Finished Good) ([7d95aca](7d95acabe7))
* **bom:** fetch routing operations when Routing is selected ([#55813](https://github.com/frappe/erpnext/issues/55813)) ([f3caed3](f3caed378b))
* **budget:** add root_type filter on account field ([#55934](https://github.com/frappe/erpnext/issues/55934)) ([0906737](0906737bd3))
* bump BOM secondary item metadata timestamp ([4f96073](4f96073d59))
* check for bank account permission when updating balance (backport [#56016](https://github.com/frappe/erpnext/issues/56016)) ([#56017](https://github.com/frappe/erpnext/issues/56017)) ([2bfb5fe](2bfb5fe8b8))
* **company:** replaced "this company" with company name on delete transactions dialog (backport [#56021](https://github.com/frappe/erpnext/issues/56021)) ([#56023](https://github.com/frappe/erpnext/issues/56023)) ([f4bf35a](f4bf35aa31))
* converted whitelist non class methods to class methods ([b616206](b616206848))
* create_raw_materials_supplied method not found ([d51ad0d](d51ad0d19f))
* exclude non-stock item's tax value from stock valuation ([3d6c7f4](3d6c7f4512))
* fiscal year check on validation (backport [#55930](https://github.com/frappe/erpnext/issues/55930)) ([#55938](https://github.com/frappe/erpnext/issues/55938)) ([f3e23d4](f3e23d4e6f))
* **get_exchange_rate:** using get_single_value to fetch `disabled` value from `currency_exchange_settings` ([2606d66](2606d660af))
* **inactive_customers:** add allowlist for doctype filter and migrate to qb ([f43af66](f43af66246))
* **Lead:** stop storing Gravatar image URLs for Leads (backport [#55880](https://github.com/frappe/erpnext/issues/55880)) ([#55882](https://github.com/frappe/erpnext/issues/55882)) ([0b03f18](0b03f18a39))
* **manufacture:** preserve user-entered rate for secondary items with zero cost allocation ([5090389](509038971c))
* multiple issues related to BOM Creator ([c10a331](c10a331a22))
* opportunity creation from contact us page (backport [#55841](https://github.com/frappe/erpnext/issues/55841)) ([#55867](https://github.com/frappe/erpnext/issues/55867)) ([85e6b8d](85e6b8d27b))
* pass source cost center to target cost center ([558415b](558415b1e7))
* pemission for whitelist functions ([dd56e80](dd56e80512))
* permission in bom compare tool ([c3b66bc](c3b66bce1e))
* permissions in workstation file ([0fea933](0fea93388d))
* prefetch batchwise valuations before streaming SLEs in stock ageing ([018f06d](018f06d8d1))
* prevent exchange rate flow from transaction to payment ([d7de07b](d7de07bfd4))
* provision to recalculate valuation rate during reposting ([5b61304](5b61304046))
* recalculate incoming rate in SLE for purchase documents during repost ([d3cc684](d3cc684899))
* regression issues related to security fixes ([be1aa0e](be1aa0e5eb))
* remove duplicate field ([#55941](https://github.com/frappe/erpnext/issues/55941)) ([545d052](545d052b4e))
* remove ignore_permissions from get_party_details signature ([#55491](https://github.com/frappe/erpnext/issues/55491)) ([b2e7fd7](b2e7fd7957))
* remove wrapper for list items in error messages (backport [#54848](https://github.com/frappe/erpnext/issues/54848)) ([#55973](https://github.com/frappe/erpnext/issues/55973)) ([4ba5557](4ba5557a3f))
* resolve pre-commit formatting and missing UOM in stock balance test ([96465a7](96465a7936))
* resolve v16 BOM backport conflicts ([c7cc0fe](c7cc0fec0f))
* restricting currency_exchange_settings write permission only to system manager ([79fd176](79fd176a8e))
* semgrep translation issue ([bcd38c1](bcd38c17d6))
* set options Email for customer_email field in appointment ([6d038c5](6d038c5e71))
* set transaction currency on payment entry gl entries ([#55989](https://github.com/frappe/erpnext/issues/55989)) ([3586df8](3586df8ed6))
* show company name in delete transactions confirmation dialog ([6a3c973](6a3c973b0f))
* show inactive product bundles in item where used ([#55769](https://github.com/frappe/erpnext/issues/55769)) ([2bea9ae](2bea9ae2a5))
* show user disable audit log ([ca61e5a](ca61e5a214))
* **stock:** make uom mandatory in item uom table ([7f8c7d2](7f8c7d2f44))
* **stock:** show only batched items in batch item selector ([11b3841](11b3841418))
* **stock:** update stock value calculation in stock balance report ([00794e0](00794e0815))
* sync employee user status after save ([a83002a](a83002aae6))
* test case ([9fcb730](9fcb730090))
* UI/UX issues in new banking module (backport [#54824](https://github.com/frappe/erpnext/issues/54824)) ([#55951](https://github.com/frappe/erpnext/issues/55951)) ([961a9ad](961a9ad321))
* update system manager permissions (backport [#55978](https://github.com/frappe/erpnext/issues/55978)) ([#56005](https://github.com/frappe/erpnext/issues/56005)) ([ab856d3](ab856d370a))
* updated role based permission for terms and conditions doctype ([#55674](https://github.com/frappe/erpnext/issues/55674)) ([254290a](254290a88e))
* use frankfurter v2 by default for new install ([471ab66](471ab662f6))

### Features

* add alternate UOM balance columns to Stock Balance report ([cd1f872](cd1f872912)), closes [#52953](https://github.com/frappe/erpnext/issues/52953)
* Allow to edit stock UOM qty for Stock Entry ([ece43bd](ece43bd79b))
* **banking:** PDF statement importer and overriding column mapping (backport [#55559](https://github.com/frappe/erpnext/issues/55559)) ([#55993](https://github.com/frappe/erpnext/issues/55993)) ([125bda9](125bda95ed))
* **currency exchange settings:** frankfurter v2 support ([e804bf3](e804bf33ba))
* **invoices:** add tooltip description to Update Stock checkbox ([#55868](https://github.com/frappe/erpnext/issues/55868)) ([12be632](12be63229a))
* new banking module (backport [#54720](https://github.com/frappe/erpnext/issues/54720)) ([#55917](https://github.com/frappe/erpnext/issues/55917)) ([67cc59c](67cc59c5ca))
* **selling:** surface and respect disabled Product Bundles (backport [#55791](https://github.com/frappe/erpnext/issues/55791)) ([0c1a508](0c1a5082bd))
* sticky columns in reports ([3317158](331715815c))
2026-06-16 21:31:15 +00:00
Diptanil Saha
c1e77c04fd Merge pull request #55981 from frappe/version-16-hotfix
chore: release v16
2026-06-17 02:59:09 +05:30
Frappe PR Bot
054b20a2ae chore(release): Bumped to Version 16.22.0
# [16.22.0](https://github.com/frappe/erpnext/compare/v16.21.1...v16.22.0) (2026-06-10)

### Bug Fixes

* **accounts:** include asset items in purchase receipt validation ([#55150](https://github.com/frappe/erpnext/issues/55150)) ([0984c86](0984c86583))
* Add authorization checks on internal functions (backport [#55709](https://github.com/frappe/erpnext/issues/55709)) ([#55726](https://github.com/frappe/erpnext/issues/55726)) ([2ae6451](2ae6451f10))
* add company filter to Budget Against dimension options ([bfc6f44](bfc6f44fb0))
* add custom dimensions filters in Gross and Net profit report (backport [#55110](https://github.com/frappe/erpnext/issues/55110)) ([#55584](https://github.com/frappe/erpnext/issues/55584)) ([5d7e69d](5d7e69d8cf))
* Add likely missing escapes (backport [#55574](https://github.com/frappe/erpnext/issues/55574)) ([#55581](https://github.com/frappe/erpnext/issues/55581)) ([6a503f8](6a503f834c))
* aggregate child cost center data in Budget Variance Report ([4f2611c](4f2611cbe8))
* allow specific methods to run ([c9a5b00](c9a5b0026e))
* bypass project permission check when updating consumed material … (backport [#55645](https://github.com/frappe/erpnext/issues/55645)) ([#55707](https://github.com/frappe/erpnext/issues/55707)) ([4471666](4471666c8c))
* **cheque_print_template:** print format creation from cheque print template requires system manager (backport [#55708](https://github.com/frappe/erpnext/issues/55708)) ([#55712](https://github.com/frappe/erpnext/issues/55712)) ([38dd298](38dd2982f3))
* disallow BOM finished good item in secondary items table (backport [#55710](https://github.com/frappe/erpnext/issues/55710)) ([#55719](https://github.com/frappe/erpnext/issues/55719)) ([ecd3a19](ecd3a19912))
* do not allow to make changes in SABB after submit ([a03e3bf](a03e3bfe9f))
* don't allow to submit job card with hold status ([b4c850d](b4c850da1c))
* drop ignore_permissions handling from add_ac ([c0cf9aa](c0cf9aa1a7))
* duplicating a Customer/Supplier shouldn't inherit the source's primary contact and address (backport [#55421](https://github.com/frappe/erpnext/issues/55421)) ([#55609](https://github.com/frappe/erpnext/issues/55609)) ([808e51d](808e51db19))
* handle multi-select stock ageing filters ([#55775](https://github.com/frappe/erpnext/issues/55775)) ([e48ffe6](e48ffe6ef0))
* handle separator rows in financial statement formatter ([d8afc00](d8afc00ab5))
* include CRM Deal in `quotation to` filters ([f7e6542](f7e6542bcd))
* item report view ([7dfae51](7dfae51044))
* **item:** format integer numeric variant attributes without decimals (backport [#55561](https://github.com/frappe/erpnext/issues/55561)) ([#55564](https://github.com/frappe/erpnext/issues/55564)) ([fffba84](fffba84868))
* linter issue ([dd83705](dd837052ef))
* minor fixes in report print formats ([#55151](https://github.com/frappe/erpnext/issues/55151)) ([80f7aff](80f7aff3f9))
* move Company filter at the start ([3fb6437](3fb6437d26))
* naming series issue ([6eecf07](6eecf0701e))
* prevent double rounding in inclusive tax calculations (backport [#52512](https://github.com/frappe/erpnext/issues/52512)) ([#55570](https://github.com/frappe/erpnext/issues/55570)) ([37b61f0](37b61f06ae))
* prevent leakage of party-derived fields in cross doctype transactions (backport [#55336](https://github.com/frappe/erpnext/issues/55336)) ([#55579](https://github.com/frappe/erpnext/issues/55579)) ([7904385](7904385b90))
* prevent negative amounts in common party JE on return invoices (backport [#55034](https://github.com/frappe/erpnext/issues/55034)) ([#55064](https://github.com/frappe/erpnext/issues/55064)) ([9eb0e3c](9eb0e3c82e))
* prevent selling items from sample retention warehouse (backport [#55613](https://github.com/frappe/erpnext/issues/55613)) ([#55634](https://github.com/frappe/erpnext/issues/55634)) ([84d205f](84d205f553))
* **process statement of accounts:** validate pdf_name and validate permission before triggering send_auto_email (backport [#55781](https://github.com/frappe/erpnext/issues/55781)) ([#55783](https://github.com/frappe/erpnext/issues/55783)) ([e15879a](e15879acd1))
* **profit-and-loss-statement-report:** margin calculation the report showing null% for empty cell ([04fe76b](04fe76bf83))
* **profit-and-loss-statement:** margin calculation the report showing null% for empty cell ([b3d3f13](b3d3f13fc5))
* **profit-loss-report:** handle zero base values and prevent null% display ([90ac065](90ac065930))
* remove item name from update items dialog item code column (backport [#55718](https://github.com/frappe/erpnext/issues/55718)) ([#55723](https://github.com/frappe/erpnext/issues/55723)) ([497c3a5](497c3a5e83))
* restrict already invoiced qty in intercompany purchase invoice ([#55768](https://github.com/frappe/erpnext/issues/55768)) ([e90a6ec](e90a6ecf1c))
* **selling:** consider delivered qty (backport [#55597](https://github.com/frappe/erpnext/issues/55597)) ([#55607](https://github.com/frappe/erpnext/issues/55607)) ([142ab3c](142ab3ce2a))
* simplify New Zealand sales accounts ([93de14c](93de14c421))
* skip empty spacer rows in compute_growth_view_data (P&L growth view) ([18afcf0](18afcf0c01))
* spelling of Payment Reconciliation in sidebar (backport [#55599](https://github.com/frappe/erpnext/issues/55599)) ([#55602](https://github.com/frappe/erpnext/issues/55602)) ([40cf77e](40cf77e7f0))
* sql injection ([02a29a8](02a29a85a7))
* Stock Reservation blocks Subcontracting operation within the same Work Order ([1c0dace](1c0dace3d6))
* **stock:** add validation for work order seial nos and batch nos (backport [#55604](https://github.com/frappe/erpnext/issues/55604)) ([#55605](https://github.com/frappe/erpnext/issues/55605)) ([7de77a8](7de77a8916))
* **stock:** change valuation rate column label in stock ledger entry/report (backport [#55323](https://github.com/frappe/erpnext/issues/55323)) ([#55394](https://github.com/frappe/erpnext/issues/55394)) ([c6560be](c6560be58d))
* **stock:** set stock received but not billed account for purchase ([#55149](https://github.com/frappe/erpnext/issues/55149)) ([90667b2](90667b2de2))
* **subscription:** bill on creation and keep status in sync with invoices (backport [#55615](https://github.com/frappe/erpnext/issues/55615)) ([#55701](https://github.com/frappe/erpnext/issues/55701)) ([0f069e1](0f069e13da))
* **subscription:** correct billing/deferred bugs and tighten guards (backport [#55554](https://github.com/frappe/erpnext/issues/55554)) ([#55610](https://github.com/frappe/erpnext/issues/55610)) ([dee7bd8](dee7bd8d64))
* **taxes:** add category and add_deduct_tax fields to tax entries (backport [#55753](https://github.com/frappe/erpnext/issues/55753)) ([#55773](https://github.com/frappe/erpnext/issues/55773)) ([9a6fae9](9a6fae9fdd))
* update add_total_row_account to control blank row addition ([e8a6933](e8a6933ff3))
* update formatter to handle blank rows in financial statements ([f657503](f657503ea3))
* update items respects workflow "Only Allow Edit For" role ([#55667](https://github.com/frappe/erpnext/issues/55667)) ([76b9b6a](76b9b6a34e))
* use new_doc with field allowlist in CRM integration endpoints ([d941ccf](d941ccfe3c))
* **UX:** Accounts settings cleanup (backport [#55470](https://github.com/frappe/erpnext/issues/55470)) ([#55603](https://github.com/frappe/erpnext/issues/55603)) ([3917415](3917415368))
* **UX:** stock settings form cleanup ([f6f542f](f6f542fadc))
* validate fg and materials qty in the disassemble entry ([4453c10](4453c1072a))
* work order status should be in process if material transfer is skipped (backport [#55641](https://github.com/frappe/erpnext/issues/55641) to version-16-hotfix) ([#55642](https://github.com/frappe/erpnext/issues/55642)) ([32011c3](32011c3364))

### Features

* add item where used report ([#55714](https://github.com/frappe/erpnext/issues/55714)) ([8f85cce](8f85cce4cf))
* add New Zealand chart of accounts ([107a446](107a446d98))
* added cost of goods sold (backport [#54974](https://github.com/frappe/erpnext/issues/54974)) ([#55552](https://github.com/frappe/erpnext/issues/55552)) ([20af709](20af7093ac))
* create sales invoice from pick list (backport [#55594](https://github.com/frappe/erpnext/issues/55594)) ([#55635](https://github.com/frappe/erpnext/issues/55635)) ([743afc9](743afc972d))
* item prices list view ([#54853](https://github.com/frappe/erpnext/issues/54853)) ([12c1940](12c1940e0b))
* show non stock items and secondary items in work order (backport [#55631](https://github.com/frappe/erpnext/issues/55631)) ([#55636](https://github.com/frappe/erpnext/issues/55636)) ([3f983c9](3f983c9e4d))

### Performance Improvements

* batch status check for on-hold/closed documents, remove N+1 queries (backport [#54798](https://github.com/frappe/erpnext/issues/54798)) ([#55573](https://github.com/frappe/erpnext/issues/55573)) ([0274afe](0274afe560))
* **transaction:** exit early before backend query (backport [#55556](https://github.com/frappe/erpnext/issues/55556)) ([#55558](https://github.com/frappe/erpnext/issues/55558)) ([6a1c384](6a1c384f9b))
2026-06-10 00:25:19 +00:00
Mihir Kandoi
03f6b7a50e Merge pull request #55764 from frappe/version-16-hotfix 2026-06-10 05:53:43 +05:30
Frappe PR Bot
6bcab7cfc8 chore(release): Bumped to Version 16.21.1
## [16.21.1](https://github.com/frappe/erpnext/compare/v16.21.0...v16.21.1) (2026-06-03)

### Bug Fixes

* item report view ([656d1bd](656d1bd6e3))
2026-06-03 09:43:23 +00:00
Nishka Gosalia
39c8161011 Merge pull request #55593 from frappe/mergify/bp/version-16/pr-55592
fix: item report view (backport #55591) (backport #55592)
2026-06-03 15:11:44 +05:30
nishkagosalia
656d1bd6e3 fix: item report view
(cherry picked from commit bca917380d)
(cherry picked from commit 7dfae51044)
2026-06-03 09:39:24 +00:00
Frappe PR Bot
ecb572de92 chore(release): Bumped to Version 16.21.0
# [16.21.0](https://github.com/frappe/erpnext/compare/v16.20.1...v16.21.0) (2026-06-02)

### Bug Fixes

* asset scrap flow related changes ([e3f03a2](e3f03a21c3))
* billing address does not belongs to the company error ([e1f29de](e1f29de078))
* **book_appointment:** when scheduling is disabled, block API endpoints (backport [#55455](https://github.com/frappe/erpnext/issues/55455)) ([#55457](https://github.com/frappe/erpnext/issues/55457)) ([aa5dfde](aa5dfde23b))
* changes as per review ([8b1d981](8b1d9817a6))
* check perm for account (backport [#55479](https://github.com/frappe/erpnext/issues/55479)) ([#55483](https://github.com/frappe/erpnext/issues/55483)) ([0c946f2](0c946f2420))
* **custom_financial_template:** sum account closing balances across dimensions ([3359e20](3359e20d06))
* import DateTimeLikeObject ([d82e03e](d82e03edb6))
* **issue:** check permission before issue status modification (backport [#55458](https://github.com/frappe/erpnext/issues/55458)) ([#55460](https://github.com/frappe/erpnext/issues/55460)) ([7c5d617](7c5d617049))
* item master list view UI cleanup ([2d554c0](2d554c05d6))
* **je:** preserve account on duplicate row when party row exists (backport [#55180](https://github.com/frappe/erpnext/issues/55180)) ([#55512](https://github.com/frappe/erpnext/issues/55512)) ([fe585dc](fe585dc225))
* Make Distributed Discount Amount field read only ([29441b7](29441b7249))
* **manufacturing:** allow to edit batch size while creating a work order (backport [#55058](https://github.com/frappe/erpnext/issues/55058)) ([#55326](https://github.com/frappe/erpnext/issues/55326)) ([ae92a82](ae92a82930))
* material transfer in transit issue ([356bb78](356bb7878f))
* merge conflicts ([b74e365](b74e365421))
* new bom version should not recalculate operations through routing (backport [#55370](https://github.com/frappe/erpnext/issues/55370)) ([#55372](https://github.com/frappe/erpnext/issues/55372)) ([933ac01](933ac0108c))
* over order allowance setting fix ([41b2de3](41b2de35a9))
* pick correct name when creating user from RFQ (backport [#55468](https://github.com/frappe/erpnext/issues/55468)) ([#55472](https://github.com/frappe/erpnext/issues/55472)) ([fc842fb](fc842fb45f))
* **pos:** escape html output in pos page templates (backport [#55527](https://github.com/frappe/erpnext/issues/55527)) ([#55529](https://github.com/frappe/erpnext/issues/55529)) ([224426e](224426e06b))
* **pos:** escape item data on pos item selector (backport [#55503](https://github.com/frappe/erpnext/issues/55503)) ([#55508](https://github.com/frappe/erpnext/issues/55508)) ([5393c93](5393c93675))
* **pos:** preserve contacts and enforce permissions in set_customer_info (backport [#55463](https://github.com/frappe/erpnext/issues/55463)) ([#55466](https://github.com/frappe/erpnext/issues/55466)) ([ef2700b](ef2700bec6))
* **ppr:** make default_advance_account optional ([7a7cc31](7a7cc31523))
* **quotation:** made customer contact column visible (backport [#55433](https://github.com/frappe/erpnext/issues/55433)) ([#55435](https://github.com/frappe/erpnext/issues/55435)) ([2feb8eb](2feb8eb370))
* **regional:** Japanese CT Rate (backport [#54998](https://github.com/frappe/erpnext/issues/54998)) ([#55438](https://github.com/frappe/erpnext/issues/55438)) ([7426aaf](7426aaf1e2))
* resolve conflict ([abe19e1](abe19e1212))
* **selling:** handle None values while grouping opportunities by utm … (backport [#55300](https://github.com/frappe/erpnext/issues/55300)) ([#55328](https://github.com/frappe/erpnext/issues/55328)) ([198970c](198970cdee))
* set a fallback value if no fiscal year set ([1521410](1521410125))
* stock reco for legacy serial nos ([67c922c](67c922cdf3))
* **stock:** add warning message to notify the user to configure the inspection ([1679680](1679680d8e))
* **stock:** allow to create quality inspection after purchase/delivery ([51a140a](51a140a2bd))
* **stock:** change qb to qb get_query to fix filter issues (backport [#55443](https://github.com/frappe/erpnext/issues/55443)) ([#55445](https://github.com/frappe/erpnext/issues/55445)) ([277a072](277a0723ef))
* **stock:** get_actual_qty during cancellations (backport [#55388](https://github.com/frappe/erpnext/issues/55388)) ([#55392](https://github.com/frappe/erpnext/issues/55392)) ([faa1573](faa15731cb))
* **tds:** treat NULL and empty-string tax_withholding_group as equivalent ([82e12d2](82e12d2d52))
* unable to submit subcontracted job card (backport [#55537](https://github.com/frappe/erpnext/issues/55537)) ([#55540](https://github.com/frappe/erpnext/issues/55540)) ([ceb1042](ceb10422ae))
* update default_advance_account type ([0bbc493](0bbc493213))
* use fiscal year instead of calendar year in accounting dashboard number cards ([81d10d3](81d10d32f2))
* use get_query instead of get_all for data fetching ([7cbef15](7cbef15596))
* **UX:** Move title field to More Info ([20592fc](20592fc25d))

### Features

* build and upload assets to GitHub Releases ([4c05ebc](4c05ebc21e))
* over order allowance setting ([08eaaa5](08eaaa5b83))
* **payment-entry:** warn user before cancelling reconciled payment entry ([61d6d2f](61d6d2f344))
2026-06-02 16:55:08 +00:00
Mihir Kandoi
23181b3962 Merge pull request #55547 from frappe/version-16-hotfix 2026-06-02 22:23:38 +05:30
ruthra kumar
4af265c48f Merge pull request #55502 from frappe/mergify/bp/version-16/pr-55495
fix: opening bal double counting in Process Period Closing Voucher (backport #55495)
2026-06-01 16:00:41 +05:30
ruthra kumar
ce97a74c5f test: prevent double counting of opening balances
(cherry picked from commit 7f2af123ee)
2026-06-01 09:36:47 +00:00
ruthra kumar
e955b4a3b9 refactor: color coded status in list view
(cherry picked from commit cfeffbb354)
2026-06-01 09:36:46 +00:00
ruthra kumar
de42a9e86e refactor: tabbed view for process period closing voucher
(cherry picked from commit 1960c81619)
2026-06-01 09:36:46 +00:00
ruthra kumar
5206b279b6 refactor: only consider non-opening balance for Balance sheet accounts
(cherry picked from commit a2b8334046)
2026-06-01 09:36:46 +00:00
Frappe PR Bot
9af618d6bf chore(release): Bumped to Version 16.20.1
## [16.20.1](https://github.com/frappe/erpnext/compare/v16.20.0...v16.20.1) (2026-06-01)

### Bug Fixes

* billing address does not belongs to the company error ([d6b7791](d6b7791f18))
2026-06-01 06:08:21 +00:00
rohitwaghchaure
3c3cde4362 Merge pull request #55475 from frappe/mergify/bp/version-16/pr-55425
fix: billing address does not belongs to the company error (backport #55417) (backport #55425)
2026-06-01 11:36:44 +05:30
Rohit Waghchaure
d6b7791f18 fix: billing address does not belongs to the company error
(cherry picked from commit 9df07b367a)
(cherry picked from commit e1f29de078)
2026-06-01 06:02:05 +00:00
Frappe PR Bot
ff46d20b25 chore(release): Bumped to Version 16.20.0
# [16.20.0](https://github.com/frappe/erpnext/compare/v16.19.1...v16.20.0) (2026-05-27)

### Bug Fixes

* consider batchwise valuation in stock ageing report (backport [#54919](https://github.com/frappe/erpnext/issues/54919)) ([#55230](https://github.com/frappe/erpnext/issues/55230)) ([a1457c7](a1457c759d))
* consumed operation cost calculation (backport [#54858](https://github.com/frappe/erpnext/issues/54858)) ([#55133](https://github.com/frappe/erpnext/issues/55133)) ([dfc9144](dfc91441b4))
* correct description for Is Rate Adjustment Entry (Debit Note) checkbox ([a39733d](a39733ddd0))
* correct remarks for foreign currency payment entries ([f3f8f32](f3f8f327df))
* corrected the pricing rule taking the wrong value (backport [#54894](https://github.com/frappe/erpnext/issues/54894)) ([#55124](https://github.com/frappe/erpnext/issues/55124)) ([1a75c14](1a75c14308))
* default use_for_shopping_cart to 0 in set_taxes ([54be4ee](54be4ee275))
* don't reset net_purchase_amount for Composite Asset if already set ([99642b9](99642b9636))
* edit stock uom qty for purchase documents (backport [#55135](https://github.com/frappe/erpnext/issues/55135)) ([#55179](https://github.com/frappe/erpnext/issues/55179)) ([123b4ad](123b4ad563))
* **employee:** js error if user does not have write permission for date field (backport [#55312](https://github.com/frappe/erpnext/issues/55312)) ([#55314](https://github.com/frappe/erpnext/issues/55314)) ([4dff5a7](4dff5a7820))
* faster range calculation on process period closing voucher ([e56ee38](e56ee383bc))
* fg valuation rate in repack entry when multiple FGs ([7b6adce](7b6adce89a))
* inclusive tax amount not considered while setting LCV from purchase invoice ([bd4c244](bd4c24493c))
* incorrect error message string in sales order (backport [#55090](https://github.com/frappe/erpnext/issues/55090)) ([#55095](https://github.com/frappe/erpnext/issues/55095)) ([17bc2b6](17bc2b691f))
* invalid filter on item_group (backport [#55186](https://github.com/frappe/erpnext/issues/55186)) ([#55188](https://github.com/frappe/erpnext/issues/55188)) ([ea86347](ea863477a4))
* item price with party condition (backport [#55100](https://github.com/frappe/erpnext/issues/55100)) ([#55107](https://github.com/frappe/erpnext/issues/55107)) ([cc438a4](cc438a4600))
* job card buttons color (backport [#55252](https://github.com/frappe/erpnext/issues/55252)) ([#55261](https://github.com/frappe/erpnext/issues/55261)) ([69c6ed3](69c6ed3cd9))
* **manufacturing:** fetch from_bom name in production plan (backport [#55085](https://github.com/frappe/erpnext/issues/55085)) ([#55092](https://github.com/frappe/erpnext/issues/55092)) ([36aca51](36aca51fbb))
* **manufacturing:** remove forecast_qty and adjust_qty fields from sa… (backport [#55129](https://github.com/frappe/erpnext/issues/55129)) ([#55136](https://github.com/frappe/erpnext/issues/55136)) ([bde7f16](bde7f1660e))
* **payment_entry:** sync paid/received amounts for cross-currency entries (backport [#55270](https://github.com/frappe/erpnext/issues/55270)) ([#55272](https://github.com/frappe/erpnext/issues/55272)) ([705814f](705814f066))
* pos profile form cleanup (backport [#52436](https://github.com/frappe/erpnext/issues/52436)) ([#55285](https://github.com/frappe/erpnext/issues/55285)) ([1f14ef2](1f14ef2344))
* prevent AttributeError in batch query filters (backport [#55257](https://github.com/frappe/erpnext/issues/55257)) ([#55279](https://github.com/frappe/erpnext/issues/55279)) ([bfd37dc](bfd37dcc21))
* **project:** update customer and sales order as no copy ([1e61ca1](1e61ca162f))
* removed redundant code ([a7eb3ac](a7eb3acd1a))
* **sales_invoice:** skip stock update for POS invoices linked to Delivery Note (backport [#55311](https://github.com/frappe/erpnext/issues/55311)) ([#55313](https://github.com/frappe/erpnext/issues/55313)) ([cd7e1bb](cd7e1bbff1))
* set bin details when adding item using update items (backport [#55096](https://github.com/frappe/erpnext/issues/55096)) ([#55098](https://github.com/frappe/erpnext/issues/55098)) ([bb87ffc](bb87ffc90a))
* single variant creation error ([82b0372](82b0372d5b))
* slow query ([66c9170](66c9170465))
* **stock:** apply posting datetime filters while fetching available batches (backport [#54976](https://github.com/frappe/erpnext/issues/54976)) ([#55185](https://github.com/frappe/erpnext/issues/55185)) ([edf6bea](edf6bea2ee))
* **stock:** remove precision for valuation rate while creating sle (backport [#55249](https://github.com/frappe/erpnext/issues/55249)) ([#55260](https://github.com/frappe/erpnext/issues/55260)) ([9600ecd](9600ecd61c))
* **stock:** remove recalculate current qty function (backport [#54774](https://github.com/frappe/erpnext/issues/54774)) ([#55075](https://github.com/frappe/erpnext/issues/55075)) ([56a9b37](56a9b37fac))
* use passed posting date in make_reverse_gl_entries ([3ce9cf2](3ce9cf2bd8))
* valuation rate missing for standalone credit notes for moving av… (backport [#55102](https://github.com/frappe/erpnext/issues/55102)) ([#55104](https://github.com/frappe/erpnext/issues/55104)) ([b11365b](b11365b8c2))

### Features

* add get_parent_supplier_groups using query builder ([82793cb](82793cbd4d))
* add party groups functionality to party specific item (backport [#54988](https://github.com/frappe/erpnext/issues/54988)) ([#55245](https://github.com/frappe/erpnext/issues/55245)) ([a618f4c](a618f4cca4))
* allow creation of any number of variants in multiple item variant creation dialog ([27db98d](27db98d222))
* pending qty in job card ([b372e6f](b372e6f118))

### Performance Improvements

* skip delink_original_entry during cancellation when Immutable Ledger is enabled ([#55130](https://github.com/frappe/erpnext/issues/55130)) ([8a4cb28](8a4cb28d90))
* skip delink_original_entry during cancellation when Immutable Ledger is enabled (backport [#55130](https://github.com/frappe/erpnext/issues/55130)) ([#55166](https://github.com/frappe/erpnext/issues/55166)) ([92689e0](92689e05da))
2026-05-27 01:22:47 +00:00
mergify[bot]
d215fa7623 chore: remove frappe-semgrep-rules submodule (backport #55083) (#55319)
Co-authored-by: diptanilsaha <diptanil@frappe.io>
2026-05-27 01:21:08 +00:00
Diptanil Saha
bf8f7ba883 Merge pull request #55307 from frappe/version-16-hotfix
chore: release v16
2026-05-27 05:33:15 +05:30
Frappe PR Bot
6ef4a2d82c chore(release): Bumped to Version 16.19.1
## [16.19.1](https://github.com/frappe/erpnext/compare/v16.19.0...v16.19.1) (2026-05-20)

### Bug Fixes

* faster range calculation on process period closing voucher ([fa4aa0c](fa4aa0c1b6))
2026-05-20 07:25:32 +00:00
ruthra kumar
e4e796146d Merge pull request #55082 from frappe/mergify/bp/version-16/pr-55072
perf: faster opening balance range calculation in process period closing voucher (backport #55072)
2026-05-20 12:53:58 +05:30
ruthra kumar
ea1d0cc277 refactor: ppcv select with for update and skip locked
(cherry picked from commit eba58b2837)
2026-05-20 06:51:01 +00:00
ruthra kumar
fa4aa0c1b6 fix: faster range calculation on process period closing voucher
(cherry picked from commit ee33574a6d)
2026-05-20 06:51:01 +00:00
Frappe PR Bot
fdfcbf72bd chore(release): Bumped to Version 16.19.0
# [16.19.0](https://github.com/frappe/erpnext/compare/v16.18.3...v16.19.0) (2026-05-20)

### Bug Fixes

* add filter subtitle in print formats ([c4037da](c4037daca8))
* add warehouse vaildation for repack entry (backport [#54866](https://github.com/frappe/erpnext/issues/54866)) ([#54901](https://github.com/frappe/erpnext/issues/54901)) ([596c257](596c2571f6))
* changes to gl print template ([caa524f](caa524f661))
* disallow editing on reversal journals ([6a53982](6a53982f4a))
* **general-ledger:** show raw GL entries when categorize_by is empty (backport [#54816](https://github.com/frappe/erpnext/issues/54816)) ([#54830](https://github.com/frappe/erpnext/issues/54830)) ([c041cd2](c041cd27b5))
* handle None delivery_date when sorting MPS data (backport [#55028](https://github.com/frappe/erpnext/issues/55028)) ([#55059](https://github.com/frappe/erpnext/issues/55059)) ([f272d32](f272d32f80))
* improve design and refactor ar print template ([059372a](059372add5))
* improve filter details render logic to avoid showing duplicate information ([040b31d](040b31d3a7))
* incoming rate for legacy serial no (backport [#54962](https://github.com/frappe/erpnext/issues/54962)) ([#54978](https://github.com/frappe/erpnext/issues/54978)) ([6bce78c](6bce78c66d))
* minor bug fixes for ar print template ([09b19f7](09b19f7a2a))
* minor bugs in print templates ([e1446fc](e1446fc6f4))
* minor changes in print template ([0ead229](0ead2296e6))
* minor changes in print template ([16bc28b](16bc28bd70))
* minor changes in print templates ([0d50e03](0d50e03595))
* minor text issues in print ([daaa4ca](daaa4ca0c8))
* normalize date comparison to avoid datatype mismatch ([42f6cb4](42f6cb40d1))
* **patch:** drop dead procedures first before other changes ([0df9591](0df9591910))
* **payment_entry:** fix paid/received amount calculation for multi-currency accounts (backport [#54963](https://github.com/frappe/erpnext/issues/54963)) ([#54970](https://github.com/frappe/erpnext/issues/54970)) ([48b09eb](48b09eb52e))
* posting date and time ([1c44c60](1c44c60dbd))
* prevent duplicate task execution and timestamp error in transaction deletion (backport [#55021](https://github.com/frappe/erpnext/issues/55021)) ([#55025](https://github.com/frappe/erpnext/issues/55025)) ([9857cc6](9857cc64d6))
* remove parent page ([10b4090](10b409005d))
* remove sql procedure method from AR report ([414319d](414319daeb))
* revamp print formats for accounts receivable summary and accounts payable summary reports ([928fab6](928fab6f7e))
* status not changing for dropshipped POs and SOs (backport [#54934](https://github.com/frappe/erpnext/issues/54934)) ([#54937](https://github.com/frappe/erpnext/issues/54937)) ([3c571a1](3c571a1691))
* stock balance showing incorrect value because of incorrect SLE ([0b3344b](0b3344bad9))
* **stock:** add whole number quantity validation in Stock Reconciliation (backport [#54922](https://github.com/frappe/erpnext/issues/54922)) ([#54925](https://github.com/frappe/erpnext/issues/54925)) ([c499454](c4994548c3))
* **stock:** ignore fetching warehouse account for asset items (backport [#54403](https://github.com/frappe/erpnext/issues/54403)) ([#54961](https://github.com/frappe/erpnext/issues/54961)) ([5e5b5cf](5e5b5cfa0c))
* **stock:** update buying amount calculation in gross profit report (backport [#55020](https://github.com/frappe/erpnext/issues/55020)) ([#55024](https://github.com/frappe/erpnext/issues/55024)) ([8870619](88706192d7))
* styling in trial_balance.html and print format ([9a18d31](9a18d318d9))
* toast message for item price insert ([#55009](https://github.com/frappe/erpnext/issues/55009)) ([c967792](c967792ccb))
* use route_options for Credit Note and Debit Note sidebar links (backport [#55026](https://github.com/frappe/erpnext/issues/55026)) ([#55063](https://github.com/frappe/erpnext/issues/55063)) ([1941c3b](1941c3b136))
* **UX:** Buying settings form cleanup ([#54731](https://github.com/frappe/erpnext/issues/54731)) ([e7ae296](e7ae296614))
* **UX:** Item master form cleanup ([#54538](https://github.com/frappe/erpnext/issues/54538)) ([0eb049c](0eb049cd85))
* validate company region in uae vat 201 (backport [#54899](https://github.com/frappe/erpnext/issues/54899)) ([#55055](https://github.com/frappe/erpnext/issues/55055)) ([4015c2b](4015c2b9a4))
* warn when accounting dimension fieldname conflicts with existing fields (backport [#55036](https://github.com/frappe/erpnext/issues/55036)) ([#55062](https://github.com/frappe/erpnext/issues/55062)) ([68a5eae](68a5eae3ff))

### Features

* add print format for accounts payable report ([1c6dc80](1c6dc80b70))
* introduce print format for Accounts Receivable report ([4e7f2ee](4e7f2eeaa0))
* introduce print formats for financial statements ([3283c46](3283c461f1))
* print format for report trial balance ([1d08448](1d08448d1a))

### Reverts

* Revert "fix: debit credit not equal in purchase transactions for mult… (backport [#54906](https://github.com/frappe/erpnext/issues/54906)) ([#54908](https://github.com/frappe/erpnext/issues/54908)) ([0d07083](0d07083299))
2026-05-20 04:10:54 +00:00
diptanilsaha
fb7f820885 Merge pull request #55051 from frappe/version-16-hotfix
chore: release v16
2026-05-20 09:39:15 +05:30
ruthra kumar
799d6d159c Merge pull request #54960 from frappe/mergify/bp/version-16/pr-54941
fix: flag to disable opening balance calculation in general ledger (backport #54941)
2026-05-15 14:31:57 +05:30
ruthra kumar
48f59a033f refactor: flag to disable opening balance calculation
(cherry picked from commit 28a2230d02)
2026-05-15 07:32:52 +00:00
Frappe PR Bot
2807c9f08f chore(release): Bumped to Version 16.18.3
## [16.18.3](https://github.com/frappe/erpnext/compare/v16.18.2...v16.18.3) (2026-05-14)

### Bug Fixes

* status not changing for dropshipped POs and SOs (backport [#54934](https://github.com/frappe/erpnext/issues/54934)) (backport [#54937](https://github.com/frappe/erpnext/issues/54937)) ([#54938](https://github.com/frappe/erpnext/issues/54938)) ([5271773](5271773595))
2026-05-14 09:39:02 +00:00
mergify[bot]
5271773595 fix: status not changing for dropshipped POs and SOs (backport #54934) (backport #54937) (#54938)
fix: status not changing for dropshipped POs and SOs (backport #54934) (#54937)

fix: status not changing for dropshipped POs and SOs (#54934)

* fix: status not changing for dropshipped POs and SOs

* test: change test case to accomodate new flow

(cherry picked from commit 78a79120ea)


(cherry picked from commit 3c571a1691)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2026-05-14 09:37:26 +00:00
Frappe PR Bot
dd35cd1f84 chore(release): Bumped to Version 16.18.2
## [16.18.2](https://github.com/frappe/erpnext/compare/v16.18.1...v16.18.2) (2026-05-14)

### Bug Fixes

* posting date and time ([ab09029](ab090295d9))
2026-05-14 05:35:39 +00:00
rohitwaghchaure
77a6299e8b Merge pull request #54931 from frappe/mergify/bp/version-16/pr-54928
fix: posting date and time (backport #54905) (backport #54928)
2026-05-14 11:04:07 +05:30
rohitwaghchaure
b79ec7cbdd chore: fix linter issue
(cherry picked from commit 3c993377aa)
(cherry picked from commit 21ada7799c)
2026-05-14 02:04:52 +00:00
rohitwaghchaure
927360dd1d chore: fixed test case
(cherry picked from commit c740f77a6f)
(cherry picked from commit f4e66914c6)
2026-05-14 02:04:52 +00:00
Rohit Waghchaure
ab090295d9 fix: posting date and time
(cherry picked from commit fb6c05f186)
(cherry picked from commit 1c44c60dbd)
2026-05-14 02:04:51 +00:00
Frappe PR Bot
c4b7b15824 chore(release): Bumped to Version 16.18.1
## [16.18.1](https://github.com/frappe/erpnext/compare/v16.18.0...v16.18.1) (2026-05-13)

### Reverts

* Revert "fix: debit credit not equal in purchase transactions for mult… (backport [#54906](https://github.com/frappe/erpnext/issues/54906)) (backport [#54908](https://github.com/frappe/erpnext/issues/54908)) ([#54916](https://github.com/frappe/erpnext/issues/54916)) ([cfd3847](cfd3847255))
2026-05-13 10:16:21 +00:00
mergify[bot]
cfd3847255 Revert "fix: debit credit not equal in purchase transactions for mult… (backport #54906) (backport #54908) (#54916)
Revert "fix: debit credit not equal in purchase transactions for mult… (backport #54906) (#54908)

Revert "fix: debit credit not equal in purchase transactions for mult… (#54906)

* Revert "fix: debit credit not equal in purchase transactions for multi currency"

This reverts commit 75bcea57f4.

* Revert "test: add test case"

This reverts commit 1d30a202c3.

* Revert "fix: include rejected qty in tax (purchase receipt)"

This reverts commit 8c9a88abbe.

(cherry picked from commit cf5e8ce878)


(cherry picked from commit 0d07083299)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2026-05-13 10:14:46 +00:00
Frappe PR Bot
dc914adb62 chore(release): Bumped to Version 16.18.0
# [16.18.0](https://github.com/frappe/erpnext/compare/v16.17.0...v16.18.0) (2026-05-12)

### Bug Fixes

* added permission validation for `deactivate_sales_person` (backport [#54884](https://github.com/frappe/erpnext/issues/54884)) ([#54886](https://github.com/frappe/erpnext/issues/54886)) ([98de025](98de025a09))
* check if item is dropshipped before updating quantity (backport [#54825](https://github.com/frappe/erpnext/issues/54825)) ([#54827](https://github.com/frappe/erpnext/issues/54827)) ([0db7e1e](0db7e1e56b))
* **crm:** handle empty _assign in appointment auto assignment (backport [#54782](https://github.com/frappe/erpnext/issues/54782)) ([#54795](https://github.com/frappe/erpnext/issues/54795)) ([f36bdaa](f36bdaadae))
* decimal issue ([8b9b83a](8b9b83a9df))
* do not rely on client side to update quantities during partial d… (backport [#54804](https://github.com/frappe/erpnext/issues/54804)) ([#54821](https://github.com/frappe/erpnext/issues/54821)) ([f24b556](f24b556336))
* fetch get_item_tax_template while update items (backport [#53708](https://github.com/frappe/erpnext/issues/53708)) ([#54767](https://github.com/frappe/erpnext/issues/54767)) ([4fbaea1](4fbaea17f8))
* incorrect serial nos picked during disassemble (backport [#54757](https://github.com/frappe/erpnext/issues/54757)) ([#54760](https://github.com/frappe/erpnext/issues/54760)) ([66ae590](66ae590adc))
* incorrect validation thrown for drop shipped PI (backport [#54751](https://github.com/frappe/erpnext/issues/54751)) ([#54753](https://github.com/frappe/erpnext/issues/54753)) ([379ebbe](379ebbe8c4))
* raw material should not have target warehouse in manufacture entry (backport [#54849](https://github.com/frappe/erpnext/issues/54849)) ([#54861](https://github.com/frappe/erpnext/issues/54861)) ([3dbadfa](3dbadfadd5))
* rename supplier wise stock analytics report ([7086db1](7086db1e1c))
* **stock:** apply filters for rejected warehouse in pick list (backport [#54733](https://github.com/frappe/erpnext/issues/54733)) ([#54776](https://github.com/frappe/erpnext/issues/54776)) ([cf0d9df](cf0d9dfbfd))
* **stock:** ignore reserved qty for stock levels in batch (backport [#54790](https://github.com/frappe/erpnext/issues/54790)) ([#54797](https://github.com/frappe/erpnext/issues/54797)) ([338d190](338d1904c1))
* **stock:** priorities pick list parent warehouse (backport [#54788](https://github.com/frappe/erpnext/issues/54788)) ([#54793](https://github.com/frappe/erpnext/issues/54793)) ([d3bc629](d3bc629f68))
* **task:** update depends_on for closing date and review date [#54850](https://github.com/frappe/erpnext/issues/54850) (backport [#54852](https://github.com/frappe/erpnext/issues/54852)) ([#54863](https://github.com/frappe/erpnext/issues/54863)) ([b962a1a](b962a1a0cd))
* validate variant values (backport [#54831](https://github.com/frappe/erpnext/issues/54831)) ([#54839](https://github.com/frappe/erpnext/issues/54839)) ([87b798b](87b798b936))

### Features

* partial delivery in dropshipping (backport [#54787](https://github.com/frappe/erpnext/issues/54787)) ([#54800](https://github.com/frappe/erpnext/issues/54800)) ([f64f871](f64f871d45))
* Philippines chart of account (backport [#53918](https://github.com/frappe/erpnext/issues/53918)) ([#54888](https://github.com/frappe/erpnext/issues/54888)) ([8f03108](8f0310859d))
2026-05-12 18:49:27 +00:00
diptanilsaha
41bff45d7a Merge pull request #54865 from frappe/version-16-hotfix
chore: release v16
2026-05-13 00:17:54 +05:30
Frappe PR Bot
7b494dc9e8 chore(release): Bumped to Version 16.17.0
# [16.17.0](https://github.com/frappe/erpnext/compare/v16.16.0...v16.17.0) (2026-05-05)

### Bug Fixes

* accounts and account types in German CoA "SKR 03" (backport [#54711](https://github.com/frappe/erpnext/issues/54711)) ([#54713](https://github.com/frappe/erpnext/issues/54713)) ([982810a](982810a700))
* add missing fields in set_currency_labels (backport [#54689](https://github.com/frappe/erpnext/issues/54689)) ([#54690](https://github.com/frappe/erpnext/issues/54690)) ([bca893a](bca893a508))
* Backfill `not_applicable` on Item Tax Template Details for German companies (backport [#54682](https://github.com/frappe/erpnext/issues/54682)) ([#54686](https://github.com/frappe/erpnext/issues/54686)) ([a22d773](a22d773341))
* copy project from first row to new rows (backport [#53295](https://github.com/frappe/erpnext/issues/53295)) ([#54620](https://github.com/frappe/erpnext/issues/54620)) ([e24ab72](e24ab72c0d))
* correct project filter in buying doctypes (backport [#54644](https://github.com/frappe/erpnext/issues/54644)) ([#54652](https://github.com/frappe/erpnext/issues/54652)) ([86cf256](86cf256358))
* correct titles set to {customer_name} or {supplier_name} text strings (backport [#54656](https://github.com/frappe/erpnext/issues/54656)) ([#54669](https://github.com/frappe/erpnext/issues/54669)) ([38cfeb1](38cfeb1bb7))
* dont show serial/batch button when PR is submitted (backport [#54642](https://github.com/frappe/erpnext/issues/54642)) ([#54646](https://github.com/frappe/erpnext/issues/54646)) ([6dbc17d](6dbc17d71a))
* error when creating quotation from CRM (backport [#54722](https://github.com/frappe/erpnext/issues/54722)) ([#54725](https://github.com/frappe/erpnext/issues/54725)) ([2cd4c1a](2cd4c1a052))
* hide payment and payment request buttons based on permissions in invoices and orders (backport [#53920](https://github.com/frappe/erpnext/issues/53920)) ([#54736](https://github.com/frappe/erpnext/issues/54736)) ([e60490d](e60490dceb))
* incorrect expense account book in purchase return (backport [#54681](https://github.com/frappe/erpnext/issues/54681)) ([#54693](https://github.com/frappe/erpnext/issues/54693)) ([0dade2c](0dade2c38c))
* mark item tax templates as not applicable (backport [#54673](https://github.com/frappe/erpnext/issues/54673)) ([#54677](https://github.com/frappe/erpnext/issues/54677)) ([126e13b](126e13be25))
* **payment_entry:** convert the date args to string type before escaping in `get_outstanding_reference_documents` (backport [#54639](https://github.com/frappe/erpnext/issues/54639)) ([#54648](https://github.com/frappe/erpnext/issues/54648)) ([19a8ebe](19a8ebe8a5))
* **project:** use user.email for invitations and skip disabled users. (backport [#54561](https://github.com/frappe/erpnext/issues/54561)) ([#54667](https://github.com/frappe/erpnext/issues/54667)) ([288cdf3](288cdf3bf0))
* py error on sales forecast doctype (backport [#54641](https://github.com/frappe/erpnext/issues/54641)) ([#54643](https://github.com/frappe/erpnext/issues/54643)) ([7bd360a](7bd360aa29))
* Remove bom stock report link from manufacturing workspace ([0f27881](0f27881fed))
* **selling:** blanket order ordered qty recalculation on sales order status change (backport [#54593](https://github.com/frappe/erpnext/issues/54593)) ([#54623](https://github.com/frappe/erpnext/issues/54623)) ([9db03bc](9db03bc520))
* set valid_from in created Item Price (backport [#54696](https://github.com/frappe/erpnext/issues/54696)) ([#54700](https://github.com/frappe/erpnext/issues/54700)) ([bbb4e79](bbb4e79d0a))
* show correct status in Serial No Ledger (backport [#54567](https://github.com/frappe/erpnext/issues/54567)) ([#54626](https://github.com/frappe/erpnext/issues/54626)) ([d6f2ff6](d6f2ff6b87))
* show in and out qty in the stock ledger report for stock recos ([d27cf48](d27cf48b19))
* skip depreciation rescheduling when asset is fully depreciated on sale ([d3c893d](d3c893d08b))
* skip rescheduling only for asset being disposed ([07a957c](07a957c164))
* use RecoverableErrors isinstance check for repost timeout status (backport [#54543](https://github.com/frappe/erpnext/issues/54543)) ([#54649](https://github.com/frappe/erpnext/issues/54649)) ([b300159](b3001595ab))

### Features

* copy terms attachments to transactions (backport [#53403](https://github.com/frappe/erpnext/issues/53403)) ([#54661](https://github.com/frappe/erpnext/issues/54661)) ([bd932da](bd932da08b))
* **ux:** Naming series dialog ([#54554](https://github.com/frappe/erpnext/issues/54554)) ([48ebb4c](48ebb4ca61))

### Performance Improvements

* max recursion depth error in serial no (backport [#54629](https://github.com/frappe/erpnext/issues/54629)) ([#54631](https://github.com/frappe/erpnext/issues/54631)) ([808214f](808214fd95))
2026-05-05 16:32:20 +00:00
diptanilsaha
ed69dafbe8 Merge pull request #54740 from frappe/version-16-hotfix 2026-05-05 22:00:39 +05:30
Frappe PR Bot
4d5c665e22 chore(release): Bumped to Version 16.16.0
# [16.16.0](https://github.com/frappe/erpnext/compare/v16.15.1...v16.16.0) (2026-04-28)

### Bug Fixes

* **`get_stock_balance`:** validate inventory dimension fieldnames (backport [#54587](https://github.com/frappe/erpnext/issues/54587)) ([#54589](https://github.com/frappe/erpnext/issues/54589)) ([9f04fcc](9f04fcc190))
* add filter labels and required filters for financial report validation ([e6f0bb6](e6f0bb66e2))
* add party type for dynamic link support ([c6d4802](c6d4802857))
* always exclude pcv entries except for closing account head ([446c111](446c111653))
* avoid double reduction of pe reference outstanding (backport [#54193](https://github.com/frappe/erpnext/issues/54193)) ([#54613](https://github.com/frappe/erpnext/issues/54613)) ([5de4b01](5de4b013ea))
* correct display depends on condition ([#54556](https://github.com/frappe/erpnext/issues/54556)) ([0df38a8](0df38a841e))
* debit credit not equal in purchase transactions for multi currency (backport [#54456](https://github.com/frappe/erpnext/issues/54456)) ([#54564](https://github.com/frappe/erpnext/issues/54564)) ([d9a9a5b](d9a9a5bcde))
* delivery schedule in the sales order ([386f499](386f49978e))
* duplicate entries being shown in batch exists in future transact… (backport [#54604](https://github.com/frappe/erpnext/issues/54604)) ([#54606](https://github.com/frappe/erpnext/issues/54606)) ([1111771](11117710d3))
* **edi:** restrict Code List imports to files and trusted backend URLs (backport [#54137](https://github.com/frappe/erpnext/issues/54137)) ([#54266](https://github.com/frappe/erpnext/issues/54266)) ([2a244d1](2a244d162b)), closes [#54488](https://github.com/frappe/erpnext/issues/54488)
* ensure fiscal year is checked before validating date filters in financial statements ([fba7871](fba78711cc))
* ensure tax withholding entries respect date range of category ([719d982](719d982a07))
* filter opening entries in first year in custom financial statement ([6bd6e62](6bd6e62c8c))
* filter overdue purchase order items by company (backport [#54099](https://github.com/frappe/erpnext/issues/54099)) ([#54611](https://github.com/frappe/erpnext/issues/54611)) ([8f8bf13](8f8bf13b41))
* hide feature flag controlled fields on install ([45dc2c4](45dc2c40fd))
* make inv dimen reqd only in delivery note (backport [#54546](https://github.com/frappe/erpnext/issues/54546)) ([#54552](https://github.com/frappe/erpnext/issues/54552)) ([d56df96](d56df96f73))
* **manufacturing:** remove conversion factor for stock qty (backport [#54525](https://github.com/frappe/erpnext/issues/54525)) ([#54573](https://github.com/frappe/erpnext/issues/54573)) ([f14751d](f14751d538))
* negative quantity check in validate_item_qty (backport [#54559](https://github.com/frappe/erpnext/issues/54559)) ([#54572](https://github.com/frappe/erpnext/issues/54572)) ([f7fa394](f7fa394aea))
* **payment_entry:** escape arguments on invoice and order fetching sql queries (backport [#54582](https://github.com/frappe/erpnext/issues/54582)) ([#54586](https://github.com/frappe/erpnext/issues/54586)) ([5289aa0](5289aa0ab3))
* **PCV:** set correct filters of `from_date` and `to_date` on General Ledger Report on clicking `Ledger` button (backport [#54522](https://github.com/frappe/erpnext/issues/54522)) ([#54524](https://github.com/frappe/erpnext/issues/54524)) ([f3996fb](f3996fb971))
* preserve inventory dimensions when raw materials are reset (backport [#54440](https://github.com/frappe/erpnext/issues/54440)) ([#54493](https://github.com/frappe/erpnext/issues/54493)) ([456e99b](456e99b352))
* py error on stock ageing report (backport [#54467](https://github.com/frappe/erpnext/issues/54467)) ([#54469](https://github.com/frappe/erpnext/issues/54469)) ([090aab3](090aab33fb))
* skip BudgetValidation when cancelling GL entries ([1b14673](1b146738c4))
* **stock:** add stock entry in batch master connection ([62bbe28](62bbe28a72))
* **stock:** remove validation for transfer_qty field (backport [#54542](https://github.com/frappe/erpnext/issues/54542)) ([#54545](https://github.com/frappe/erpnext/issues/54545)) ([cc85370](cc85370d54))
* **stock:** set incoming rate as zero for outward sle (backport [#54514](https://github.com/frappe/erpnext/issues/54514)) ([#54533](https://github.com/frappe/erpnext/issues/54533)) ([cabea2f](cabea2f288))
* **stock:** show available qty in warehouse link field (backport [#54474](https://github.com/frappe/erpnext/issues/54474)) ([#54484](https://github.com/frappe/erpnext/issues/54484)) ([f7b87ed](f7b87ed0e3))
* **stock:** show item code in serial and batch selector dialog ([85d1eb8](85d1eb8379))
* summing of values could be zero even if values exist ([d51ce66](d51ce66cb2))
* update account identification to avoid using name_field in financial statements ([7b60ec8](7b60ec8457))
* update fiscal year filter to use mandatory_depends_on instead of reqd ([6570796](6570796fba))
* update status of quotation in patch (backport [#54577](https://github.com/frappe/erpnext/issues/54577)) ([#54580](https://github.com/frappe/erpnext/issues/54580)) ([134e4b7](134e4b7446))

### Features

* add setting to hide Subscription references across doctypes ([#54576](https://github.com/frappe/erpnext/issues/54576)) ([15b6633](15b6633fc3))
* Add XLSX styling support to custom financial report templates ([#52612](https://github.com/frappe/erpnext/issues/52612)) ([055ff56](055ff56ce4))
* Add XLSX styling support to custom financial report templates (backport [#52612](https://github.com/frappe/erpnext/issues/52612)) ([#54485](https://github.com/frappe/erpnext/issues/54485)) ([df3fbed](df3fbeded2))
* danish_bosnian_address_template (backport [#54093](https://github.com/frappe/erpnext/issues/54093)) ([#54516](https://github.com/frappe/erpnext/issues/54516)) ([5c0d2cb](5c0d2cb474))
* enhance account category with root type ([#53190](https://github.com/frappe/erpnext/issues/53190)) ([96bab08](96bab08ae0))
2026-04-28 21:03:29 +00:00
diptanilsaha
e09487d140 Merge pull request #54583 from frappe/version-16-hotfix 2026-04-29 02:31:54 +05:30
63 changed files with 164 additions and 921 deletions

View File

@@ -6,7 +6,7 @@ import frappe
from frappe.model.document import Document
from frappe.utils.user import is_website_user
__version__ = "16.15.1"
__version__ = "16.23.1"
def get_default_company(user=None):

View File

@@ -22,13 +22,11 @@ class TestAdvancePaymentLedgerEntry(ERPNextTestSuite, AccountsTestMixin):
"""
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.supplier = "_Test Supplier"
self.item = "_Test Item"
self.cash = "Cash - _TC"
self.debtors_usd = "_Test Receivable USD - _TC"
self.creditors_usd = "_Test Payable USD - _TC"
self.create_company()
self.create_usd_receivable_account()
self.create_usd_payable_account()
self.create_item()
self.clear_old_entries()
def create_sales_order(self, qty=1, rate=100, currency="INR", do_not_submit=False):
"""

View File

@@ -9,13 +9,6 @@ cur_frm.add_fetch("bank", "swift_number", "swift_number");
frappe.ui.form.on("Bank Guarantee", {
setup: function (frm) {
frm.set_query("reference_doctype", function () {
return {
filters: {
name: ["in", ["Sales Order", "Purchase Order"]],
},
};
});
frm.set_query("bank_account", function () {
return {
filters: {

View File

@@ -1,6 +1,5 @@
{
"actions": [],
"allow_bulk_edit": 1,
"autoname": "ACC-BG-.YYYY.-.#####",
"creation": "2016-12-17 10:43:35.731631",
"doctype": "DocType",
@@ -51,7 +50,8 @@
"fieldname": "reference_doctype",
"fieldtype": "Link",
"label": "Reference Document Type",
"options": "DocType"
"options": "DocType",
"read_only": 1
},
{
"fieldname": "reference_docname",
@@ -60,14 +60,14 @@
"options": "reference_doctype"
},
{
"depends_on": "eval: doc.reference_doctype == \"Sales Order\"",
"depends_on": "eval: doc.bg_type == \"Receiving\"",
"fieldname": "customer",
"fieldtype": "Link",
"label": "Customer",
"options": "Customer"
},
{
"depends_on": "eval: doc.reference_doctype == \"Purchase Order\"",
"depends_on": "eval: doc.bg_type == \"Providing\"",
"fieldname": "supplier",
"fieldtype": "Link",
"label": "Supplier",
@@ -218,11 +218,10 @@
"grid_page_length": 50,
"is_submittable": 1,
"links": [],
"modified": "2026-05-25 18:12:10.768835",
"modified": "2025-08-29 11:52:33.550847",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Guarantee",
"naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{

View File

@@ -17,10 +17,9 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestBankReconciliationTool(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.bank = "HDFC - _TC"
self.debit_to = "Debtors - _TC"
self.create_company()
self.create_customer()
self.clear_old_entries()
bank_dt = qb.DocType("Bank")
qb.from_(bank_dt).delete().where(bank_dt.name == "HDFC").run()
self.create_bank_account()

View File

@@ -26,9 +26,9 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestBankStatementImportLog(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.bank = "HDFC - _TC"
self.create_company()
self.create_customer()
self.clear_old_entries()
bank_dt = qb.DocType("Bank")
qb.from_(bank_dt).delete().where(bank_dt.name == "HDFC").run()
self.create_bank_account()

View File

@@ -11,11 +11,9 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestBankTransactionRule(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.bank = "HDFC - _TC"
self.debit_to = "Debtors - _TC"
self.cash = "Cash - _TC"
self.create_company()
self.create_customer()
self.clear_old_entries()
bank_dt = qb.DocType("Bank")
qb.from_(bank_dt).delete().where(bank_dt.name == "HDFC").run()
self.create_bank_account()

View File

@@ -136,9 +136,6 @@ function set_total_budget_amount(frm) {
function toggle_distribution_fields(frm) {
const grid = frm.fields_dict.budget_distribution.grid;
frm.set_df_property("budget_distribution", "cannot_add_rows", true);
frm.set_df_property("budget_distribution", "cannot_delete_rows", true);
["amount", "percent"].forEach((field) => {
grid.update_docfield_property(field, "read_only", frm.doc.distribute_equally);
});

View File

@@ -355,8 +355,8 @@ class Budget(Document):
if self.should_regenerate_budget_distribution():
return
total_amount = sum(flt(d.amount) for d in self.budget_distribution)
total_percent = sum(flt(d.percent) for d in self.budget_distribution)
total_amount = sum(d.amount for d in self.budget_distribution)
total_percent = sum(d.percent for d in self.budget_distribution)
if flt(abs(total_amount - self.budget_amount), 2) > 0.10:
frappe.throw(

View File

@@ -18,7 +18,6 @@
"in_list_view": 1,
"label": "Start Date",
"read_only": 1,
"reqd": 1,
"search_index": 1
},
{
@@ -26,29 +25,26 @@
"fieldtype": "Date",
"in_list_view": 1,
"label": "End Date",
"read_only": 1,
"reqd": 1
"read_only": 1
},
{
"fieldname": "amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
"reqd": 1
"label": "Amount"
},
{
"fieldname": "percent",
"fieldtype": "Percent",
"in_list_view": 1,
"label": "Percent",
"reqd": 1
"label": "Percent"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2026-06-18 11:23:17.669733",
"modified": "2025-11-03 13:18:28.398198",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Budget Distribution",

View File

@@ -15,12 +15,12 @@ class BudgetDistribution(Document):
from frappe.types import DF
amount: DF.Currency
end_date: DF.Date
end_date: DF.Date | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
percent: DF.Percent
start_date: DF.Date
start_date: DF.Date | None
# end: auto-generated types
pass

View File

@@ -75,10 +75,7 @@ def validate_company(company):
@frappe.whitelist()
def import_coa(file_name, company):
frappe.only_for("Accounts Manager")
# delete existing data for accounts
frappe.has_permission("Company", "write", company, throw=True)
unset_existing_data(company)
# create accounts
@@ -454,7 +451,6 @@ def unset_existing_data(company):
fieldnames = get_linked_fields("Account").get("Company", {}).get("fieldname", [])
linked = [{"fieldname": name} for name in fieldnames]
update_values = {d.get("fieldname"): "" for d in linked}
frappe.db.set_value("Company", company, update_values, update_values)
# remove accounts data from various doctypes
@@ -466,7 +462,8 @@ def unset_existing_data(company):
"Sales Taxes and Charges Template",
"Purchase Taxes and Charges Template",
]:
frappe.get_query(doctype, delete=True, filters={"company": company}, ignore_permissions=False).run()
dt = frappe.qb.DocType(doctype)
frappe.qb.from_(dt).where(dt.company == company).delete().run()
def set_default_accounts(company):

View File

@@ -616,10 +616,6 @@ def calculate_exchange_rate_using_last_gle(company, account, party_type, party):
def get_account_details(
company, posting_date, account, party_type=None, party=None, rounding_loss_allowance: float | None = None
):
if not account:
return
frappe.has_permission("Account", doc=account, throw=True)
if not (company and posting_date):
frappe.throw(_("Company and Posting Date is mandatory"))

View File

@@ -15,11 +15,11 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestExchangeRateRevaluation(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.item = "_Test Item"
self.customer = "_Test Customer"
self.cost_center = "Main - _TC"
self.debtors_usd = "_Test Receivable USD - _TC"
self.create_company()
self.create_usd_receivable_account()
self.create_item()
self.create_customer()
self.clear_old_entries()
self.set_system_and_company_settings()
def set_system_and_company_settings(self):

View File

@@ -19,7 +19,6 @@ from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger
validate_docs_for_voucher_types,
)
from erpnext.accounts.doctype.tax_withholding_entry.tax_withholding_entry import JournalTaxWithholding
from erpnext.accounts.general_ledger import validate_opening_entry_against_pcv
from erpnext.accounts.party import get_party_account
from erpnext.accounts.utils import (
cancel_exchange_gain_loss_journal,
@@ -132,9 +131,6 @@ class JournalEntry(AccountsController):
if not self.is_opening:
self.is_opening = "No"
if self.is_opening == "Yes":
validate_opening_entry_against_pcv(self.company)
self.clearance_date = None
self.validate_party()

View File

@@ -12,11 +12,10 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestLedgerHealth(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.debit_to = "Debtors - _TC"
self.income_account = "Sales - _TC"
self.create_company()
self.create_customer()
self.configure_monitoring_tool()
self.clear_old_entries()
def configure_monitoring_tool(self):
monitor_settings = frappe.get_doc("Ledger Health Monitor")

View File

@@ -1206,9 +1206,9 @@ class PaymentEntry(AccountsController):
continue
if tax.add_deduct_tax == "Add":
included_taxes += flt(tax.base_tax_amount)
included_taxes += tax.base_tax_amount
else:
included_taxes -= flt(tax.base_tax_amount)
included_taxes -= tax.base_tax_amount
return included_taxes

View File

@@ -1113,27 +1113,6 @@ class TestPaymentEntry(ERPNextTestSuite):
self.assertEqual(gl_entries, expected_gl_entries)
def test_payment_entry_with_inclusive_tax(self):
# inclusive tax built server-side: base_tax_amount is None until apply_taxes()
payment_entry = create_payment_entry(paid_amount=1180)
payment_entry.append(
"taxes",
{
"account_head": "_Test Account Service Tax - _TC",
"charge_type": "On Paid Amount",
"rate": 18,
"included_in_paid_amount": 1,
"add_deduct_tax": "Add",
"description": "Service Tax",
},
)
payment_entry.save()
payment_entry.submit()
# 1180 incl 18% => 1000 base + 180 tax
self.assertEqual(flt(payment_entry.total_taxes_and_charges, 2), 180.0)
self.assertEqual(flt(payment_entry.unallocated_amount, 2), 1000.0)
def test_payment_entry_against_onhold_purchase_invoice(self):
pi = make_purchase_invoice()

View File

@@ -20,6 +20,7 @@ class TestPaymentLedgerEntry(ERPNextTestSuite):
self.create_company()
self.create_item()
self.create_customer()
self.clear_old_entries()
def create_company(self):
company_name = "_Test Payment Ledger"

View File

@@ -21,8 +21,10 @@ class TestProcessStatementOfAccounts(ERPNextTestSuite, AccountsTestMixin):
letterhead.is_default = 0
letterhead.save()
self.company = "_Test Company"
self.create_company()
self.create_customer()
self.create_customer(customer_name="Other Customer")
self.clear_old_entries()
self.si = create_sales_invoice()
create_sales_invoice(customer="Other Customer")

View File

@@ -3008,14 +3008,6 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
party_link.delete()
def test_purchase_invoice_cancellation_post_account_freezing_date(self):
pi = make_purchase_invoice()
frappe.db.set_value("Company", "_Test Company", "accounts_frozen_till_date", add_days(getdate(), 1))
try:
self.assertRaises(frappe.ValidationError, pi.cancel)
finally:
frappe.db.set_value("Company", "_Test Company", "accounts_frozen_till_date", None)
def set_advance_flag(company, flag, default_account):
frappe.db.set_value(

View File

@@ -16,14 +16,12 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestUnreconcilePayment(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.supplier = "_Test Supplier"
self.item = "_Test Item"
self.debit_to = "Debtors - _TC"
self.cost_center = "Main - _TC"
self.cash = "Cash - _TC"
self.debtors_usd = "_Test Receivable USD - _TC"
self.create_company()
self.create_customer()
self.create_supplier()
self.create_usd_receivable_account()
self.create_item()
self.clear_old_entries()
def create_sales_invoice(self, do_not_submit=False):
si = create_sales_invoice(
@@ -374,6 +372,7 @@ class TestUnreconcilePayment(ERPNextTestSuite, AccountsTestMixin):
self.assertEqual(so.advance_paid, 0)
def test_06_unreconcile_advance_from_payment_entry(self):
self.enable_advance_as_liability()
so1 = self.create_sales_order()
so2 = self.create_sales_order()
@@ -424,11 +423,7 @@ class TestUnreconcilePayment(ERPNextTestSuite, AccountsTestMixin):
self.disable_advance_as_liability()
def test_07_adv_from_so_to_invoice(self):
frappe.db.set_value("Company", self.company, "book_advance_payments_in_separate_party_account", True)
frappe.db.set_value(
"Company", self.company, "default_advance_received_account", "Advance Received - _TC"
)
self.enable_advance_as_liability()
so = self.create_sales_order()
pe = self.create_payment_entry()
pe.paid_amount = 1000

View File

@@ -716,7 +716,7 @@ def make_reverse_gl_entries(
partial_cancel=partial_cancel,
)
validate_accounting_period(gl_entries)
check_freezing_date(gl_entries[0]["posting_date"], gl_entries[0]["company"], adv_adj)
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
is_opening = any(d.get("is_opening") == "Yes" for d in gl_entries)
@@ -821,24 +821,13 @@ def check_freezing_date(posting_date, company, adv_adj=False):
)
def validate_opening_entry_against_pcv(company):
if frappe.db.exists("Period Closing Voucher", {"docstatus": 1, "company": company}):
def validate_against_pcv(is_opening, posting_date, company):
if is_opening and frappe.db.exists("Period Closing Voucher", {"docstatus": 1, "company": company}):
frappe.throw(
_(
"A Period Closing Voucher is already submitted and an Opening Entry can no longer be created. {0} to learn more."
).format(
'<a href="https://docs.frappe.io/erpnext/period-closing-voucher#14-pcv-and-opening-entries" target="_blank" rel="noopener">'
+ _("Read the docs")
+ "</a>"
),
_("Opening Entry can not be created after Period Closing Voucher is created."),
title=_("Invalid Opening Entry"),
)
def validate_against_pcv(is_opening, posting_date, company):
if is_opening:
validate_opening_entry_against_pcv(company)
last_pcv_date = frappe.db.get_value(
"Period Closing Voucher", {"docstatus": 1, "company": company}, [{"MAX": "period_end_date"}]
)

View File

@@ -9,10 +9,11 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestAccountsPayable(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.item = "_Test Item"
self.supplier = "_Test Supplier 2"
self.creditors_usd = "_Test Payable USD - _TC"
self.create_company()
self.create_customer()
self.create_item()
self.create_supplier(currency="USD", supplier_name="Test Supplier2")
self.create_usd_payable_account()
def test_accounts_payable_for_foreign_currency_supplier(self):
pi = self.create_purchase_invoice(do_not_submit=True)

View File

@@ -12,17 +12,11 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestAccountsReceivable(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.company_abbr = "_TC"
self.customer = "_Test Customer"
self.item = "_Test Item"
self.cost_center = "Main - _TC"
self.warehouse = "Stores - _TC"
self.income_account = "Sales - _TC"
self.expense_account = "Cost of Goods Sold - _TC"
self.debit_to = "Debtors - _TC"
self.cash = "Cash - _TC"
self.debtors_usd = "_Test Receivable USD - _TC"
self.create_company()
self.create_customer()
self.create_item()
self.create_usd_receivable_account()
self.clear_old_entries()
def create_sales_invoice(self, no_payment_schedule=False, do_not_submit=False, **args):
frappe.set_user("Administrator")

View File

@@ -11,11 +11,10 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestAccountsReceivable(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.maxDiff = None
self.company = "_Test Company"
self.customer = "_Test Customer"
self.item = "_Test Item"
self.debit_to = "Debtors - _TC"
self.cost_center = "Main - _TC"
self.create_company()
self.create_customer()
self.create_item()
self.clear_old_entries()
def test_01_receivable_summary_output(self):
"""

View File

@@ -84,13 +84,7 @@ def build_budget_map(budget_records, filters):
budget_distributions = get_budget_distributions(budget)
for row in budget_distributions:
if not row.start_date or not row.end_date:
continue
months = get_months_in_range(row.start_date, row.end_date)
if not months:
continue
monthly_budget = flt(row.amount) / len(months)
for month_date in months:

View File

@@ -12,12 +12,10 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestCustomerLedgerSummary(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.item = "_Test Item"
self.debit_to = "Debtors - _TC"
self.cost_center = "Main - _TC"
self.cash = "Cash - _TC"
self.create_company()
self.create_customer()
self.create_item()
self.clear_old_entries()
def create_sales_invoice(self, do_not_submit=False, **args):
si = create_sales_invoice(

View File

@@ -61,16 +61,11 @@ class TestDeferredRevenueAndExpense(ERPNextTestSuite, AccountsTestMixin):
)
def setUp(self):
self.company = "_Test Company"
self.company_abbr = "_TC"
self.customer = "_Test Customer"
self.supplier = "_Test Supplier"
self.warehouse = "Stores - _TC"
self.debit_to = "Debtors - _TC"
self.cost_center = "Main - _TC"
self.income_account = "Sales - _TC"
self.expense_account = "Cost of Goods Sold - _TC"
self.create_company()
self.create_customer("_Test Customer")
self.create_supplier("_Test Furniture Supplier")
self.setup_deferred_accounts_and_items()
self.clear_old_entries()
@ERPNextTestSuite.change_settings("Accounts Settings", {"book_deferred_entries_based_on": "Months"})
def test_deferred_revenue(self):

View File

@@ -12,13 +12,7 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestGeneralAndPaymentLedger(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.debit_to = "Debtors - _TC"
self.expense_account = "Cost of Goods Sold - _TC"
self.cost_center = "Main - _TC"
self.income_account = "Sales - _TC"
self.warehouse = "Stores - _TC"
self.creditors = "Creditors - _TC"
self.create_company()
self.cleanup()
def cleanup(self):

View File

@@ -14,6 +14,7 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestGeneralLedger(ERPNextTestSuite):
def setUp(self):
self.company = "_Test Company"
self.clear_old_entries()
def clear_old_entries(self):
doctype_list = [

View File

@@ -18,6 +18,8 @@ class TestGrossProfit(ERPNextTestSuite):
self.create_item()
self.create_bundle()
self.create_customer()
self.create_sales_invoice()
self.clear_old_entries()
def create_company(self):
company_name = "_Test Gross Profit"

View File

@@ -9,9 +9,9 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestItemWisePurchaseRegister(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.supplier = "_Test Supplier"
self.item = "_Test Item"
self.create_company()
self.create_supplier()
self.create_item()
def create_purchase_invoice(self, do_not_submit=False):
pi = make_purchase_invoice(

View File

@@ -9,11 +9,9 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestItemWiseSalesRegister(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.item = "_Test Item"
self.debit_to = "Debtors - _TC"
self.cost_center = "Main - _TC"
self.create_company()
self.create_customer()
self.create_item()
def create_sales_invoice(self, item=None, taxes=None, do_not_submit=False):
si = create_sales_invoice(

View File

@@ -14,11 +14,9 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestProfitAndLossStatement(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.item = "_Test Item"
self.debit_to = "Debtors - _TC"
self.cost_center = "Main - _TC"
self.create_company()
self.create_customer()
self.create_item()
def create_sales_invoice(self, qty=1, rate=150, no_payment_schedule=False, do_not_submit=False):
frappe.set_user("Administrator")

View File

@@ -10,13 +10,9 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestItemWiseSalesRegister(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.customer = "_Test Customer"
self.item = "_Test Item"
self.debit_to = "Debtors - _TC"
self.cost_center = "Main - _TC"
self.income_account = "Sales - _TC"
self.cash = "Cash - _TC"
self.create_company()
self.create_customer()
self.create_item()
self.create_child_cost_center()
def create_child_cost_center(self):

View File

@@ -9,9 +9,10 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestSupplierLedgerSummary(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.supplier = "_Test Supplier"
self.item = "_Test Item"
self.create_company()
self.create_supplier()
self.create_item()
self.clear_old_entries()
def create_purchase_invoice(self, do_not_submit=False):
frappe.set_user("Administrator")

View File

@@ -20,7 +20,8 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestTaxWithholdingDetails(ERPNextTestSuite, AccountsTestMixin):
def setUp(self):
self.company = "_Test Company"
self.create_company()
self.clear_old_entries()
create_records()
def test_tax_withholding_for_customers(self):

View File

@@ -146,6 +146,7 @@ def get_appropriate_company(filters):
return company
@frappe.whitelist()
def get_invoiced_item_gross_margin(sales_invoice=None, item_code=None, company=None, with_item_data=False):
from erpnext.accounts.report.gross_profit.gross_profit import GrossProfitGenerator

View File

@@ -7,7 +7,6 @@ import json
import frappe
from frappe import _
from frappe.query_builder import Case
from frappe.utils import cstr, flt
from erpnext.utilities.product import get_item_codes_by_attributes
@@ -130,53 +129,6 @@ def validate_is_incremental(numeric_attribute, attribute, value, item):
)
def get_attribute_value_renames(item_attribute):
"""Return old to new attribute value mappings for renamed Item Attribute Value rows."""
if item_attribute.numeric_values:
return {}
db_value = item_attribute.get_doc_before_save()
if not db_value:
return {}
old_values = {d.name: d.attribute_value for d in db_value.item_attribute_values}
renames = {}
for row in item_attribute.item_attribute_values:
if row.name in old_values and old_values[row.name] != row.attribute_value:
renames[old_values[row.name]] = row.attribute_value
return renames
def update_variant_attribute_values(item_attribute):
"""Propagate renamed Item Attribute Values to Item Variant Attribute on variant items."""
value_map = get_attribute_value_renames(item_attribute)
if not value_map:
return
item_variant_table = frappe.qb.DocType("Item Variant Attribute")
item_table = frappe.qb.DocType("Item")
attribute_value = item_variant_table.attribute_value
attribute_value_case = Case()
for old_value, new_value in value_map.items():
attribute_value_case = attribute_value_case.when(attribute_value == old_value, new_value)
(
frappe.qb.update(item_variant_table)
.join(item_table)
.on(item_table.name == item_variant_table.parent)
.set(attribute_value, attribute_value_case.else_(attribute_value))
.where(item_table.variant_of.isnotnull())
.where(item_table.variant_of != "")
.where(item_variant_table.attribute == item_attribute.name)
.where(attribute_value.isin(list(value_map)))
).run()
frappe.flags.attribute_values = None
def validate_item_attribute_value(attributes_list, attribute, attribute_value, item, from_variant=True):
allow_rename_attribute_value = frappe.db.get_single_value(
"Item Variant Settings", "allow_rename_attribute_value"

View File

@@ -445,8 +445,6 @@ def make_return_doc(doctype: str, source_name: str, target_doc=None, return_agai
doc.pricing_rules = []
doc.return_against = source.name
doc.set_warehouse = ""
if doctype == "Sales Invoice":
doc.is_debit_note = 0
if doctype == "Sales Invoice" or doctype == "POS Invoice":
doc.is_pos = source.is_pos

View File

@@ -22,14 +22,6 @@ from erpnext.controllers.sales_and_purchase_return import (
filter_serial_batches,
make_serial_batch_bundle_for_return,
)
# Re-exported for backward compatibility; canonical home is erpnext.exceptions.
from erpnext.exceptions import (
BatchExpiredError,
QualityInspectionNotSubmittedError,
QualityInspectionRejectedError,
QualityInspectionRequiredError,
)
from erpnext.setup.doctype.brand.brand import get_brand_defaults
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
from erpnext.stock import get_warehouse_account_map
@@ -45,6 +37,22 @@ from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle impor
from erpnext.stock.stock_ledger import get_items_to_be_repost
class QualityInspectionRequiredError(frappe.ValidationError):
pass
class QualityInspectionRejectedError(frappe.ValidationError):
pass
class QualityInspectionNotSubmittedError(frappe.ValidationError):
pass
class BatchExpiredError(frappe.ValidationError):
pass
class StockController(AccountsController):
def validate(self):
super().validate()
@@ -2155,7 +2163,7 @@ def check_item_quality_inspection(doctype: str, docstatus: str | int, items: str
inspection_fieldname = inspection_fieldname_map.get(doctype)
if inspection_fieldname is None:
return items if doctype == "Stock Entry" else []
return []
allow_after_transaction = cint(docstatus) == 1 and frappe.get_single_value(
"Stock Settings", "allow_to_make_quality_inspection_after_purchase_or_delivery"

View File

@@ -743,14 +743,7 @@ class SubcontractingInwardController:
"name": ["in", list(data.keys())],
"docstatus": 1,
},
fields=[
"rate",
"name",
"required_qty",
"received_qty",
"returned_qty",
"consumed_qty",
],
fields=["rate", "name", "required_qty", "received_qty"],
)
doc_updates = {}
@@ -758,17 +751,13 @@ class SubcontractingInwardController:
current_qty = flt(data[d.name].transfer_qty) * (1 if self._action == "submit" else -1)
current_rate = flt(data[d.name].rate)
# Weighted average rate must be computed on the on-hand balance
balance_qty = d.received_qty - d.returned_qty - d.consumed_qty
old_total = d.rate * balance_qty
# Calculate weighted average rate
old_total = d.rate * d.received_qty
current_total = current_rate * current_qty
new_balance_qty = balance_qty + current_qty
d.received_qty = d.received_qty + current_qty
d.rate = (
flt((old_total + current_total) / new_balance_qty, precision)
if new_balance_qty > 0
else 0.0
flt((old_total + current_total) / d.received_qty, precision) if d.received_qty else 0.0
)
if not d.required_qty and not d.received_qty:

View File

@@ -28,20 +28,3 @@ class MandatoryAccountDimensionError(frappe.ValidationError):
class ReportingCurrencyExchangeNotFoundError(frappe.ValidationError):
pass
# stock
class QualityInspectionRequiredError(frappe.ValidationError):
pass
class QualityInspectionRejectedError(frappe.ValidationError):
pass
class QualityInspectionNotSubmittedError(frappe.ValidationError):
pass
class BatchExpiredError(frappe.ValidationError):
pass

View File

@@ -483,4 +483,3 @@ erpnext.patches.v16_0.fix_titles
erpnext.patches.v16_0.set_not_applicable_on_german_item_tax_templates
erpnext.patches.v16_0.clear_procedures_from_receivable_report
erpnext.patches.v16_0.migrate_address_contact_custom_fields
erpnext.patches.v16_0.drop_redundant_serial_no_index_from_sabb

View File

@@ -1,7 +0,0 @@
from frappe.database.utils import drop_index_if_exists
def execute():
drop_index_if_exists("tabSerial and Batch Entry", "serial_no")
drop_index_if_exists("tabSerial and Batch Entry", "warehouse")
drop_index_if_exists("tabSerial and Batch Entry", "type_of_transaction")

View File

@@ -389,13 +389,11 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
);
}
const incoming_doctypes = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"];
const incoming_purposes = ["Manufacture", "Material Receipt"];
const inspection_type =
incoming_doctypes.includes(this.frm.doc.doctype) ||
(this.frm.doc.doctype === "Stock Entry" && incoming_purposes.includes(this.frm.doc.purpose))
? "Incoming"
: "Outgoing";
const inspection_type = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(
this.frm.doc.doctype
)
? "Incoming"
: "Outgoing";
let quality_inspection_field = this.frm.get_docfield("items", "quality_inspection");
quality_inspection_field.get_route_options_for_new_doc = function (row) {
@@ -2887,13 +2885,11 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
];
const me = this;
const incoming_doctypes = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"];
const incoming_purposes = ["Manufacture", "Material Receipt"];
const inspection_type =
incoming_doctypes.includes(this.frm.doc.doctype) ||
(this.frm.doc.doctype === "Stock Entry" && incoming_purposes.includes(this.frm.doc.purpose))
? "Incoming"
: "Outgoing";
const inspection_type = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(
this.frm.doc.doctype
)
? "Incoming"
: "Outgoing";
const dialog = new frappe.ui.Dialog({
title: __("Select Items for Quality Inspection"),
size: "extra-large",

View File

@@ -19,7 +19,6 @@
"stock_uom",
"expiry_date",
"use_batchwise_valuation",
"allow_negative_stock_for_batch",
"disabled",
"source",
"column_break_9",
@@ -200,14 +199,6 @@
{
"fieldname": "column_break_xrll",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "If enabled, the system will allow negative stock entries for this batch, overriding the 'Allow negative stock for Batch' setting in Stock Settings. This may lead to incorrect valuation rates, so it is recommended to avoid using this option.",
"fieldname": "allow_negative_stock_for_batch",
"fieldtype": "Check",
"label": "Allow Negative Stock for Batch",
"no_copy": 1
}
],
"icon": "fa fa-archive",
@@ -215,7 +206,7 @@
"image_field": "image",
"links": [],
"max_attachments": 5,
"modified": "2026-06-17 16:01:26.556324",
"modified": "2026-06-16 16:01:26.556324",
"modified_by": "Administrator",
"module": "Stock",
"name": "Batch",

View File

@@ -94,7 +94,6 @@ class Batch(Document):
if TYPE_CHECKING:
from frappe.types import DF
allow_negative_stock_for_batch: DF.Check
batch_id: DF.Data
batch_qty: DF.Float
description: DF.SmallText | None

View File

@@ -410,89 +410,6 @@ class TestItem(ERPNextTestSuite):
self.assertRaises(InvalidItemAttributeValueError, attribute.save)
def test_rename_attribute_value_updates_variants(self):
frappe.delete_doc_if_exists("Item", "_Test Variant Item-L", force=1)
variant = create_variant("_Test Variant Item", {"Test Size": "Large"})
variant.save()
attribute = frappe.get_doc("Item Attribute", "Test Size")
for row in attribute.item_attribute_values:
if row.attribute_value == "Large":
row.attribute_value = "Larger"
break
def restore_test_size_large():
doc = frappe.get_doc("Item Attribute", "Test Size")
for row in doc.item_attribute_values:
if row.attribute_value == "Larger":
row.attribute_value = "Large"
break
frappe.flags.attribute_values = None
doc.save()
self.addCleanup(restore_test_size_large)
frappe.flags.attribute_values = None
attribute.save()
self.assertEqual(
frappe.db.get_value(
"Item Variant Attribute",
{"parent": variant.name, "attribute": "Test Size"},
"attribute_value",
),
"Larger",
)
def test_swapped_attribute_value_renames_update_variants(self):
frappe.delete_doc_if_exists("Item", "_Test Variant Item-L", force=1)
frappe.delete_doc_if_exists("Item", "_Test Variant Item-S", force=1)
large_variant = create_variant("_Test Variant Item", {"Test Size": "Large"})
large_variant.save()
small_variant = create_variant("_Test Variant Item", {"Test Size": "Small"})
small_variant.save()
attribute = frappe.get_doc("Item Attribute", "Test Size")
original_values = {row.name: row.attribute_value for row in attribute.item_attribute_values}
def restore_test_size_values():
doc = frappe.get_doc("Item Attribute", "Test Size")
for row in doc.item_attribute_values:
row.attribute_value = original_values[row.name]
frappe.flags.attribute_values = None
doc.save()
self.addCleanup(restore_test_size_values)
for row in attribute.item_attribute_values:
if row.attribute_value == "Large":
row.attribute_value = "Small"
elif row.attribute_value == "Small":
row.attribute_value = "Large"
frappe.flags.attribute_values = None
attribute.save()
self.assertEqual(
frappe.db.get_value(
"Item Variant Attribute",
{"parent": large_variant.name, "attribute": "Test Size"},
"attribute_value",
),
"Small",
)
self.assertEqual(
frappe.db.get_value(
"Item Variant Attribute",
{"parent": small_variant.name, "attribute": "Test Size"},
"attribute_value",
),
"Large",
)
def test_make_item_variant(self):
frappe.delete_doc_if_exists("Item", "_Test Variant Item-L", force=1)

View File

@@ -9,7 +9,6 @@ from frappe.utils import flt
from erpnext.controllers.item_variant import (
InvalidItemAttributeValueError,
update_variant_attribute_values,
validate_is_incremental,
validate_item_attribute_value,
)
@@ -45,7 +44,6 @@ class ItemAttribute(Document):
self.validate_duplication()
def on_update(self):
update_variant_attribute_values(self)
self.validate_exising_items()
self.set_enabled_disabled_in_items()

View File

@@ -1143,52 +1143,6 @@ class TestMaterialRequest(ERPNextTestSuite):
se.save()
se.submit()
def test_mr_status_for_mixed_direct_and_transit_transfer(self):
material_request = make_material_request(
material_request_type="Material Transfer",
item_code="_Test Item Home Desktop 100",
qty=5,
)
in_transit_wh = get_in_transit_warehouse(material_request.company)
# Make stock available
self._insert_stock_entry(20.0, 20.0)
# Direct Transfer for 3 Qty
direct_transfer = make_stock_entry(material_request.name)
direct_transfer.items[0].update(
{
"qty": 3,
"transfer_qty": 3,
"s_warehouse": "_Test Warehouse 1 - _TC",
}
)
direct_transfer.save()
direct_transfer.submit()
# In Transit Transfer for remaining 2 Qty
transit_transfer = make_in_transit_stock_entry(material_request.name, in_transit_wh)
transit_transfer.items[0].update(
{
"qty": 2,
"s_warehouse": "_Test Warehouse 1 - _TC",
}
)
transit_transfer.save()
transit_transfer.submit()
# Complete End Transit
end_transit = make_stock_in_entry(transit_transfer.name)
end_transit.save()
end_transit.submit()
material_request.reload()
self.assertEqual(material_request.per_ordered, 100)
self.assertEqual(material_request.status, "Transferred")
self.assertEqual(material_request.transfer_status, "Completed")
def get_in_transit_warehouse(company):
if not frappe.db.exists("Warehouse Type", "Transit"):

View File

@@ -1581,7 +1581,7 @@ class SerialandBatchBundle(Document):
def throw_negative_batch(self, batch_no, available_qty, precision, posting_datetime=None):
from erpnext.stock.stock_ledger import NegativeStockError
if allow_negative_stock_for_batch(batch_no):
if frappe.db.get_single_value("Stock Settings", "allow_negative_stock_for_batch"):
return
date_msg = ""
@@ -1592,7 +1592,7 @@ class SerialandBatchBundle(Document):
"""
The Batch {0} of an item {1} has negative stock in the warehouse {2}{3}.
Please add a stock quantity of {4} to proceed with this entry.
If it is not possible to make an adjustment entry, please enable 'Allow Negative Stock for Batch' in the batch {0} or in the Stock Settings to proceed.
If it is not possible to make an adjustment entry, please enable 'Allow Negative Stock for Batch' in Stock Settings to proceed.
However, enabling this setting may lead to negative stock in the system.
So please ensure the stock levels are adjusted as soon as possible to maintain the correct valuation rate."""
).format(
@@ -2188,19 +2188,6 @@ def combine_datetime(date, time=None):
return get_combine_datetime(date, time)
def allow_negative_stock_for_batch(batch_no):
"""Return whether negative stock is allowed for the given batch.
The batch-level setting takes priority: if `allow_negative_stock_for_batch`
is enabled on the Batch, negative stock is allowed regardless of Stock Settings.
Otherwise, fall back to the `allow_negative_stock_for_batch` Stock Setting.
"""
if batch_no and frappe.db.get_value("Batch", batch_no, "allow_negative_stock_for_batch"):
return True
return bool(frappe.db.get_single_value("Stock Settings", "allow_negative_stock_for_batch"))
def get_batch(item_code):
from erpnext.stock.doctype.batch.batch import make_batch

View File

@@ -37,7 +37,8 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Serial No",
"options": "Serial No"
"options": "Serial No",
"search_index": 1
},
{
"depends_on": "eval:parent.has_batch_no == 1",
@@ -61,7 +62,8 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "Warehouse",
"options": "Warehouse"
"options": "Warehouse",
"search_index": 1
},
{
"fieldname": "column_break_2",
@@ -176,7 +178,8 @@
"fieldtype": "Data",
"label": "Type of Transaction",
"no_copy": 1,
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "column_break_eykr",

View File

@@ -42,4 +42,3 @@ class SerialandBatchEntry(Document):
def on_doctype_update():
frappe.db.add_index("Serial and Batch Entry", ["warehouse", "batch_no", "posting_datetime"])
frappe.db.add_index("Serial and Batch Entry", ["warehouse", "serial_no", "posting_datetime"])

View File

@@ -1,30 +1,26 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
cur_frm.add_fetch("customer", "customer_name", "customer_name");
cur_frm.add_fetch("supplier", "supplier_name", "supplier_name");
cur_frm.add_fetch("item_code", "item_name", "item_name");
cur_frm.add_fetch("item_code", "description", "description");
cur_frm.add_fetch("item_code", "item_group", "item_group");
cur_frm.add_fetch("item_code", "brand", "brand");
cur_frm.cscript.onload = function () {
cur_frm.set_query("item_code", function () {
return erpnext.queries.item({ is_stock_item: 1, has_serial_no: 1 });
});
};
frappe.ui.form.on("Serial No", "refresh", function (frm) {
frm.toggle_enable("item_code", frm.doc.__islocal);
});
frappe.ui.form.on("Serial No", {
setup(frm) {
frm.add_fetch("customer", "customer_name", "customer_name");
frm.add_fetch("supplier", "supplier_name", "supplier_name");
frm.add_fetch("item_code", "item_name", "item_name");
frm.add_fetch("item_code", "description", "description");
frm.add_fetch("item_code", "item_group", "item_group");
frm.add_fetch("item_code", "brand", "brand");
frm.set_query("item_code", function () {
return erpnext.queries.item({ is_stock_item: 1, has_serial_no: 1 });
});
frm.set_query("work_order", () => {
return {
filters: {
docstatus: 1,
},
};
});
},
refresh(frm) {
frm.toggle_enable("item_code", frm.doc.__islocal);
frm.trigger("view_ledgers");
},

View File

@@ -216,11 +216,10 @@ frappe.ui.form.on("Stock Entry", {
}
let quality_inspection_field = frm.get_docfield("items", "quality_inspection");
const incoming_purposes = ["Manufacture", "Material Receipt"];
quality_inspection_field.get_route_options_for_new_doc = function (row) {
if (frm.is_new()) return {};
return {
inspection_type: incoming_purposes.includes(frm.doc.purpose) ? "Incoming" : "Outgoing",
inspection_type: "Incoming",
reference_type: frm.doc.doctype,
reference_name: frm.doc.name,
child_row_reference: row.doc.name,

View File

@@ -259,6 +259,7 @@
},
{
"default": "0",
"depends_on": "eval: doc.purpose === \"Manufacture\"",
"fieldname": "inspection_required",
"fieldtype": "Check",
"label": "Inspection Required"
@@ -768,7 +769,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2026-06-11 18:23:12.340065",
"modified": "2026-03-04 19:03:23.426082",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",

View File

@@ -4646,19 +4646,13 @@ def get_batchwise_serial_nos(item_code, row):
def get_transferred_qty(material_request):
from pypika import Case
se = DocType("Stock Entry")
sed = DocType("Stock Entry Detail")
completed_qty = Case().when(se.add_to_transit == 1, sed.transferred_qty).else_(sed.transfer_qty)
query = (
frappe.qb.from_(sed)
.inner_join(se)
.on(se.name == sed.parent)
.select(
Sum(sed.transfer_qty).as_("transfer_qty"),
Sum(completed_qty).as_("transferred_qty"),
Sum(sed.transferred_qty).as_("transferred_qty"),
)
.where((sed.material_request == material_request) & (sed.docstatus == 1))
).run(as_dict=True)

View File

@@ -1089,316 +1089,6 @@ class TestStockEntry(ERPNextTestSuite):
repack.insert()
self.assertRaises(frappe.ValidationError, repack.submit)
def test_check_item_quality_inspection_returns_items_for_stock_entry(self):
from erpnext.controllers.stock_controller import check_item_quality_inspection
items = [
{"item_code": "_Test Item", "qty": 1},
{"item_code": "_Test Item Home Desktop 100", "qty": 1},
]
se_result = check_item_quality_inspection("Stock Entry", 0, items)
self.assertEqual(len(se_result), 2)
# a doctype not in INSPECTION_FIELDNAME_MAP and not a Stock Entry returns nothing
self.assertEqual(check_item_quality_inspection("Material Request", 0, items), [])
@ERPNextTestSuite.change_settings("Stock Settings", {"action_if_quality_inspection_is_rejected": "Stop"})
def test_quality_inspection_across_stock_entry_purposes(self):
from erpnext.controllers.stock_controller import check_item_quality_inspection
from erpnext.exceptions import QualityInspectionRejectedError, QualityInspectionRequiredError
from erpnext.stock.doctype.quality_inspection.test_quality_inspection import (
create_quality_inspection,
)
item_code = "_Test Item For QI Purposes"
if not frappe.db.exists("Item", item_code):
create_item(item_code, is_stock_item=1)
s_wh = "Stores - _TC"
t_wh = "_Test Warehouse - _TC"
# stock the source warehouse for transfer / issue purposes
make_stock_entry(item_code=item_code, target=s_wh, qty=100, basic_rate=100)
# purpose -> warehouses for the moved row; inward (with target) requires QI
purposes = {
"Material Receipt": {"to_warehouse": t_wh},
"Material Transfer": {"from_warehouse": s_wh, "to_warehouse": t_wh},
"Material Issue": {"from_warehouse": s_wh},
}
for purpose, warehouses in purposes.items():
with self.subTest(purpose=purpose):
needs_qi = "to_warehouse" in warehouses
se = make_stock_entry(
item_code=item_code,
qty=5,
basic_rate=100,
purpose=purpose,
inspection_required=True,
do_not_submit=True,
**warehouses,
)
# QI can be created from the Stock Entry for any purpose
allowed = check_item_quality_inspection("Stock Entry", 0, se.as_dict().get("items"))
self.assertTrue(any(row.get("item_code") == item_code for row in allowed))
if not needs_qi:
# outward-only entry: QI is not enforced
se.submit()
self.assertEqual(se.docstatus, 1)
continue
# inward entry without QI must block submission
self.assertRaises(QualityInspectionRequiredError, se.submit)
# a rejected QI must also block submission
se_rej = make_stock_entry(
item_code=item_code,
qty=5,
basic_rate=100,
purpose=purpose,
inspection_required=True,
do_not_submit=True,
**warehouses,
)
create_quality_inspection(
reference_type="Stock Entry",
reference_name=se_rej.name,
item_code=item_code,
inspection_type="Incoming",
status="Rejected",
)
se_rej.reload()
self.assertRaises(QualityInspectionRejectedError, se_rej.submit)
# a submitted, accepted QI links itself to the inward row; submission then succeeds
se_ok = make_stock_entry(
item_code=item_code,
qty=5,
basic_rate=100,
purpose=purpose,
inspection_required=True,
do_not_submit=True,
**warehouses,
)
create_quality_inspection(
reference_type="Stock Entry",
reference_name=se_ok.name,
item_code=item_code,
inspection_type="Incoming",
status="Accepted",
)
se_ok.reload()
se_ok.submit()
self.assertEqual(se_ok.docstatus, 1)
@ERPNextTestSuite.change_settings("Stock Settings", {"action_if_quality_inspection_is_rejected": "Stop"})
def test_quality_inspection_required_for_manufacture(self):
from erpnext.exceptions import QualityInspectionRejectedError, QualityInspectionRequiredError
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
from erpnext.manufacturing.doctype.work_order.work_order import (
make_stock_entry as make_wo_stock_entry,
)
from erpnext.stock.doctype.quality_inspection.test_quality_inspection import (
create_quality_inspection,
)
wo = make_wo_order_test_record(qty=1)
make_stock_entry(item_code="_Test Item", target="Stores - _TC", qty=10, basic_rate=100)
make_stock_entry(
item_code="_Test Item Home Desktop 100", target="Stores - _TC", qty=10, basic_rate=100
)
# transfer raw materials to WIP (no inspection on the transfer)
transfer = frappe.get_doc(make_wo_stock_entry(wo.name, "Material Transfer for Manufacture", 1))
for d in transfer.get("items"):
d.s_warehouse = "Stores - _TC"
transfer.insert()
transfer.submit()
# manufacture with inspection required
mfg = frappe.get_doc(make_wo_stock_entry(wo.name, "Manufacture", 1))
mfg.inspection_required = 1
mfg.insert()
self.assertRaises(QualityInspectionRequiredError, mfg.submit)
# a rejected QI on the finished-good row must also block submission
qi = create_quality_inspection(
reference_type="Stock Entry",
reference_name=mfg.name,
item_code=wo.production_item,
inspection_type="Incoming",
status="Rejected",
)
mfg.reload()
self.assertRaises(QualityInspectionRejectedError, mfg.submit)
# accepting the QI then allows submission
frappe.db.set_value("Quality Inspection", qi.name, "status", "Accepted")
mfg.reload()
mfg.submit()
self.assertEqual(mfg.docstatus, 1)
@ERPNextTestSuite.change_settings("Stock Settings", {"action_if_quality_inspection_is_rejected": "Stop"})
def test_quality_inspection_required_for_material_transfer_for_manufacture(self):
from erpnext.exceptions import QualityInspectionRejectedError, QualityInspectionRequiredError
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
from erpnext.manufacturing.doctype.work_order.work_order import (
make_stock_entry as make_wo_stock_entry,
)
from erpnext.stock.doctype.quality_inspection.test_quality_inspection import (
create_quality_inspection,
)
wo = make_wo_order_test_record(qty=1)
make_stock_entry(item_code="_Test Item", target="Stores - _TC", qty=10, basic_rate=100)
make_stock_entry(
item_code="_Test Item Home Desktop 100", target="Stores - _TC", qty=10, basic_rate=100
)
transfer = frappe.get_doc(make_wo_stock_entry(wo.name, "Material Transfer for Manufacture", 1))
for d in transfer.get("items"):
d.s_warehouse = "Stores - _TC"
transfer.inspection_required = 1
transfer.insert()
self.assertRaises(QualityInspectionRequiredError, transfer.submit)
# a rejected QI on any row moved into WIP must block submission;
# every raw-material row moved into WIP needs a QI
qis = []
for item_code in {d.item_code for d in transfer.items if d.t_warehouse}:
qis.append(
create_quality_inspection(
reference_type="Stock Entry",
reference_name=transfer.name,
item_code=item_code,
inspection_type="Incoming",
status="Rejected",
)
)
transfer.reload()
self.assertRaises(QualityInspectionRejectedError, transfer.submit)
# accepting every QI then allows submission
for qi in qis:
frappe.db.set_value("Quality Inspection", qi.name, "status", "Accepted")
transfer.reload()
transfer.submit()
self.assertEqual(transfer.docstatus, 1)
def test_quality_inspection_required_for_send_to_subcontractor(self):
from erpnext.controllers.subcontracting_controller import make_rm_stock_entry
from erpnext.controllers.tests.test_subcontracting_controller import (
get_subcontracting_order,
make_service_item,
)
from erpnext.exceptions import QualityInspectionRequiredError
from erpnext.stock.doctype.quality_inspection.test_quality_inspection import (
create_quality_inspection,
)
make_service_item("Subcontracted Service Item 1")
sco = get_subcontracting_order(
service_items=[
{
"warehouse": "_Test Warehouse - _TC",
"item_code": "Subcontracted Service Item 1",
"qty": 10,
"rate": 500,
"fg_item": "_Test FG Item",
"fg_item_qty": 10,
}
]
)
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=100, basic_rate=100)
make_stock_entry(
item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC", qty=100, basic_rate=100
)
se = frappe.get_doc(make_rm_stock_entry(sco.name))
se.from_warehouse = "_Test Warehouse - _TC"
se.to_warehouse = "_Test Warehouse - _TC"
se.stock_entry_type = "Send to Subcontractor"
se.inspection_required = 1
se.insert()
self.assertRaises(QualityInspectionRequiredError, se.submit)
for item_code in {row.item_code for row in se.items if row.t_warehouse}:
create_quality_inspection(
reference_type="Stock Entry",
reference_name=se.name,
item_code=item_code,
inspection_type="Outgoing",
status="Accepted",
)
se.reload()
se.submit()
self.assertEqual(se.docstatus, 1)
@ERPNextTestSuite.change_settings("Stock Settings", {"action_if_quality_inspection_is_rejected": "Stop"})
def test_quality_inspection_required_for_disassemble(self):
from erpnext.exceptions import QualityInspectionRejectedError, QualityInspectionRequiredError
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
from erpnext.manufacturing.doctype.work_order.work_order import (
make_stock_entry as make_wo_stock_entry,
)
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.quality_inspection.test_quality_inspection import (
create_quality_inspection,
)
source_warehouse = "Stores - _TC"
fg_item = make_item("Test Disassemble FG QI", {"is_stock_item": 1}).name
raw_materials = ["Test Disassemble RM QI 1", "Test Disassemble RM QI 2"]
for item in raw_materials:
make_item(item, {"is_stock_item": 1})
make_stock_entry(item_code=item, target=source_warehouse, qty=5, basic_rate=100)
make_bom(item=fg_item, source_warehouse=source_warehouse, raw_materials=raw_materials)
wo = make_wo_order_test_record(
item=fg_item, qty=1, source_warehouse=source_warehouse, skip_transfer=1
)
# manufacture the FG so there is something to disassemble
mfg = frappe.get_doc(make_wo_stock_entry(wo.name, "Manufacture", 1))
for row in mfg.items:
if row.item_code in raw_materials:
row.s_warehouse = source_warehouse
mfg.submit()
# disassemble with inspection required -> the component rows need a QI
dis = frappe.get_doc(make_wo_stock_entry(wo.name, "Disassemble", 1))
dis.inspection_required = 1
dis.insert()
self.assertRaises(QualityInspectionRequiredError, dis.submit)
# a rejected QI on any disassembled component row must also block submission
qis = []
for item_code in {row.item_code for row in dis.items if row.t_warehouse}:
qis.append(
create_quality_inspection(
reference_type="Stock Entry",
reference_name=dis.name,
item_code=item_code,
inspection_type="Outgoing",
status="Rejected",
)
)
dis.reload()
self.assertRaises(QualityInspectionRejectedError, dis.submit)
# accepting every QI then allows submission
for qi in qis:
frappe.db.set_value("Quality Inspection", qi.name, "status", "Accepted")
dis.reload()
dis.submit()
self.assertEqual(dis.docstatus, 1)
def test_customer_provided_parts_se(self):
create_item("CUST-0987", is_customer_provided_item=1, customer="_Test Customer", is_purchase_item=0)
se = make_stock_entry(

View File

@@ -358,7 +358,7 @@ class FIFOSlots:
if row.voucher_type != "Stock Reconciliation":
return
if row.has_serial_no and (not row.batch_no or row.serial_no or row.serial_and_batch_bundle):
if not row.batch_no or row.serial_no or row.serial_and_batch_bundle:
if row.voucher_detail_no in self.stock_reco_voucher_wise_count:
# Legacy reconciliation with a single SLE has qty_after_transaction and
# stock_value_difference without an outward entry, so reset the queue first.
@@ -1065,7 +1065,6 @@ class FIFOSlots:
(doctype.voucher_type == "Stock Reconciliation")
& (doctype.docstatus < 2)
& (doctype.is_cancelled == 0)
& (item.has_serial_no == 1)
)
.groupby(doctype.voucher_detail_no)
)

View File

@@ -191,67 +191,6 @@ class TestStockAgeing(ERPNextTestSuite):
self.assertEqual(queue[0][0], 20.0)
self.assertEqual(queue[1][0], 20.0)
def test_non_serial_stock_reco_decrease_preserves_ageing(self):
"""
Non-serial stock reconciliation should adjust FIFO by the balance delta.
Decreasing stock consumes old slots; increasing stock adds only the new qty.
"""
def make_sle(
posting_date,
voucher_type,
voucher_no,
actual_qty,
qty_after,
voucher_detail_no=None,
stock_value_difference=None,
):
stock_value_difference = actual_qty if stock_value_difference is None else stock_value_difference
return frappe._dict(
name="Flask Item",
item_name="Flask Item",
description="Flask Item",
item_group=None,
brand=None,
stock_uom="Nos",
actual_qty=actual_qty,
qty_after_transaction=qty_after,
stock_value_difference=stock_value_difference,
valuation_rate=1,
warehouse="WH 1",
posting_date=posting_date,
voucher_type=voucher_type,
voucher_no=voucher_no,
voucher_detail_no=voucher_detail_no,
has_serial_no=False,
has_batch_no=False,
serial_no=None,
batch_no=None,
serial_and_batch_bundle=None,
)
filters = frappe._dict(company="_Test Company", to_date="2026-02-15", ranges=["30", "60", "90"])
sle = [
make_sle("2025-11-30", "Stock Entry", "001", 100, 100),
make_sle("2025-12-31", "Stock Reconciliation", "002", 0, 60, "SRI-DECREASE", -40),
make_sle("2026-01-31", "Stock Reconciliation", "003", 0, 90, "SRI-INCREASE", 30),
]
fifo_slots = FIFOSlots(filters, sle)
def prepare_stock_reco_voucher_wise_count():
fifo_slots.stock_reco_voucher_wise_count = frappe._dict({"SRI-DECREASE": 100, "SRI-INCREASE": 60})
fifo_slots.prepare_stock_reco_voucher_wise_count = prepare_stock_reco_voucher_wise_count
slots = fifo_slots.generate()
queue = slots["Flask Item"]["fifo_queue"]
report_data = format_report_data(filters, slots, filters.to_date)
self.assertEqual(queue, [[60.0, "2025-11-30", 60.0], [30.0, "2026-01-31", 30.0]])
self.assertEqual(report_data[0][7:15], [30.0, 30.0, 0.0, 0.0, 60.0, 60.0, 0.0, 0.0])
def test_sequential_stock_reco_same_warehouse(self):
"""
Test back to back stock recos (same warehouse).

View File

@@ -88,46 +88,6 @@ class IntegrationTestSubcontractingInwardOrder(ERPNextTestSuite):
self.assertEqual(received_item.received_qty, 5)
self.assertEqual(received_item.rate, 10)
def test_customer_provided_item_rate_with_return_between_receipts(self):
"""Weight the average rate on the on-hand balance, not gross received_qty.
Receive 10 @ 100, return 5, receive 6 @ 130:
balance-weighted (correct) = (5 * 100 + 6 * 130) / 11 = 116.36
gross-weighted (wrong) = (10 * 100 + 6 * 130) / 16 = 111.25
"""
so, scio = create_so_scio()
rm_item = "Basic RM"
def receive(qty, rate):
rm_in = frappe.new_doc("Stock Entry").update(scio.make_rm_stock_entry_inward())
rm_in.items = [item for item in rm_in.items if item.item_code == rm_item]
rm_in.items[0].qty = qty
rm_in.items[0].transfer_qty = qty
rm_in.items[0].basic_rate = rate
rm_in.submit()
scio.reload()
# Receipt 1: 10 @ 100
receive(10, 100)
received_item = next(item for item in scio.received_items if item.rm_item_code == rm_item)
self.assertEqual(received_item.rate, 100)
# Return 5 to the customer
rm_return = frappe.new_doc("Stock Entry").update(scio.make_rm_return())
rm_return.items = [item for item in rm_return.items if item.item_code == rm_item]
rm_return.items[0].qty = 5
rm_return.items[0].transfer_qty = 5
rm_return.submit()
scio.reload()
received_item = next(item for item in scio.received_items if item.rm_item_code == rm_item)
self.assertEqual(received_item.returned_qty, 5)
# Receipt 2: 6 @ 130 — must weight against the balance of 5, not gross 10
receive(6, 130)
received_item = next(item for item in scio.received_items if item.rm_item_code == rm_item)
self.assertAlmostEqual(received_item.rate, (5 * 100 + 6 * 130) / 11, places=2)
def test_add_extra_customer_provided_item(self):
so, scio = create_so_scio()