Compare commits

..

421 Commits

Author SHA1 Message Date
Frappe PR Bot
05d5dc5321 chore(release): Bumped to Version 15.80.0
# [15.80.0](https://github.com/frappe/erpnext/compare/v15.79.2...v15.80.0) (2025-09-23)

### Bug Fixes

* **accounts receivable:** exclude employee transactions ([c071107](c071107b27))
* **accounts:** dynamic zero cutoff (backport [#48899](https://github.com/frappe/erpnext/issues/48899)) ([#49552](https://github.com/frappe/erpnext/issues/49552)) ([5ef7a78](5ef7a7857c))
* add condition for name ([65ce737](65ce737c2d))
* add option for currency field (backport [#49572](https://github.com/frappe/erpnext/issues/49572)) ([#49594](https://github.com/frappe/erpnext/issues/49594)) ([1a4ea07](1a4ea07b78))
* auto commit if too many writes reached ([0310172](0310172338))
* Consider non SABB batch qty in reserved batch validation ([7ed97e4](7ed97e47cc))
* incorrect current qty calculation for the batch ([bf48cf0](bf48cf02e5))
* **item:** avoid inheriting item defaults from identically named items ([#49571](https://github.com/frappe/erpnext/issues/49571)) ([9e58a56](9e58a56b5c))
* only show filters in print view if 'Include filters' is enabled ([79d4731](79d4731fe7))
* **payment-reconciliation:** apply field precision for allocated and difference amounts (backport [#49448](https://github.com/frappe/erpnext/issues/49448)) ([#49595](https://github.com/frappe/erpnext/issues/49595)) ([fbd62e7](fbd62e72f9))
* project accounting dimension and gl posting date column width (backport [#49563](https://github.com/frappe/erpnext/issues/49563)) ([#49591](https://github.com/frappe/erpnext/issues/49591)) ([bce22cb](bce22cb27b))
* **purchase order:** get party type based on supplier field ([3aebbf6](3aebbf6e92))
* restore auto_commit_on_many_writes flag ([5320782](53207821aa))
* set first_response_time on status change of issue ([0d5613c](0d5613ca4c))
* skip receivable/payable account validation in payroll entry if party is not available (backport [#49585](https://github.com/frappe/erpnext/issues/49585)) ([#49598](https://github.com/frappe/erpnext/issues/49598)) ([697f6ef](697f6ef086))
* **stock:** NoneType object error on stock entry ([de8c4ee](de8c4eec1b))
* warehouse for batch validation ([cb94c4b](cb94c4b5f1))

### Features

* add filters option in print view (backport [#49631](https://github.com/frappe/erpnext/issues/49631)) ([#49700](https://github.com/frappe/erpnext/issues/49700)) ([e9b29ed](e9b29ed544))
* populate available qty in pick list locations ([bc7f884](bc7f884ae1))
2025-09-23 14:00:33 +00:00
ruthra kumar
74b19f2743 Merge pull request #49697 from frappe/version-15-hotfix
chore: release v15
2025-09-23 19:29:11 +05:30
ruthra kumar
e9b29ed544 feat: add filters option in print view (backport #49631) (#49700)
fix: only show filters in print view if 'Include filters' is enabled

(cherry picked from commit 1979879b07)

# Conflicts:
#	erpnext/accounts/report/general_ledger/general_ledger.html

Co-authored-by: Nareshkanna S <nareshkannashanmugam@gmail.com>
2025-09-23 16:40:11 +05:30
Nareshkanna S
79d4731fe7 fix: only show filters in print view if 'Include filters' is enabled
(cherry picked from commit 1979879b07)

# Conflicts:
#	erpnext/accounts/report/general_ledger/general_ledger.html
2025-09-23 16:29:18 +05:30
ruthra kumar
e4997af1c0 Merge pull request #49695 from frappe/mergify/bp/version-15-hotfix/pr-49694
chore: update sales_data from site_info (backport #49694)
2025-09-23 15:11:22 +05:30
Jannat Patel
ff08ee6ada test: activation with site_info
(cherry picked from commit 5a26d593e4)
2025-09-23 09:22:03 +00:00
Jannat Patel
ac55028f6b chore: update sales_data from site_info
(cherry picked from commit 866b252309)
2025-09-23 09:22:03 +00:00
Frappe PR Bot
98457a8530 chore(release): Bumped to Version 15.79.2
## [15.79.2](https://github.com/frappe/erpnext/compare/v15.79.1...v15.79.2) (2025-09-23)

### Bug Fixes

* Consider non SABB batch qty in reserved batch validation ([9158751](91587517d9))
* warehouse for batch validation ([59a7104](59a710433a))
2025-09-23 07:16:11 +00:00
rohitwaghchaure
236d8c7af1 Merge pull request #49693 from frappe/mergify/bp/version-15/pr-49691
fix: Consider non SABB batch qty in reserved batch validation (backport #49648) (backport #49691)
2025-09-23 12:44:43 +05:30
rohitwaghchaure
63c1fd52b1 Merge pull request #49692 from frappe/mergify/bp/version-15/pr-49688
fix: warehouse for batch validation (backport #49687) (backport #49688)
2025-09-23 12:44:21 +05:30
Kavin
91587517d9 fix: Consider non SABB batch qty in reserved batch validation
(cherry picked from commit ae8b34e03c)
(cherry picked from commit 7ed97e47cc)
2025-09-23 06:39:33 +00:00
rohitwaghchaure
7402549b4b Merge pull request #49691 from frappe/mergify/bp/version-15-hotfix/pr-49648
fix: Consider non SABB batch qty in reserved batch validation (backport #49648)
2025-09-23 12:09:11 +05:30
Rohit Waghchaure
59a710433a fix: warehouse for batch validation
(cherry picked from commit 381072170a)
(cherry picked from commit cb94c4b5f1)
2025-09-23 06:37:26 +00:00
rohitwaghchaure
f4cef8a417 Merge pull request #49690 from frappe/mergify/bp/version-15-hotfix/pr-49684
feat: populate available qty in pick list locations (backport #49684)
2025-09-23 12:07:00 +05:30
rohitwaghchaure
dc6d4f2620 Merge pull request #49688 from frappe/mergify/bp/version-15-hotfix/pr-49687
fix: warehouse for batch validation (backport #49687)
2025-09-23 12:06:31 +05:30
Kavin
7ed97e47cc fix: Consider non SABB batch qty in reserved batch validation
(cherry picked from commit ae8b34e03c)
2025-09-23 06:21:00 +00:00
Kavin
a463f4a419 refactor: fetching qty on warehouse trigger
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
(cherry picked from commit e3ab0e7c67)
2025-09-23 06:20:23 +00:00
Kavin
bc7f884ae1 feat: populate available qty in pick list locations
(cherry picked from commit d8756fc7de)
2025-09-23 06:20:23 +00:00
Kavin
056d51937b chore: rename stock qty label
(cherry picked from commit fc967fceb2)
2025-09-23 06:20:22 +00:00
Rohit Waghchaure
cb94c4b5f1 fix: warehouse for batch validation
(cherry picked from commit 381072170a)
2025-09-23 06:12:44 +00:00
Diptanil Saha
868987e46e Merge pull request #49686 from frappe/mergify/bp/version-15-hotfix/pr-49676
fix: auto commit if too many writes reached (backport #49676)
2025-09-23 11:20:36 +05:30
Kavin
53207821aa fix: restore auto_commit_on_many_writes flag
(cherry picked from commit 66712fa8b5)
2025-09-23 05:31:28 +00:00
Kavin
0310172338 fix: auto commit if too many writes reached
(cherry picked from commit 99a0ba0b45)
2025-09-23 05:31:27 +00:00
ruthra kumar
5bfb4d2390 Merge pull request #49667 from frappe/mergify/bp/version-15-hotfix/pr-49644
fix(purchase order): get party type based on supplier field (backport #49644)
2025-09-22 15:05:53 +05:30
venkat102
3aebbf6e92 fix(purchase order): get party type based on supplier field
(cherry picked from commit 11b9b1adc5)

# Conflicts:
#	erpnext/public/js/controllers/transaction.js
2025-09-22 15:01:57 +05:30
ruthra kumar
925afe1b59 Merge pull request #49665 from frappe/mergify/bp/version-15-hotfix/pr-49653
fix(accounts receivable): exclude employee transactions (backport #49653)
2025-09-22 14:58:17 +05:30
venkat102
c071107b27 fix(accounts receivable): exclude employee transactions
(cherry picked from commit 736a776d3d)
2025-09-22 08:05:36 +00:00
ruthra kumar
8c7e20f9a2 Merge pull request #49664 from frappe/mergify/bp/version-15-hotfix/pr-49470
fix(bank clearance): use base total taxes and charges if exists (backport #49470)
2025-09-22 12:44:55 +05:30
Ravibharathi
81824320db Merge pull request #49470 from aerele/bank-clearance-tax-calculation
fix(bank clearance): use base total taxes and charges if exists

(cherry picked from commit 302ff49b7f)
2025-09-22 05:58:20 +00:00
Diptanil Saha
9914d20127 Merge pull request #49659 from frappe/mergify/bp/version-15-hotfix/pr-49649
fix: set first_response_time on set_first_response (backport #49649)
2025-09-22 00:38:16 +05:30
diptanilsaha
0d5613ca4c fix: set first_response_time on status change of issue
(cherry picked from commit ba459204b0)
2025-09-21 18:36:29 +00:00
Frappe PR Bot
20d14881fe chore(release): Bumped to Version 15.79.1
## [15.79.1](https://github.com/frappe/erpnext/compare/v15.79.0...v15.79.1) (2025-09-21)

### Bug Fixes

* **stock:** NoneType object error on stock entry ([48bd005](48bd005a09))
2025-09-21 18:34:45 +00:00
rohitwaghchaure
73e76f533e Merge pull request #49658 from frappe/mergify/bp/version-15/pr-49619
fix(stock): NoneType object error on stock entry (backport #49615) (backport #49619)
2025-09-22 00:03:18 +05:30
Kavin
48bd005a09 fix(stock): NoneType object error on stock entry
(cherry picked from commit aee03417de)
(cherry picked from commit de8c4eec1b)
2025-09-21 17:12:19 +00:00
Mihir Kandoi
04c2bb4f50 Merge pull request #49619 from frappe/mergify/bp/version-15-hotfix/pr-49615
fix(stock): NoneType object error on stock entry (backport #49615)
2025-09-18 21:18:09 +05:30
Kavin
de8c4eec1b fix(stock): NoneType object error on stock entry
(cherry picked from commit aee03417de)
2025-09-18 14:47:04 +00:00
mergify[bot]
697f6ef086 fix: skip receivable/payable account validation in payroll entry if party is not available (backport #49585) (#49598)
fix: skip receivable/payable account validation in payroll entry if party is not available (#49585)

* fix: skip receivable/payable account validation if party is not available in creation of payroll entry

* refactor: rename flag

(cherry picked from commit 8b543e5503)

Co-authored-by: Raheel Khan <raheel@frappe.io>
2025-09-18 17:04:28 +05:30
ruthra kumar
d66aed52f7 Merge pull request #49617 from frappe/mergify/bp/version-15-hotfix/pr-49467
fix: add condition for name (backport #49467)
2025-09-18 17:03:32 +05:30
venkat102
089c068ee8 test: add test to validate user permission in qb
(cherry picked from commit a5b881ea74)

# Conflicts:
#	erpnext/setup/doctype/employee/test_employee.py
2025-09-18 16:46:39 +05:30
venkat102
65ce737c2d fix: add condition for name
(cherry picked from commit cf5a2d6351)
2025-09-18 11:12:13 +00:00
mergify[bot]
5ef7a7857c fix(accounts): dynamic zero cutoff (backport #48899) (#49552)
fix(accounts): dynamic zero cutoff (#48899)

* fix(accounts): dynamic zero cutoff

The cutoff for displaying zero values in accounting reports has so far been hardcoded to 0.005, giving wrong results for currencies that require a higher precision. This PR changes this to a dynamic value calculated from the Currency's _Fraction Units_.

* style: fix typo

(cherry picked from commit 6972f161b8)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-09-17 18:03:48 +05:30
mergify[bot]
fbd62e72f9 fix(payment-reconciliation): apply field precision for allocated and difference amounts (backport #49448) (#49595)
fix(payment-reconciliation): apply field precision for allocated and difference amounts (#49448)

fix(payment-reconciliation): handle allocated and difference amount with field precision for accurate exchange rate calculations

(cherry picked from commit 194ab87fef)

Co-authored-by: Bhavansathru <122002510+Bhavan23@users.noreply.github.com>
2025-09-17 17:33:33 +05:30
mergify[bot]
1a4ea07b78 fix: add option for currency field (backport #49572) (#49594)
fix: add option for currency field (#49572)

(cherry picked from commit e0299e1cbd)

Co-authored-by: Logesh Periyasamy <logeshperiyasamy24@gmail.com>
2025-09-17 17:33:15 +05:30
mergify[bot]
bce22cb27b fix: project accounting dimension and gl posting date column width (backport #49563) (#49591)
fix: project accounting dimension and gl posting date column width (#49563)

* fix: add width for posting_date

* fix: add project field for missing doctype

* fix: remove allow_on_submit to align with cost center

(cherry picked from commit 9fc17e0e3a)

Co-authored-by: Logesh Periyasamy <logeshperiyasamy24@gmail.com>
2025-09-17 17:33:02 +05:30
Imesha Sudasingha
9e58a56b5c fix(item): avoid inheriting item defaults from identically named items (#49571) 2025-09-17 17:32:13 +05:30
rohitwaghchaure
87a2774511 Merge pull request #49592 from frappe/mergify/bp/version-15-hotfix/pr-49587
fix: incorrect current qty calculation for the batch (backport #49587)
2025-09-17 17:21:26 +05:30
Rohit Waghchaure
bf48cf02e5 fix: incorrect current qty calculation for the batch
(cherry picked from commit 535f8657ed)
2025-09-17 11:32:11 +00:00
Frappe PR Bot
6ae8e32efa chore(release): Bumped to Version 15.79.0
# [15.79.0](https://github.com/frappe/erpnext/compare/v15.78.1...v15.79.0) (2025-09-16)

### Bug Fixes

* add Address and Contact in Add Column ([28b3856](28b3856bc9))
* batch qty calculation performance issue ([921f317](921f317423))
* correct grammatical errors in asset movement validation messages ([97765ce](97765ce8bd))
* correct typo in asset movement purpose validation ([edd3f5d](edd3f5da1c))
* depreciate asset with remaining amount when depreciation amount exceeds current asset value ([845d346](845d3464b4))
* do not allow backdated entries if stock reco exists in future for serial or batch ([44869f0](44869f02b4))
* incorrect batch qty ([ae3dd5b](ae3dd5b831))
* incorrect stock value in the report ([d302ca7](d302ca7ea0))
* non batch-wise valuation for batch item ([affe09e](affe09ee0b))
* precision issue for valuation rate calculation ([7a8cd47](7a8cd47259))
* remove ignore_permissions ([7280034](7280034abd))
* renamed temporary bank account to 'Demo Bank Account' ([6ab287f](6ab287f19c))
* SABB document status validation ([7bb9225](7bb92255c5))
* **sales invoice:** fetch tax id from customer ([ee7da99](ee7da999a3))
* set basic rate on selection of the batch ([39eeafd](39eeafd0d0))
* skip 'Bank Account' creation on setup ([07241aa](07241aa54a))
* validation for document status ([0b2f53f](0b2f53fefe))

### Features

* add permission check for custom button ([9db9dd6](9db9dd6f35))
2025-09-16 14:43:36 +00:00
ruthra kumar
89204046de Merge pull request #49566 from frappe/version-15-hotfix
chore: release v15
2025-09-16 20:12:09 +05:30
rohitwaghchaure
fea0ca8e8e Merge pull request #49562 from frappe/mergify/bp/version-15-hotfix/pr-49558
fix: set basic rate on selection of the batch (backport #49558)
2025-09-16 13:08:42 +05:30
Rohit Waghchaure
39eeafd0d0 fix: set basic rate on selection of the batch
(cherry picked from commit bebb8ae1ea)
2025-09-16 07:26:10 +00:00
ruthra kumar
add236c907 Merge pull request #49559 from frappe/mergify/bp/version-15-hotfix/pr-49511
fix(sales invoice): fetch tax id from customer (backport #49511)
2025-09-16 12:48:01 +05:30
ravibharathi656
ee7da999a3 fix(sales invoice): fetch tax id from customer
(cherry picked from commit df329964dd)
2025-09-16 06:32:20 +00:00
rohitwaghchaure
0a7247f94c Merge pull request #49554 from frappe/mergify/bp/version-15-hotfix/pr-49549
fix: do not allow backdated entries if stock reco exists in future for serial or batch (backport #49549)
2025-09-15 16:22:33 +05:30
rohitwaghchaure
572af6e08a chore: fix conflicts 2025-09-15 15:43:38 +05:30
Rohit Waghchaure
44869f02b4 fix: do not allow backdated entries if stock reco exists in future for serial or batch
(cherry picked from commit 335dcc976c)

# Conflicts:
#	erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
2025-09-15 10:12:08 +00:00
Khushi Rawat
e92ec66890 Merge pull request #49551 from frappe/mergify/bp/version-15-hotfix/pr-49524
fix: Assets Movement Typos (backport #49524)
2025-09-15 13:00:46 +05:30
KerollesFathy
97765ce8bd fix: correct grammatical errors in asset movement validation messages
(cherry picked from commit 5f083d55b5)
2025-09-15 06:26:45 +00:00
KerollesFathy
edd3f5da1c fix: correct typo in asset movement purpose validation
(cherry picked from commit 56da3bd2e4)
2025-09-15 06:26:45 +00:00
rohitwaghchaure
1addaae669 Merge pull request #49543 from frappe/mergify/bp/version-15-hotfix/pr-49542
fix: validation for document status (backport #49542)
2025-09-14 17:06:53 +05:30
Rohit Waghchaure
0b2f53fefe fix: validation for document status
(cherry picked from commit 96e2e356b6)
2025-09-14 06:57:36 +00:00
rohitwaghchaure
b5417af6f5 Merge pull request #49541 from frappe/mergify/bp/version-15-hotfix/pr-49539
fix: precision issue for valuation rate calculation (backport #49539)
2025-09-14 12:27:02 +05:30
Rohit Waghchaure
7a8cd47259 fix: precision issue for valuation rate calculation
(cherry picked from commit c92a06d77d)
2025-09-14 06:22:22 +00:00
rohitwaghchaure
f523413bce Merge pull request #49540 from frappe/mergify/bp/version-15-hotfix/pr-49538
fix: SABB document status validation (backport #49538)
2025-09-14 11:51:18 +05:30
Rohit Waghchaure
7bb92255c5 fix: SABB document status validation
(cherry picked from commit c0236191aa)
2025-09-14 05:56:11 +00:00
rohitwaghchaure
6245bf9b87 Merge pull request #49495 from frappe/mergify/bp/version-15-hotfix/pr-49477
fix: batch qty calculation performance issue (backport #49477)
2025-09-08 10:06:21 +05:30
Rohit Waghchaure
921f317423 fix: batch qty calculation performance issue
(cherry picked from commit 1a262483a4)
2025-09-07 11:20:42 +00:00
Diptanil Saha
08cfd00373 Merge pull request #49492 from frappe/mergify/bp/version-15-hotfix/pr-49485
fix: skip 'Bank Account' creation on setup (backport #49485)
2025-09-06 13:32:07 +05:30
diptanilsaha
6ab287f19c fix: renamed temporary bank account to 'Demo Bank Account'
(cherry picked from commit efeda90cad)
2025-09-06 07:44:55 +00:00
diptanilsaha
07241aa54a fix: skip 'Bank Account' creation on setup
(cherry picked from commit 47d4319f83)
2025-09-06 07:44:54 +00:00
ruthra kumar
f27c67a19d Merge pull request #49482 from frappe/mergify/bp/version-15-hotfix/pr-46996
fix: Allow adding Address/Contact fields to `Address And Contacts` report (backport #46996)
2025-09-05 20:17:26 +05:30
ruthra kumar
4f1f46a4d4 chore: translatable labels
(cherry picked from commit 39174f9dc0)
2025-09-05 14:05:20 +00:00
Sanket322
28b3856bc9 fix: add Address and Contact in Add Column
(cherry picked from commit d9ca7e755f)
2025-09-05 14:05:20 +00:00
Khushi Rawat
ee9369cd44 Merge pull request #49468 from khushi8112/asset-scrapping-issue
fix: asset scrapping issue
2025-09-05 02:22:41 +05:30
khushi8112
da039e5bf0 chore: remove print statement 2025-09-05 01:58:20 +05:30
khushi8112
845d3464b4 fix: depreciate asset with remaining amount when depreciation amount exceeds current asset value 2025-09-05 01:54:56 +05:30
Frappe PR Bot
ceb17b6b61 chore(release): Bumped to Version 15.78.1
## [15.78.1](https://github.com/frappe/erpnext/compare/v15.78.0...v15.78.1) (2025-09-04)

### Bug Fixes

* non batch-wise valuation for batch item ([9c14aa2](9c14aa2d01))
2025-09-04 14:39:10 +00:00
rohitwaghchaure
745070dc97 Merge pull request #49464 from frappe/mergify/bp/version-15/pr-49457
fix: non batch-wise valuation for batch item (backport #49453) (backport #49457)
2025-09-04 20:07:51 +05:30
Mihir Kandoi
b1c1452b90 Merge pull request #49440 from frappe/mergify/bp/version-15-hotfix/pr-49437
refactor: PR 49320 (backport #49437)
2025-09-04 20:00:32 +05:30
rohitwaghchaure
4dbcef3d67 chore: fix test case
(cherry picked from commit ac8637d5a0)
(cherry picked from commit 6bdf11f5c9)
2025-09-04 12:52:18 +00:00
Rohit Waghchaure
9c14aa2d01 fix: non batch-wise valuation for batch item
(cherry picked from commit 11b82ba008)
(cherry picked from commit affe09ee0b)
2025-09-04 12:52:18 +00:00
rohitwaghchaure
e0f4c17462 Merge pull request #49457 from frappe/mergify/bp/version-15-hotfix/pr-49453
fix: non batch-wise valuation for batch item (backport #49453)
2025-09-04 18:20:11 +05:30
rohitwaghchaure
6bdf11f5c9 chore: fix test case
(cherry picked from commit ac8637d5a0)
2025-09-04 09:01:08 +00:00
Rohit Waghchaure
affe09ee0b fix: non batch-wise valuation for batch item
(cherry picked from commit 11b82ba008)
2025-09-04 09:01:07 +00:00
rohitwaghchaure
eb631d6e75 Merge pull request #49452 from frappe/mergify/bp/version-15-hotfix/pr-49449
fix: incorrect stock value in the report (backport #49449)
2025-09-04 07:10:40 +05:30
Rohit Waghchaure
d302ca7ea0 fix: incorrect stock value in the report
(cherry picked from commit 5824b5effd)
2025-09-03 19:18:03 +00:00
Raffael Meyer
af0399c2d2 Merge pull request #49435 from frappe/mergify/bp/version-15-hotfix/pr-49374
fix: improve permission handling for party link creation (backport #49374)
2025-09-03 17:13:08 +02:00
rohitwaghchaure
ce820e4150 Merge pull request #49443 from frappe/mergify/bp/version-15-hotfix/pr-49442
fix: incorrect batch qty (backport #49442)
2025-09-03 19:20:10 +05:30
Rohit Waghchaure
ae3dd5b831 fix: incorrect batch qty
(cherry picked from commit 000135a3d4)
2025-09-03 11:13:52 +00:00
Mihir Kandoi
43e9ab9cd1 refactor: PR 49320
(cherry picked from commit 991413608b)
2025-09-03 08:50:57 +00:00
mergify[bot]
b8a07a437b test: use valid IBANs in party matching test case (backport #49432) (#49433)
Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com>
2025-09-02 17:35:03 +00:00
Marc-Constantin Enke
9db9dd6f35 feat: add permission check for custom button
(cherry picked from commit 00fd1d2f26)
2025-09-02 17:20:37 +00:00
Marc-Constantin Enke
7280034abd fix: remove ignore_permissions
(cherry picked from commit 7f55f421ab)
2025-09-02 17:20:37 +00:00
Frappe PR Bot
2851f6e786 chore(release): Bumped to Version 15.78.0
# [15.78.0](https://github.com/frappe/erpnext/compare/v15.77.0...v15.78.0) (2025-09-02)

### Bug Fixes

* 🐛 fixing buying controller to include transaction controller… (backport [#49140](https://github.com/frappe/erpnext/issues/49140)) ([#49370](https://github.com/frappe/erpnext/issues/49370)) ([c06f72f](c06f72f9f7))
* add is_cancelled in condition ([f2c4bae](f2c4baeb0e))
* add option to disable Transaction Log (backport [#49342](https://github.com/frappe/erpnext/issues/49342)) ([#49344](https://github.com/frappe/erpnext/issues/49344)) ([7926cfd](7926cfd8c4))
* **budget:** always set fiscal year before fetching company approver role ([e6a305e](e6a305e972))
* convert NaN to numerical ([0b3fac3](0b3fac3a0e))
* **exchange rate revaluation:** add check for gain_loss ([1d28135](1d28135898))
* hide is_cumulative for apply_on is set to Transaction (backport [#49243](https://github.com/frappe/erpnext/issues/49243)) ([#49257](https://github.com/frappe/erpnext/issues/49257)) ([064ce4b](064ce4bf6d))
* ignore cancelled gl and add company filter ([835b9c3](835b9c3378))
* Issue with Barcode Scanning in Stock Entry ([45cdb39](45cdb39edd))
* **perf:** applying consistent index to fetch gl entries for financial statements ([a3605d8](a3605d8370))
* remove defunct payment gateway links from ERPNext Integrations workspace ([17f7351](17f7351f85)), closes [#49352](https://github.com/frappe/erpnext/issues/49352)
* **repost item valuation:** reorder function call ([e802536](e8025365cd))
* **repost item valuation:** validate voucher type in transaction ([6761a02](6761a023d0))
* run config with force ([9d34eb6](9d34eb686c))
* set missing due date in Purchase Invoice and POS Invoice ([#49232](https://github.com/frappe/erpnext/issues/49232)) ([6a31b7b](6a31b7b118))
* show company currency symbol ([ecb7858](ecb7858062))
* show create purchase receipt button only when update stock is not checked ([caa1681](caa1681c5f))
* source warehouse in manufacture entry and reqd prop of scrap warehouse ([7bb180e](7bb180e5da))
* source warehouse in manufacture entry and reqd prop of scrap warehouse (backport [#49320](https://github.com/frappe/erpnext/issues/49320)) ([#49337](https://github.com/frappe/erpnext/issues/49337)) ([be6f793](be6f79330a))
* validation for Recreate Stock Ledgers ([9f0d743](9f0d743e1b))
* valuation for batch items ([b57dabd](b57dabd8ef))

### Features

* optional fixed outgoing email for RfQ ([#49258](https://github.com/frappe/erpnext/issues/49258)) ([c875ff9](c875ff972f))

### Performance Improvements

* check PCV (smaller) table before checking GL Entries ([fc47fbe](fc47fbeaa1))
2025-09-02 14:17:15 +00:00
ruthra kumar
3b527e4155 Merge pull request #49423 from frappe/version-15-hotfix
chore: release v15
2025-09-02 19:45:59 +05:30
rohitwaghchaure
1d9b77460d Merge pull request #49429 from rohitwaghchaure/fixed-valuation-for-batch-v15
fix: valuation for batch items
2025-09-02 19:11:10 +05:30
Rohit Waghchaure
b57dabd8ef fix: valuation for batch items 2025-09-02 18:54:06 +05:30
ruthra kumar
e2f6ed693c Merge pull request #49421 from frappe/mergify/bp/version-15-hotfix/pr-49306
fix(exchange rate revaluation): add check for gain_loss (backport #49306)
2025-09-02 14:10:12 +05:30
ruthra kumar
dd0aa83882 Merge pull request #49420 from frappe/mergify/bp/version-15-hotfix/pr-49332
perf: check PCV (smaller) table before checking GL Entries (backport #49332)
2025-09-02 13:39:43 +05:30
ravibharathi656
1d28135898 fix(exchange rate revaluation): add check for gain_loss
(cherry picked from commit e5affb16c7)
2025-09-02 08:05:38 +00:00
Vignesh Sekar
fc47fbeaa1 perf: check PCV (smaller) table before checking GL Entries
(cherry picked from commit 4d3ddeae8d)
2025-09-02 07:47:16 +00:00
Diptanil Saha
8b2f384af3 Merge pull request #49419 from frappe/mergify/bp/version-15-hotfix/pr-49407
fix(perf): applying consistent index to fetch gl entries for financial statements (backport #49407)
2025-09-02 12:32:16 +05:30
diptanilsaha
a3605d8370 fix(perf): applying consistent index to fetch gl entries for financial statements
(cherry picked from commit 3e2fb85ae6)
2025-09-02 06:42:10 +00:00
ruthra kumar
a8531eec5b Merge pull request #49417 from frappe/mergify/bp/version-15-hotfix/pr-49379
fix: add is_cancelled in condition (backport #49379)
2025-09-02 11:14:07 +05:30
l0gesh29
f2c4baeb0e fix: add is_cancelled in condition
(cherry picked from commit 77a9cf6398)
2025-09-02 05:27:40 +00:00
ruthra kumar
28d69ca26f Merge pull request #49412 from frappe/mergify/bp/version-15-hotfix/pr-49366
fix(trial-balance-simple): ignore cancelled gl and add company filter (backport #49366)
2025-09-02 10:42:16 +05:30
Raffael Meyer
e36ff57c49 Merge pull request #49234 from frappe/mergify/bp/version-15-hotfix/pr-49232
fix: set missing due date in Purchase Invoice and POS Invoice (backport #49232)
2025-09-02 00:46:29 +02:00
rohitwaghchaure
7eb523fd5b Merge pull request #49408 from frappe/mergify/bp/version-15-hotfix/pr-49403
fix: validation for Recreate Stock Ledgers (backport #49403)
2025-09-01 22:08:50 +05:30
l0gesh29
835b9c3378 fix: ignore cancelled gl and add company filter
(cherry picked from commit afb067ce50)
2025-09-01 11:16:25 +00:00
Rohit Waghchaure
9f0d743e1b fix: validation for Recreate Stock Ledgers
(cherry picked from commit 785845a425)
2025-09-01 10:42:59 +00:00
ruthra kumar
ab089fae7e Merge pull request #49406 from frappe/mergify/bp/version-15-hotfix/pr-49335
fix: show company currency symbol (backport #49335)
2025-09-01 15:34:13 +05:30
Navin-S-R
ecb7858062 fix: show company currency symbol
(cherry picked from commit 49bb095152)

# Conflicts:
#	erpnext/selling/doctype/quotation_item/quotation_item.json
2025-09-01 15:09:02 +05:30
ruthra kumar
293735db32 Merge pull request #49404 from frappe/mergify/bp/version-15-hotfix/pr-49331
fix: run sync auto reconcile config with force (backport #49331)
2025-09-01 15:05:06 +05:30
ravibharathi656
9d34eb686c fix: run config with force
(cherry picked from commit e8288a2f63)
2025-09-01 09:13:04 +00:00
ruthra kumar
1e99ba5932 Merge pull request #49400 from frappe/mergify/bp/version-15-hotfix/pr-49302
fix(budget):  fiscal year assignment and approver role in budget (backport #49302)
2025-09-01 13:30:11 +05:30
Bhavan23
e6a305e972 fix(budget): always set fiscal year before fetching company approver role
(cherry picked from commit 770d6dd8e2)
2025-09-01 07:05:25 +00:00
Mihir Kandoi
ab0f37740c Merge pull request #49353 from IMS94/fix-defunct-payment-gateway-workspace-links
fix: remove defunct payment gateway links from ERPNext Integrations workspace
2025-09-01 11:34:09 +05:30
Mihir Kandoi
8db3307d6b Merge pull request #49395 from frappe/mergify/bp/version-15-hotfix/pr-49394
chore: remove unused import (Order) module (backport #49394)
2025-08-31 17:29:27 +05:30
Fawaz Alhafiz
6f20a2c6e5 chore: remove unused import (Order) module
(cherry picked from commit 4e86a46008)
2025-08-31 07:50:40 +00:00
Mihir Kandoi
6329f4524d Merge pull request #49391 from frappe/mergify/bp/version-15-hotfix/pr-49388
fix(repost item valuation): validate voucher type in transaction (backport #49388)
2025-08-30 23:56:13 +05:30
ravibharathi656
6761a023d0 fix(repost item valuation): validate voucher type in transaction
(cherry picked from commit 5663c2a1ca)
2025-08-30 17:56:29 +00:00
rohitwaghchaure
6317db19e1 Merge pull request #49387 from frappe/mergify/bp/version-15-hotfix/pr-49386
fix: Issue with Barcode Scanning in Stock Entry (backport #49386)
2025-08-30 13:59:53 +05:30
Rohit Waghchaure
45cdb39edd fix: Issue with Barcode Scanning in Stock Entry
(cherry picked from commit 13e3db3730)
2025-08-30 07:07:09 +00:00
rohitwaghchaure
dcb3e01df1 Merge pull request #49385 from frappe/mergify/bp/version-15-hotfix/pr-49376
fix(repost item valuation): reorder function call (backport #49376)
2025-08-30 12:36:17 +05:30
ravibharathi656
f43ed2e50e chore: remove console log
(cherry picked from commit d117411070)
2025-08-29 16:52:52 +00:00
ravibharathi656
e8025365cd fix(repost item valuation): reorder function call
(cherry picked from commit aaa4f0ae26)
2025-08-29 16:52:52 +00:00
mergify[bot]
c06f72f9f7 fix: 🐛 fixing buying controller to include transaction controller… (backport #49140) (#49370)
* fix: 🐛 fixing buying controller to include transaction controller… (#49140)

* fix: 🐛 fixing buying controller to include transaction controller function

* refactor: fixed formatting

---------

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
(cherry picked from commit aedb171dd4)

# Conflicts:
#	erpnext/public/js/controllers/buying.js

* chore: resolve conflicts

---------

Co-authored-by: jll-02 <63648645+jll-02@users.noreply.github.com>
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-08-28 23:42:35 +05:30
Imesha Sudasingha
17f7351f85 fix: remove defunct payment gateway links from ERPNext Integrations workspace
- Remove GoCardless Settings link (DocType deleted in v15.0)
- Remove Mpesa Settings link (DocType deleted in v15.0)
- Update Payments card link_count from 3 to 1
- Only Plaid Settings remains in Payments section

Fixes broken links that resulted in errors when clicked.
Closes #49352
2025-08-28 01:48:29 +05:30
Mihir Kandoi
b5d3863ecd Merge pull request #49349 from frappe/mergify/bp/version-15-hotfix/pr-49244
fix: convert NaN to numerical (backport #49244)
2025-08-27 22:46:27 +05:30
Mihir Kandoi
3ddaba9553 Merge pull request #49348 from frappe/mergify/bp/version-15-hotfix/pr-49258
feat: optional fixed outgoing email for RfQ (backport #49258)
2025-08-27 22:46:16 +05:30
Mihir Kandoi
9dc91e2bc6 Merge pull request #49351 from frappe/mergify/bp/version-15-hotfix/pr-49254
fix: show create purchase receipt button in purchase invoice only when update stock is not checked (backport #49254)
2025-08-27 22:45:29 +05:30
mergify[bot]
064ce4bf6d fix: hide is_cumulative for apply_on is set to Transaction (backport #49243) (#49257)
* fix: hide is_cumulative for apply_on is set to Transaction

(cherry picked from commit 699d42b26c)

# Conflicts:
#	erpnext/accounts/doctype/promotional_scheme/promotional_scheme.json

* chore: update modified date for promotional_scheme.json

---------

Co-authored-by: Navin-S-R <navin@aerele.in>
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-08-27 16:51:19 +00:00
anwarpatelnoori
caa1681c5f fix: show create purchase receipt button only when update stock is not checked
(cherry picked from commit ed550bb633)
2025-08-27 16:41:58 +00:00
Mihir Kandoi
700f96af61 Merge pull request #49175 from AssemBahnasy/fix-pricing-rule-utils-final
fix: Pricing rule validation not working for Sales Invoice when validate_applied_rule is enabled
2025-08-27 22:10:57 +05:30
El-Shafei H.
0b3fac3a0e fix: convert NaN to numerical
(cherry picked from commit fac8013dba)
2025-08-27 16:36:36 +00:00
0xD0M1M0
c875ff972f feat: optional fixed outgoing email for RfQ (#49258)
* feat: optional fixed outgoing email for RfQ

* fix: linters

* fix: select only outgoing account

* fix: linters

(cherry picked from commit 2bf0ba9802)
2025-08-27 16:32:37 +00:00
mergify[bot]
7926cfd8c4 fix: add option to disable Transaction Log (backport #49342) (#49344)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: add option to disable Transaction Log (#49342)
2025-08-27 14:13:39 +02:00
Mihir Kandoi
be6f79330a fix: source warehouse in manufacture entry and reqd prop of scrap warehouse (backport #49320) (#49337)
fix: source warehouse in manufacture entry and reqd prop of scrap warehouse

(cherry picked from commit fe0722c4f1)

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-08-26 21:59:02 +05:30
Mihir Kandoi
7bb180e5da fix: source warehouse in manufacture entry and reqd prop of scrap warehouse
(cherry picked from commit fe0722c4f1)
2025-08-26 16:01:30 +00:00
Frappe PR Bot
c86e95e524 chore(release): Bumped to Version 15.77.0
# [15.77.0](https://github.com/frappe/erpnext/compare/v15.76.0...v15.77.0) (2025-08-26)

### Bug Fixes

* **asset:** handle None in depreciation value ([f231b1e](f231b1e32f))
* child item picker picking all items when creating PI from PR ([edaff5d](edaff5d699))
* correct logic for warehouse field label ([0767c2e](0767c2e0f6))
* correct typo in monthly auto exchange rate revaluation filter ([aa35770](aa35770423))
* handle all searchfields in items ([db4fc85](db4fc8545d))
* handle ple for immutable ledger ([756216b](756216b2cb))
* incorrect pending qty when creating sales invoice from sales order ([54030eb](54030eb721))
* match warehouse only when `last_scanned_warehouse` field exists ([fbbd5a3](fbbd5a3af5))
* Serial Nos popup only appears 1 time ([1968120](196812017e))
* set valid serial no naming series format ([bec385a](bec385a667))
* set value for asset owner company field ([94cd454](94cd4549c6))
* **Supplier:** add make_method for Pricing Rule ([#49282](https://github.com/frappe/erpnext/issues/49282)) ([ba840d2](ba840d22e5))

### Features

* add make methods for Bank Account (backport [#49000](https://github.com/frappe/erpnext/issues/49000)) ([#49275](https://github.com/frappe/erpnext/issues/49275)) ([655af24](655af24183))
* **payment-reconciliation:** add posting date field for debit/credit note auto jv creation ([083661b](083661b779))
* show title in link field for Project DocType ([#49265](https://github.com/frappe/erpnext/issues/49265)) ([c52f2c7](c52f2c75f6))
2025-08-26 11:46:29 +00:00
ruthra kumar
c00e20e17c Merge pull request #49328 from frappe/version-15-hotfix
chore: release v15
2025-08-26 17:15:09 +05:30
ruthra kumar
45aa450f88 Merge pull request #49330 from frappe/mergify/bp/version-15-hotfix/pr-49236
fix: handle ple for immutable ledger (backport #49236)
2025-08-26 16:30:01 +05:30
l0gesh29
756216b2cb fix: handle ple for immutable ledger
(cherry picked from commit 48eb488918)

# Conflicts:
#	erpnext/accounts/general_ledger.py
#	erpnext/accounts/utils.py
2025-08-26 16:14:23 +05:30
ruthra kumar
2cf1dd37ba Merge pull request #49326 from frappe/mergify/bp/version-15-hotfix/pr-49296
fix(accounts): correct typo in monthly auto exchange rate revaluation filter (backport #49296)
2025-08-26 15:48:38 +05:30
Khushi Rawat
45c60911db Merge pull request #49325 from frappe/mergify/bp/version-15-hotfix/pr-49319
fix: set value for asset owner company field (backport #49319)
2025-08-26 15:27:02 +05:30
CoiledCoder
2cb2bdeb00 refactor: centralize exchange rate revaluation scheduling logic
- Introduced a private helper `_auto_create_exchange_rate_revaluation_for(frequency)`
- Removed duplicate logic across daily, weekly, and monthly ERR functions
- Prevents future copy-paste bugs
- Keeps existing behavior unchanged

(cherry picked from commit 15040a362d)
2025-08-26 09:09:49 +00:00
CoiledCoder
aa35770423 fix: correct typo in monthly auto exchange rate revaluation filter
The "auto_create_exchange_rate_revaluation_monthly" function was
using the wrong filter key `"Montly"` instead of `"Monthly"`.
As a result, no companies configured for monthly ERR were being
processed.

(cherry picked from commit 19729a307f)
2025-08-26 09:09:48 +00:00
khushi8112
94cd4549c6 fix: set value for asset owner company field
(cherry picked from commit a24f1d056b)
2025-08-26 09:06:48 +00:00
Khushi Rawat
bd40106c7d Merge pull request #49322 from aerele/cancel-asset-value-adjustment
fix(asset): handle None in depreciation value
2025-08-26 14:18:55 +05:30
ravibharathi656
f231b1e32f fix(asset): handle None in depreciation value 2025-08-26 13:33:26 +05:30
ruthra kumar
3a50554149 Merge pull request #49300 from frappe/mergify/bp/version-15-hotfix/pr-49252
feat(payment-reconciliation): add posting date field for debit/credit… (backport #49252)
2025-08-26 13:28:11 +05:30
ruthra kumar
64c5af202c Merge pull request #49315 from frappe/mergify/bp/version-15-hotfix/pr-48875
fix: incorrect pending qty when creating sales invoice from sales order (backport #48875)
2025-08-26 13:12:58 +05:30
ruthra kumar
9cd15939c9 Merge pull request #49293 from frappe/mergify/bp/version-15-hotfix/pr-49265
feat: show title in link field for Project DocType (backport #49265)
2025-08-26 11:35:12 +05:30
Hussain Nagaria
c52f2c75f6 feat: show title in link field for Project DocType (#49265)
(cherry picked from commit a5f200636a)

# Conflicts:
#	erpnext/projects/doctype/project/project.json
2025-08-26 11:18:39 +05:30
l0gesh29
083661b779 feat(payment-reconciliation): add posting date field for debit/credit note auto jv creation
(cherry picked from commit 6b4004b127)

# Conflicts:
#	erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json
2025-08-26 11:16:37 +05:30
ruthra kumar
6983573243 chore: resolve conflict 2025-08-26 11:06:55 +05:30
ravibharathi656
1380ee21b6 chore: remove update_stock
(cherry picked from commit 368dbe3bbf)
2025-08-25 19:39:14 +00:00
ravibharathi656
b403b6c7b4 test: add pending quantity check for invoice creation
(cherry picked from commit e5d4b4f0f0)

# Conflicts:
#	erpnext/selling/doctype/sales_order/test_sales_order.py
2025-08-25 19:39:14 +00:00
ravibharathi656
54030eb721 fix: incorrect pending qty when creating sales invoice from sales order
(cherry picked from commit a5138f4899)
2025-08-25 19:39:14 +00:00
Sagar Vora
5a7161eeb3 Merge pull request #49313 from frappe/mergify/bp/version-15-hotfix/pr-49312
fix: multiple fixes to warehouse barcode scanning logic (backport #49312)
2025-08-25 19:11:59 +00:00
Sagar Vora
0767c2e0f6 fix: correct logic for warehouse field label
(cherry picked from commit 72a38929e5)
2025-08-25 19:08:38 +00:00
Sagar Vora
fbbd5a3af5 fix: match warehouse only when last_scanned_warehouse field exists
(cherry picked from commit 4005e4412d)
2025-08-25 19:08:37 +00:00
rohitwaghchaure
04c2fca4e2 Merge pull request #49303 from frappe/mergify/bp/version-15-hotfix/pr-49301
fix: set valid serial no naming series format (backport #49301)
2025-08-25 17:51:15 +05:30
Kavin
bec385a667 fix: set valid serial no naming series format
(cherry picked from commit 46b85c7857)
2025-08-25 11:53:12 +00:00
Raffael Meyer
ba840d22e5 fix(Supplier): add make_method for Pricing Rule (#49282) 2025-08-22 19:18:42 +02:00
mergify[bot]
655af24183 feat: add make methods for Bank Account (backport #49000) (#49275)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-08-22 19:04:42 +02:00
mergify[bot]
c375ac3939 Merge pull request #49272 from frappe/mergify/bp/version-15-hotfix/pr-49050
fix: ensure variant conversion factor is returned before the template's (backport #49050)
2025-08-22 15:11:26 +05:30
rohitwaghchaure
e4f3836b31 Merge pull request #49270 from frappe/mergify/bp/version-15-hotfix/pr-49269
fix: Serial Nos popup only appears 1 time (backport #49269)
2025-08-21 23:38:01 +05:30
rohitwaghchaure
be01c4fafe chore: fix conflicts 2025-08-21 23:34:38 +05:30
Rohit Waghchaure
196812017e fix: Serial Nos popup only appears 1 time
(cherry picked from commit 5503d4b05b)

# Conflicts:
#	erpnext/public/js/controllers/transaction.js
2025-08-21 17:59:24 +00:00
Mihir Kandoi
c2d07eb2b2 Merge pull request #49263 from frappe/mergify/bp/version-15-hotfix/pr-49182 2025-08-21 18:11:02 +05:30
ravibharathi656
db4fc8545d fix: handle all searchfields in items
(cherry picked from commit ad559c3491)
2025-08-21 10:56:31 +00:00
Mihir Kandoi
b7307b4a56 Merge pull request #49251 from frappe/mergify/bp/version-15-hotfix/pr-49250 2025-08-20 18:04:08 +05:30
Mihir Kandoi
edaff5d699 fix: child item picker picking all items when creating PI from PR
(cherry picked from commit 738c1e0d0a)
2025-08-20 12:18:59 +00:00
Mihir Kandoi
dec7680d73 Merge pull request #49247 from frappe/mergify/bp/version-15-hotfix/pr-49183
Fix/mr status from wo (backport #49183)
2025-08-20 15:28:26 +05:30
Kavin
1c7a18866f Merge pull request #49183 from aerele/fix/mr-status-from-wo
Fix/mr status from wo

(cherry picked from commit 67e57018bc)
2025-08-20 09:43:11 +00:00
Raffael Meyer
6a31b7b118 fix: set missing due date in Purchase Invoice and POS Invoice (#49232)
(cherry picked from commit 77478303fe)
2025-08-19 12:31:26 +00:00
Frappe PR Bot
36bc8fe3f0 chore(release): Bumped to Version 15.76.0
# [15.76.0](https://github.com/frappe/erpnext/compare/v15.75.1...v15.76.0) (2025-08-19)

### Bug Fixes

* add fieldname in accounting dimension filter ([ac4a5bf](ac4a5bfe6d))
* add patch ([a853010](a853010537))
* add validation for draft PR/PI in Asset ([4187e60](4187e60b07))
* add value adjustment amount in asset value ([89ad9f1](89ad9f1bb4))
* add value adjustment amount in report for group by category filter ([089007f](089007f88a))
* additional cost not consider in valuation rate for Stock Entry transfer ([e4398d3](e4398d3761))
* apply grand total to default payment mode in Sales and POS invoices ([605f513](605f513ce3))
* **asset:** prevent translation function shadowing in make_journal_entry ([1af8ab2](1af8ab2a3b))
* company issue in setup wizard ([cea4b50](cea4b50bbc))
* current qty for batch in stock reco ([3ecb09a](3ecb09ae52))
* fetch fieldname in accounting dimension filter ([d494d8c](d494d8c299))
* formatted string for disabled filter in get_income_account ([c9f79b3](c9f79b3ba9))
* handle default accounting dimension ([e50d6c6](e50d6c6b62))
* handle default dimension for all company ([0cd45a0](0cd45a0022))
* handle empty loyalty point details ([dc953f7](dc953f70d1))
* handle mode of payment filter (backport [#49185](https://github.com/frappe/erpnext/issues/49185)) ([#49221](https://github.com/frappe/erpnext/issues/49221)) ([b6c992f](b6c992ffeb))
* ignore links in Dunning patch (backport [#49201](https://github.com/frappe/erpnext/issues/49201)) ([#49204](https://github.com/frappe/erpnext/issues/49204)) ([07ff97f](07ff97f647))
* **pos:** include Product Bundle components in reserved qty to prevent overselling ([5ce0dc2](5ce0dc2a7a)), closes [#49021](https://github.com/frappe/erpnext/issues/49021)
* **pos:** populate packed_items table in POS Invoice ([1f3d8e8](1f3d8e8d64))
* **pos:** use packed_items snapshot for bundle reservations ([cc82836](cc82836109)), closes [#49106](https://github.com/frappe/erpnext/issues/49106)
* product bundle child item quantity should be a positive number ([f831d45](f831d45cc3))
* **quotation:** update currency on duplicate ([419f717](419f717542))
* remove unclear message related to availability of product bundle ([383744b](383744b8e4))
* sanitize column name for inventory_dimensions in get_stock_balance ([69389bb](69389bb355))
* **stock:** don't override t_warehouse if no rules found ([da3d8fb](da3d8fbbc5))
* update dunning status based on credit notes (backport [#49066](https://github.com/frappe/erpnext/issues/49066)) ([#49208](https://github.com/frappe/erpnext/issues/49208)) ([9a12c73](9a12c73e22))
* use query builder instead of raw SQL in get_blanket_orders ([4a0d7fd](4a0d7fd205))
* use query builder instead of raw SQL in get_loyalty_details ([a3c5b0a](a3c5b0a510))
* use query builder instead of raw SQL in get_material_requests_based_on_supplier ([9d0fe06](9d0fe060c8))
* use query builder instead of raw SQL in get_rfq_containing_supplier ([4ac386a](4ac386a84e))
* use query builder instead of raw SQL in get_timesheet_detail_rate ([0a2a7fa](0a2a7fa6aa))
* use query builder instead of raw SQL in unset_existing_data ([92391a6](92391a69cf))
* wrap inter-company order button labels in __() for translation ([#49178](https://github.com/frappe/erpnext/issues/49178)) ([db48635](db486356db))
* wrap inter-company order button labels in __() for translation (backport [#49178](https://github.com/frappe/erpnext/issues/49178)) ([#49179](https://github.com/frappe/erpnext/issues/49179)) ([6030eb2](6030eb2992))

### Features

* enhance barcode scanner to support warehouse scanning (backport [#48865](https://github.com/frappe/erpnext/issues/48865)) ([#49162](https://github.com/frappe/erpnext/issues/49162)) ([ad052d7](ad052d72d7))
* select child item when creating one document from another ([5f06d87](5f06d87f01))

### Reverts

* Revert "fix: use checkout@v2 instead of v4" ([e849019](e8490196ba))
2025-08-19 11:56:17 +00:00
ruthra kumar
cf86843d48 Merge pull request #49227 from frappe/version-15-hotfix
chore: release v15
2025-08-19 17:25:00 +05:30
rohitwaghchaure
696fbbb0e2 Merge pull request #49230 from frappe/mergify/bp/version-15-hotfix/pr-49228
fix: company issue in setup wizard (backport #49228)
2025-08-19 16:42:29 +05:30
rohitwaghchaure
dffa3baea6 Merge pull request #49229 from frappe/mergify/bp/version-15-hotfix/pr-49223
fix(stock): don't override t_warehouse if no rules found (backport #49223)
2025-08-19 16:27:14 +05:30
Rohit Waghchaure
cea4b50bbc fix: company issue in setup wizard
(cherry picked from commit 1fb0d1460a)
2025-08-19 10:52:49 +00:00
Kavin
da3d8fbbc5 fix(stock): don't override t_warehouse if no rules found
(cherry picked from commit 66f217c8e6)
2025-08-19 10:39:47 +00:00
ruthra kumar
dac8dc6b8a Merge pull request #49224 from frappe/mergify/bp/version-15-hotfix/pr-49102
fix(quotation): update currency on duplicate (backport #49102)
2025-08-19 14:10:21 +05:30
ravibharathi656
419f717542 fix(quotation): update currency on duplicate
(cherry picked from commit 430a06d056)
2025-08-19 08:35:09 +00:00
Khushi Rawat
80d9181b29 Merge pull request #49215 from frappe/mergify/bp/version-15-hotfix/pr-49141
refactor: consider asset value adjustments in report (backport #49141)
2025-08-19 13:06:54 +05:30
ruthra kumar
b6c992ffeb fix: handle mode of payment filter (backport #49185) (#49221)
Merge pull request #49185 from aerele/mop-sales-register

fix: handle mode of payment filter
(cherry picked from commit d656e02441)

Co-authored-by: Logesh Periyasamy <logeshperiyasamy24@gmail.com>
2025-08-19 12:26:25 +05:30
Logesh Periyasamy
cfb7558465 Merge pull request #49185 from aerele/mop-sales-register
fix: handle mode of payment filter
(cherry picked from commit d656e02441)
2025-08-19 06:33:41 +00:00
ruthra kumar
2cfdb2d2cd Merge pull request #49218 from frappe/mergify/bp/version-15-hotfix/pr-49055
fix: fetch fieldname in accounting dimension filter (backport #49055)
2025-08-19 11:24:52 +05:30
Diptanil Saha
529a84154b Merge pull request #49219 from frappe/mergify/bp/version-15-hotfix/pr-49192
fix: improve queries with query builder and input sanitization (backport #49192)
2025-08-19 11:16:02 +05:30
ruthra kumar
4af814dc3b chore: resolve conflicts 2025-08-19 11:06:23 +05:30
diptanilsaha
dc953f70d1 fix: handle empty loyalty point details
(cherry picked from commit 1231ca17c9)
2025-08-19 05:25:19 +00:00
diptanilsaha
0a2a7fa6aa fix: use query builder instead of raw SQL in get_timesheet_detail_rate
(cherry picked from commit e563ed0c75)
2025-08-19 05:25:19 +00:00
diptanilsaha
4ac386a84e fix: use query builder instead of raw SQL in get_rfq_containing_supplier
(cherry picked from commit 7f2a52ff71)
2025-08-19 05:25:18 +00:00
diptanilsaha
92391a69cf fix: use query builder instead of raw SQL in unset_existing_data
(cherry picked from commit 7fa4ed6139)
2025-08-19 05:25:18 +00:00
diptanilsaha
69389bb355 fix: sanitize column name for inventory_dimensions in get_stock_balance
(cherry picked from commit eb22794f14)
2025-08-19 05:25:18 +00:00
diptanilsaha
4a0d7fd205 fix: use query builder instead of raw SQL in get_blanket_orders
(cherry picked from commit 1db135262d)
2025-08-19 05:25:18 +00:00
diptanilsaha
c9f79b3ba9 fix: formatted string for disabled filter in get_income_account
(cherry picked from commit 6320f7290f)
2025-08-19 05:25:17 +00:00
diptanilsaha
9d0fe060c8 fix: use query builder instead of raw SQL in get_material_requests_based_on_supplier
(cherry picked from commit de919568b4)
2025-08-19 05:25:17 +00:00
diptanilsaha
a3c5b0a510 fix: use query builder instead of raw SQL in get_loyalty_details
(cherry picked from commit 8696ba2f5d)
2025-08-19 05:25:17 +00:00
l0gesh29
0cd45a0022 fix: handle default dimension for all company
(cherry picked from commit 77021fff74)
2025-08-19 05:19:01 +00:00
l0gesh29
e50d6c6b62 fix: handle default accounting dimension
(cherry picked from commit 16e440f9a7)
2025-08-19 05:19:01 +00:00
l0gesh29
a853010537 fix: add patch
(cherry picked from commit 3cf765d985)

# Conflicts:
#	erpnext/patches.txt
2025-08-19 05:19:00 +00:00
l0gesh29
d494d8c299 fix: fetch fieldname in accounting dimension filter
(cherry picked from commit 42f9d27d79)
2025-08-19 05:18:59 +00:00
l0gesh29
ac4a5bfe6d fix: add fieldname in accounting dimension filter
(cherry picked from commit ac2acc535d)

# Conflicts:
#	erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.json
2025-08-19 05:18:59 +00:00
khushi8112
089007f88a fix: add value adjustment amount in report for group by category filter
(cherry picked from commit cd2bab7c5f)
2025-08-18 21:28:42 +00:00
khushi8112
89ad9f1bb4 fix: add value adjustment amount in asset value
(cherry picked from commit f8050f4278)
2025-08-18 21:28:42 +00:00
Diptanil Saha
d14391fb6f Merge pull request #49210 from diptanilsaha/skip_gt_default_mop
fix: apply grand total to default payment mode in Sales and POS invoices
2025-08-18 17:27:02 +05:30
mergify[bot]
9a12c73e22 fix: update dunning status based on credit notes (backport #49066) (#49208)
Co-authored-by: Karm Soni <karmdsoni8159@gmail.com>
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
2025-08-18 11:51:24 +00:00
diptanilsaha
605f513ce3 fix: apply grand total to default payment mode in Sales and POS invoices 2025-08-18 17:04:38 +05:30
Diptanil Saha
fb34991980 Merge pull request #49207 from frappe/mergify/bp/version-15-hotfix/pr-49169
fix(asset): prevent translation function shadowing in make_journal_entry (backport #49169)
2025-08-18 15:16:37 +05:30
l0gesh29
1af8ab2a3b fix(asset): prevent translation function shadowing in make_journal_entry
(cherry picked from commit 5e82de1b71)
2025-08-18 09:26:40 +00:00
mergify[bot]
07ff97f647 fix: ignore links in Dunning patch (backport #49201) (#49204)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: ignore links in Dunning patch (#49201)
2025-08-17 18:52:55 +00:00
Mihir Kandoi
b49f85b877 Merge pull request #49197 from mihir-kandoi/version-15-hotfix 2025-08-17 14:27:00 +05:30
Mihir Kandoi
e8490196ba Revert "fix: use checkout@v2 instead of v4"
This reverts commit c9d69d9629.
2025-08-17 13:01:58 +05:30
rohitwaghchaure
bc1c57a18a Merge pull request #49195 from frappe/mergify/bp/version-15-hotfix/pr-49193
fix: additional cost not consider in valuation rate for Stock Entry transfer (backport #49193)
2025-08-17 11:15:19 +05:30
rohitwaghchaure
016948804d chore: fix test case 2025-08-17 10:55:54 +05:30
rohitwaghchaure
41e7463412 chore: fix conflicts 2025-08-17 10:54:46 +05:30
Rohit Waghchaure
e4398d3761 fix: additional cost not consider in valuation rate for Stock Entry transfer
(cherry picked from commit bbc772abe7)

# Conflicts:
#	erpnext/stock/doctype/stock_entry/test_stock_entry.py
2025-08-17 05:22:52 +00:00
Mihir Kandoi
6030eb2992 fix: wrap inter-company order button labels in __() for translation (backport #49178) (#49179)
fix: wrap inter-company order button labels in __() for translation (#49178)

* Updated purchase_order.js

* Update sales_order.js

(cherry picked from commit 078b8439d9)

Co-authored-by: divyalekha99 <32547248+divyalekha99@users.noreply.github.com>
2025-08-14 20:33:32 +05:30
divyalekha99
db486356db fix: wrap inter-company order button labels in __() for translation (#49178)
* Updated purchase_order.js

* Update sales_order.js

(cherry picked from commit 078b8439d9)
2025-08-14 15:00:01 +00:00
Diptanil Saha
464f504b61 Merge pull request #49177 from frappe/mergify/bp/version-15-hotfix/pr-49108
fix(pos): include Product Bundle components in reserved qty to preven… (backport #49108)
2025-08-14 19:09:42 +05:30
Diptanil Saha
84fda4afb5 Merge pull request #49176 from frappe/mergify/bp/version-15-hotfix/pr-49163
fix: product bundle child item quantity should be a positive number (backport #49163)
2025-08-14 19:08:53 +05:30
Lewis
93ad17ac7b chore: improve code clarity per reviewer feedback
- Rename stock_qty variable to reserved_qty for clarity
- Update get_pos_reserved_qty_from_table to return float
- Simplify aggregation logic in get_pos_reserved_qty
- Ensure return values match docstring specifications

(cherry picked from commit 54d3e5675f)
2025-08-14 13:19:28 +00:00
diptanilsaha
f831d45cc3 fix: product bundle child item quantity should be a positive number
(cherry picked from commit 711076d02d)
2025-08-14 13:19:27 +00:00
Lewis
cc82836109 fix(pos): use packed_items snapshot for bundle reservations
Replaced live Product Bundle queries with `Packed Item` table
lookups to ensure historical reservation accuracy.
Addresses bundle qty underestimation and avoids errors when
bundle definitions change after sale.

Inspired by approach from @diptanilsaha in #49106.

(cherry picked from commit d77d79e011)
2025-08-14 13:19:27 +00:00
Lewis
383744b8e4 fix: remove unclear message related to availability of product bundle
(cherry picked from commit f5e5f7b588)
2025-08-14 13:19:27 +00:00
Lewis
1f3d8e8d64 fix(pos): populate packed_items table in POS Invoice
(cherry picked from commit a65b200eb7)
2025-08-14 13:19:27 +00:00
Lewis
c9902eed72 chore: apply pre-commit formatting
(cherry picked from commit 0fc187adc3)
2025-08-14 13:19:26 +00:00
Lewis Mojica
0d793c11a1 chore: remove unused variable
(cherry picked from commit 5a5804ca87)
2025-08-14 13:19:26 +00:00
Lewis
5ce0dc2a7a fix(pos): include Product Bundle components in reserved qty to prevent overselling
- Add `get_bundle_pos_reserved_qty` to account for component items in submitted POS Invoices
- Update `get_pos_reserved_qty` to sum direct and bundle reservations
- Remove double subtraction in `get_bundle_availability` to avoid underestimating bundle availability
- Prevents overselling when multiple POS sessions sell bundles with shared components
- Fixes #49021

(cherry picked from commit 984d744ac2)
2025-08-14 13:19:26 +00:00
Assem Bahnasy
d6d8903d13 style: Apply ruff formatting 2025-08-14 16:05:09 +03:00
mergify[bot]
ad052d72d7 feat: enhance barcode scanner to support warehouse scanning (backport #48865) (#49162)
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
Co-authored-by: Soni Karm <93865733+karm1000@users.noreply.github.com>
2025-08-14 13:20:01 +05:30
Khushi Rawat
8d9095def0 Merge pull request #49146 from frappe/mergify/bp/version-15-hotfix/pr-49075
fix: add validation for draft PR/PI in Asset (backport #49075)
2025-08-14 12:10:00 +05:30
Frappe PR Bot
aaeb3ab06c chore(release): Bumped to Version 15.75.1
## [15.75.1](https://github.com/frappe/erpnext/compare/v15.75.0...v15.75.1) (2025-08-14)

### Bug Fixes

* current qty for batch in stock reco ([de641d7](de641d7f68))
2025-08-14 06:03:46 +00:00
rohitwaghchaure
1975ec3f76 Merge pull request #49159 from frappe/mergify/bp/version-15/pr-49158
chore: convert message to toast notification (backport #49155) (backport #49158)
2025-08-14 11:32:20 +05:30
rohitwaghchaure
b4533ee362 Merge pull request #49160 from frappe/mergify/bp/version-15/pr-49156
fix: current qty for batch in stock reco (backport #49154) (backport #49156)
2025-08-14 11:32:01 +05:30
Rohit Waghchaure
de641d7f68 fix: current qty for batch in stock reco
(cherry picked from commit 817e719cc2)
(cherry picked from commit 3ecb09ae52)
2025-08-14 05:27:13 +00:00
Rohit Waghchaure
02735e69dd chore: convert message to toast notification
(cherry picked from commit fc71001110)
(cherry picked from commit 7a04bf85bc)
2025-08-14 05:26:23 +00:00
rohitwaghchaure
ae22a90160 Merge pull request #49158 from frappe/mergify/bp/version-15-hotfix/pr-49155
chore: convert message to toast notification (backport #49155)
2025-08-14 10:55:28 +05:30
Rohit Waghchaure
7a04bf85bc chore: convert message to toast notification
(cherry picked from commit fc71001110)
2025-08-14 05:06:00 +00:00
rohitwaghchaure
ef0f91f862 Merge pull request #49156 from frappe/mergify/bp/version-15-hotfix/pr-49154
fix: current qty for batch in stock reco (backport #49154)
2025-08-14 08:31:20 +05:30
Rohit Waghchaure
3ecb09ae52 fix: current qty for batch in stock reco
(cherry picked from commit 817e719cc2)
2025-08-13 18:28:29 +00:00
Khushi Rawat
9c5dacd977 refactor: validate linked purchase docs before field usage
(cherry picked from commit 4a48b13715)
2025-08-13 11:49:35 +00:00
Rehan Ansari
4187e60b07 fix: add validation for draft PR/PI in Asset
(cherry picked from commit 4cf481cca8)
2025-08-13 11:49:35 +00:00
Mihir Kandoi
69eb31028a Merge pull request #49138 from frappe/mergify/bp/version-15-hotfix/pr-49134
chore: add default value for posting_time field in subcontracting receipt (backport #49134)
2025-08-13 14:21:41 +05:30
Karm Soni
15a104b0f8 chore: add default value for posting_time field in subcontracting receipt
(cherry picked from commit b7470617e0)
2025-08-13 08:35:45 +00:00
Mihir Kandoi
6b436e1e71 Merge pull request #49124 from frappe/mergify/bp/version-15-hotfix/pr-49122
feat: select child item when creating one document from another (backport #49122)
2025-08-12 21:53:39 +05:30
Mihir Kandoi
5f06d87f01 feat: select child item when creating one document from another
(cherry picked from commit a9936ae133)
2025-08-12 16:07:51 +00:00
Frappe PR Bot
ed50c3d896 chore(release): Bumped to Version 15.75.0
# [15.75.0](https://github.com/frappe/erpnext/compare/v15.74.0...v15.75.0) (2025-08-12)

### Bug Fixes

* avoid property setter for custom field ([faae734](faae734797))
* handle case where taxes is added invoice changed to non-export later ([90913c6](90913c66ae))
* handle negative inventory check ([#48558](https://github.com/frappe/erpnext/issues/48558)) ([#48691](https://github.com/frappe/erpnext/issues/48691)) ([9da2be2](9da2be2325))
* Pick List barcode scanner and manual picking issues ([38c886d](38c886db8b))
* **process statement of accounts:** use date instead of formatted date ([6ad3461](6ad3461953))
* **regional-uae:** mark export items as zero rated ([9df6424](9df6424a20))
* **regional-uae:** restrict zero rated export to invoice ([62db42c](62db42cf2f))
* **regional-uae:** split export determination ([106b83e](106b83e9f9))
* show message only if no tax is applied ([614d38d](614d38d0e6))
* show name of the employee in general ledger report ([0e7f778](0e7f778b3f))
* simplify export determination logic ([68c6586](68c65866bf))
* table render issue on pop-up edit ([52db89f](52db89f73f))

### Features

* add customer name column in gross profit report ([9cd6053](9cd60531d2))
* add item_name column to Material Request dialog in Purchase Order ([eafe33a](eafe33a176))
* add party name column in general ledger report ([680fa3b](680fa3b8f3))
* add party name in GL entries ([3763ad4](3763ad451b))

### Performance Improvements

* multiple performance fixes in `get_item_warehouse` (backport [#49118](https://github.com/frappe/erpnext/issues/49118)) ([76b0f4f](76b0f4fb25))
2025-08-12 12:04:27 +00:00
ruthra kumar
85bb086e90 Merge pull request #49116 from frappe/version-15-hotfix
chore: release v15
2025-08-12 17:33:04 +05:30
mergify[bot]
76b0f4fb25 perf: multiple performance fixes in get_item_warehouse (backport #49118)
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
2025-08-12 11:43:43 +00:00
ruthra kumar
167ff00c99 Merge pull request #48999 from frappe/mergify/bp/version-15-hotfix/pr-48761
fix: prevent gain or loss entry cancellation upon reposting (backport #48761)
2025-08-12 17:03:12 +05:30
Logesh Periyasamy
6e7fb2ea01 Merge pull request #48761 from aerele/exchange-gain-or-loss-on-repost
fix: prevent gain or loss entry cancellation upon reposting
(cherry picked from commit a8d17b7590)
2025-08-12 16:47:07 +05:30
ruthra kumar
daf3aab6ae Merge pull request #49111 from frappe/mergify/bp/version-15-hotfix/pr-49086
fix(process statement of accounts): use date instead of formatted date (backport #49086)
2025-08-12 11:39:14 +05:30
ruthra kumar
1c9a74f81c Merge pull request #49110 from frappe/mergify/bp/version-15-hotfix/pr-49096
fix: table render issue on pop-up edit (backport #49096)
2025-08-12 10:49:38 +05:30
ruthra kumar
2eaffa119f Merge pull request #48715 from wojosc/patch-44
refactor: remove default value for opportunity type
2025-08-12 10:49:16 +05:30
ravibharathi656
6ad3461953 fix(process statement of accounts): use date instead of formatted date
(cherry picked from commit aa3f50ab77)
2025-08-12 05:18:09 +00:00
l0gesh29
52db89f73f fix: table render issue on pop-up edit
(cherry picked from commit 3431c6c90e)
2025-08-12 05:10:22 +00:00
Khushi Rawat
4f72635698 Merge pull request #49100 from frappe/mergify/bp/version-15-hotfix/pr-48862
feat: show party name in reports (backport #48862)
2025-08-11 18:25:50 +05:30
khushi8112
0e7f778b3f fix: show name of the employee in general ledger report
(cherry picked from commit 70411ec086)
2025-08-11 12:24:45 +00:00
khushi8112
d6e9216a45 chore: code format
(cherry picked from commit b0c0a86fcf)
2025-08-11 12:24:45 +00:00
khushi8112
9cd60531d2 feat: add customer name column in gross profit report
(cherry picked from commit 9dee411eb5)
2025-08-11 12:24:44 +00:00
khushi8112
3763ad451b feat: add party name in GL entries
(cherry picked from commit 3d94a7cf2c)
2025-08-11 12:24:44 +00:00
khushi8112
680fa3b8f3 feat: add party name column in general ledger report
(cherry picked from commit 5f24061dd4)
2025-08-11 12:24:44 +00:00
ruthra kumar
0644c78c2e Merge pull request #49097 from frappe/mergify/bp/version-15-hotfix/pr-49093
fix: allow creation of root accounts in account tree view  (backport #49093)
2025-08-11 17:44:51 +05:30
Lakshit Jain
c2ad5d0fc7 Merge pull request #49093 from ljain112/fix-account-coa
fix: allow creation of root accounts in account tree view

(cherry picked from commit d45cd5af2b)
2025-08-11 11:38:30 +00:00
Asmita Hase
6de74697c9 Merge pull request #49095 from frappe/mergify/bp/version-15-hotfix/pr-49088
fix: Include Employee party type in Receivable and Payable account filters (backport #49088)
2025-08-11 17:01:48 +05:30
Wolfram Schmidt
36197afa19 refactor: remove default value for opportunity type
removing default value as this leads to an error in non-english setups
2025-08-11 16:54:56 +05:30
Assem Bahnasy
e762007e0e refactor: Move Employee inclusion to SQL level to preserve search semantics
(cherry picked from commit 8a9bf166c6)
2025-08-11 11:15:19 +00:00
Assem Bahnasy
c462219dd7 refactor: Use parameterized SQL queries to prevent injection and handle None values
(cherry picked from commit a08c7f37d3)
2025-08-11 11:15:19 +00:00
ruthra kumar
0cd9330e44 Merge pull request #49085 from frappe/mergify/bp/version-15-hotfix/pr-48730
fix(regional-uae): mark export items as zero rated (backport #48730)
2025-08-11 12:35:56 +05:30
ruthra kumar
faba523086 chore: resolve conflict 2025-08-11 11:41:10 +05:30
Dany Robert
90913c66ae fix: handle case where taxes is added invoice changed to non-export later
(cherry picked from commit 29c3ef8280)
2025-08-11 06:06:08 +00:00
Dany Robert
d47c25287d chore: code styling
(cherry picked from commit c8940a39b3)
2025-08-11 06:06:08 +00:00
Dany Robert
614d38d0e6 fix: show message only if no tax is applied
(cherry picked from commit 38471995e7)
2025-08-11 06:06:08 +00:00
Dany Robert
534b27afa5 chore: linters
(cherry picked from commit eb6c8d8938)
2025-08-11 06:06:07 +00:00
Dany Robert
faae734797 fix: avoid property setter for custom field
(cherry picked from commit 0c15b65756)
2025-08-11 06:06:07 +00:00
Dany Robert
68c65866bf fix: simplify export determination logic
(cherry picked from commit d25846f383)
2025-08-11 06:06:07 +00:00
Dany Robert
62db42cf2f fix(regional-uae): restrict zero rated export to invoice
(cherry picked from commit 1170e4fb2c)
2025-08-11 06:06:06 +00:00
Dany Robert
106b83e9f9 fix(regional-uae): split export determination
(cherry picked from commit dc72e6cf36)
2025-08-11 06:06:06 +00:00
Dany Robert
9df6424a20 fix(regional-uae): mark export items as zero rated
(cherry picked from commit b8224693c4)

# Conflicts:
#	erpnext/patches.txt
2025-08-11 06:06:06 +00:00
Mihir Kandoi
474ddbae0c Merge pull request #49083 from frappe/mergify/bp/version-15-hotfix/pr-48691
fix: handle negative inventory check (#48558) (backport #48691)
2025-08-11 10:45:20 +05:30
Vishist16
9da2be2325 fix: handle negative inventory check (#48558) (#48691)
* fix: handle negative inventory check (#48558)

* fix: updated DocField via Desk UI as suggested

* fix: update DocField via Desk UI and fix linting issues

(cherry picked from commit 3ee23d9ee8)
2025-08-11 05:00:20 +00:00
mergify[bot]
15e8fa3189 Merge pull request #49081 from frappe/mergify/bp/version-15-hotfix/pr-49068
fix(job-card): Add filter to item_code query for scrap_items to exclude disabled (backport #49068)
2025-08-11 10:25:21 +05:30
Mihir Kandoi
02d2ad6442 Merge pull request #49080 from frappe/mergify/bp/version-15-hotfix/pr-49071
feat: add item_name column to Material Request dialog in Purchase Order (backport #49071)
2025-08-11 10:11:47 +05:30
navinrc
eafe33a176 feat: add item_name column to Material Request dialog in Purchase Order
(cherry picked from commit 4312719010)
2025-08-11 04:33:31 +00:00
rohitwaghchaure
bb2c21be44 Merge pull request #49029 from IMS94/fix/pick-list-barcode-scanner-serial-assignment-hotfix
fix: Pick List barcode scanner and manual picking issues
2025-08-08 19:53:21 +05:30
Frappe PR Bot
d4519e5d3d chore(release): Bumped to Version 15.74.0
# [15.74.0](https://github.com/frappe/erpnext/compare/v15.73.2...v15.74.0) (2025-08-08)

### Bug Fixes

* add condition to fetch active accounts ([0d47eb1](0d47eb1fa0))
* added a flag on journal entry to ignore party account type validation if required ([8a3fdb4](8a3fdb4ec2))
* dont validate account type in for employee party type ([d3dde83](d3dde833f7))
* nonetype error on applying presentation_currency filter on financial statements and trial balance report ([24ca7bb](24ca7bb64f))
* **purchase invoice:** filter only enabled account ([b060cdb](b060cdb4f5))
* stock reservation Delivered Qty against the batch ([849f646](849f646bd2))
* timeout while submitting purchase receipt ([e693ab7](e693ab76fa))
* zero valuation rate for the batch ([90a0873](90a0873044))

### Features

* added chart of accounts and tax template for australian localisation ([#48208](https://github.com/frappe/erpnext/issues/48208)) ([36cb5b6](36cb5b6589))
2025-08-08 09:20:20 +00:00
Asmita Hase
1fceebd0a8 Merge pull request #49058 from frappe/version-15-hotfix 2025-08-08 14:48:56 +05:30
Asmita Hase
418d14ecc9 Merge pull request #49054 from frappe/mergify/bp/version-15-hotfix/pr-49053
fix: dont validate account type while creating journal entry for employee party type (backport #49053)
2025-08-08 14:19:17 +05:30
Asmita Hase
d3dde833f7 fix: dont validate account type in for employee party type
(cherry picked from commit e7a2ff1884)
2025-08-08 08:28:37 +00:00
Asmita Hase
0e56c47a4c Merge pull request #49052 from frappe/mergify/bp/version-15-hotfix/pr-49051 2025-08-08 13:56:38 +05:30
Asmita Hase
5f2725f61f chore: trigger create_advance_payment_ledger_records patch
(cherry picked from commit 6d908f44a5)
2025-08-08 07:29:33 +00:00
Mihir Kandoi
b45d74c56e Merge pull request #49049 from frappe/mergify/bp/version-15-hotfix/pr-48813
fix(purchase invoice): filter only enabled account (backport #48813)
2025-08-08 11:11:43 +05:30
mithili
90e583db19 chore: add back filter
(cherry picked from commit 23308f6d10)
2025-08-08 05:25:04 +00:00
mithili
0d47eb1fa0 fix: add condition to fetch active accounts
(cherry picked from commit 7c8dd86a35)
2025-08-08 05:25:04 +00:00
mithili
b060cdb4f5 fix(purchase invoice): filter only enabled account
(cherry picked from commit c3111db6e2)
2025-08-08 05:25:04 +00:00
Asmita Hase
09c96d6a83 Merge pull request #49044 from frappe/mergify/bp/version-15-hotfix/pr-49042
fix: flag on journal entry to ignore party account type validation if required (backport #49042)
2025-08-07 18:17:15 +05:30
Asmita Hase
8a3fdb4ec2 fix: added a flag on journal entry to ignore party account type validation if required
(cherry picked from commit 0665d13fd3)
2025-08-07 12:30:05 +00:00
Frappe PR Bot
e0313bb27f chore(release): Bumped to Version 15.73.2
## [15.73.2](https://github.com/frappe/erpnext/compare/v15.73.1...v15.73.2) (2025-08-07)

### Bug Fixes

* zero valuation rate for the batch ([fb126e0](fb126e0838))
2025-08-07 11:03:27 +00:00
rohitwaghchaure
04c5369792 Merge pull request #49039 from frappe/mergify/bp/version-15/pr-49022
fix: zero valuation rate for the batch (backport #49022)
2025-08-07 16:32:05 +05:30
rohitwaghchaure
a11d368465 chore: fix conflicts 2025-08-07 16:15:31 +05:30
Rohit Waghchaure
fb126e0838 fix: zero valuation rate for the batch
(cherry picked from commit c8410cb5ca)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
2025-08-07 10:43:45 +00:00
rohitwaghchaure
96e467670a Merge pull request #49035 from frappe/mergify/bp/version-15-hotfix/pr-49022
fix: zero valuation rate for the batch (backport #49022)
2025-08-07 14:34:46 +05:30
rohitwaghchaure
105838091e chore: fix conflicts 2025-08-07 14:10:21 +05:30
Rohit Waghchaure
90a0873044 fix: zero valuation rate for the batch
(cherry picked from commit c8410cb5ca)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
2025-08-07 08:25:51 +00:00
rohitwaghchaure
965de96251 Merge pull request #49012 from rohitwaghchaure/fixed-support-43860
fix: stock reservation Delivered Qty against the batch
2025-08-07 12:27:54 +05:30
ruthra kumar
1a57f603fb Merge pull request #49031 from frappe/mergify/bp/version-15-hotfix/pr-48208
feat: added chart of accounts and tax template for australian localisation (backport #48208)
2025-08-07 10:36:52 +05:30
Jeba Jebas
36cb5b6589 feat: added chart of accounts and tax template for australian localisation (#48208)
* Add Australian Localisation Setup

* feat: added chart of accounts and tax template for australian localisation

* chore: linter fix

---------

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
(cherry picked from commit bb62a01c0d)
2025-08-07 04:39:17 +00:00
Imesha Sudasingha
dab6bb8e05 style: apply pre-commit formatting fixes 2025-08-07 05:15:42 +05:30
Imesha Sudasingha
eebeb36b6c refactor: combine duplicate pick_manually handlers in pick_list.js 2025-08-07 05:09:46 +05:30
Imesha Sudasingha
38c886db8b fix: Pick List barcode scanner and manual picking issues
- Fix barcode scanner serial_no_field configuration from 'not_supported' to 'serial_no'
- Add conditional serial assignment in create_pick_list to respect pick_manually flag
- Add client-side handler to clear auto-assigned data when switching to manual picking
- Add server-side validation to ensure data consistency
2025-08-07 05:04:25 +05:30
Diptanil Saha
f4f1fdedee Merge pull request #49025 from frappe/mergify/bp/version-15-hotfix/pr-49023
fix: NoneType error on applying presentation_currency filter on financial statements and trial balance report (backport #49023)
2025-08-07 02:27:43 +05:30
diptanilsaha
24ca7bb64f fix: nonetype error on applying presentation_currency filter on financial statements and trial balance report
(cherry picked from commit d7e22de44c)
2025-08-06 20:41:36 +00:00
Rohit Waghchaure
849f646bd2 fix: stock reservation Delivered Qty against the batch 2025-08-06 22:29:45 +05:30
rohitwaghchaure
e19c4c6452 Merge pull request #49019 from frappe/mergify/bp/version-15-hotfix/pr-49010
fix: timeout while submitting purchase receipt (backport #49010)
2025-08-06 22:24:17 +05:30
Rohit Waghchaure
e693ab76fa fix: timeout while submitting purchase receipt
(cherry picked from commit c433943c46)
2025-08-06 14:36:34 +00:00
Frappe PR Bot
6b38654542 chore(release): Bumped to Version 15.73.1
## [15.73.1](https://github.com/frappe/erpnext/compare/v15.73.0...v15.73.1) (2025-08-06)

### Bug Fixes

* fetch revaluated asset value for all the assets ([5224b66](5224b6677d))
2025-08-06 12:23:54 +00:00
Asmita Hase
935b8cfcf7 Merge pull request #49016 from frappe/version-15-hotfix 2025-08-06 17:52:33 +05:30
Khushi Rawat
639c75312d Merge pull request #49013 from frappe/mergify/bp/version-15-hotfix/pr-49011
fix: fetch revaluated asset value for fixed asset register (backport #49011)
2025-08-06 17:36:09 +05:30
khushi8112
e1121d1c68 chore: format code
(cherry picked from commit a33bcb47b3)
2025-08-06 11:44:55 +00:00
khushi8112
5224b6677d fix: fetch revaluated asset value for all the assets
(cherry picked from commit 67ec4fa477)
2025-08-06 11:44:55 +00:00
Asmita Hase
ad3d6a7c91 Merge pull request #49006 from frappe/mergify/bp/version-15-hotfix/pr-49003 2025-08-06 12:14:59 +05:30
Asmita Hase
2d420ed661 chore: removed uncessary comment
(cherry picked from commit b4f831a931)
2025-08-06 06:16:55 +00:00
Asmita Hase
4cc9061990 chore: add account type to employee advance account in standard chart of accounts
(cherry picked from commit a273147b6e)
2025-08-06 06:16:54 +00:00
Asmita Hase
5266690cd8 refactor: get advance payment doctypes from hooks
(cherry picked from commit 2cb2e05b19)
2025-08-06 06:16:54 +00:00
ruthra kumar
373a17e3de Merge pull request #49002 from ruthra-kumar/fix_linter_issue
chore: resolve linting issue
2025-08-06 09:57:40 +05:30
ruthra kumar
2af2002431 chore: resolve linting issue 2025-08-06 09:56:39 +05:30
Frappe PR Bot
5b4093069c chore(release): Bumped to Version 15.73.0
# [15.73.0](https://github.com/frappe/erpnext/compare/v15.72.3...v15.73.0) (2025-08-06)

### Bug Fixes

* account currency validation to exclude cancelled entries ([4ce4d34](4ce4d345e7))
* **accounts:** allow default bank account per company ([8cd90de](8cd90de70b))
* add doctype fieldname in condition ([3603cdf](3603cdf457))
* add missing parentheses ([78857cd](78857cd798))
* change modified timestamp so migrations work ([f8ea431](f8ea431551))
* do not recalculate depreciation on sale invoice cancellation for fully depreciated asset ([db41b14](db41b14317))
* do not split round off when there is a cost center allocation ([e36e502](e36e5027d7))
* enable allow_on_submit for accounting dimensions in allowed doctypes ([e22f93f](e22f93f1fb))
* failing subcontracting patch ([2f4a9f2](2f4a9f283d))
* failing subcontracting patch (backport [#48940](https://github.com/frappe/erpnext/issues/48940)) ([#48961](https://github.com/frappe/erpnext/issues/48961)) ([5a984de](5a984de697))
* include child doctypes in allow_on_submit patch for accounting dimensions ([ad56177](ad56177234))
* include child doctypes in repostable accounting types ([56dca02](56dca02cab))
* include Sales Invoice in SABB validation for packed items ([d862a74](d862a742b0))
* multiple fixes for advance payment accounting (backport [#48341](https://github.com/frappe/erpnext/issues/48341)) ([#48896](https://github.com/frappe/erpnext/issues/48896)) ([cb0addc](cb0addc122))
* payment ledger voucher seperator row currencies ([5b0486c](5b0486ca26))
* permission error on tests ([6f12029](6f12029477))
* prevent negative values in BOM fields ([#48520](https://github.com/frappe/erpnext/issues/48520), [#48662](https://github.com/frappe/erpnext/issues/48662)) (backport [#48696](https://github.com/frappe/erpnext/issues/48696)) ([#48897](https://github.com/frappe/erpnext/issues/48897)) ([5de5a8b](5de5a8bfd5))
* **process statement of accounts:** make date fields mandatory ([3e8deee](3e8deeed07))
* provide company for outstanding record. ([dc4b236](dc4b236951))
* provide missing `company` in report records that require reference to `Company:company:default_currency` ([070190d](070190d07b))
* remove api call to set default payments ([d9c1ef0](d9c1ef0926))
* server error on opportunity summary by sales stage report ([652589f](652589f636))
* set use_serial_batch_fields when creating PR from PO ([0207b82](0207b82f82))
* submit depreciation schedule only for submitted asset ([9d8cb2f](9d8cb2f57c))
* **tax withholding details:** avoid voucher duplication ([cee9f20](cee9f200ad))
* use checkout@v2 instead of v4 ([c9d69d9](c9d69d9629))
* Use correct Attachments folder in code list import ([dc7ac35](dc7ac3550e))
* use maintenance_status filter for indicators ([eec327c](eec327c02b))
* validate if journal entry linked to schedule is in draft ([37eaa07](37eaa07192))

### Features

* add 'Manufacture' section to project dashboard and show linked Work Orders ([83e9842](83e9842dd3))
* add non-negative constraint to batch size and sub operation time fields (backport [#48948](https://github.com/frappe/erpnext/issues/48948)) ([#48991](https://github.com/frappe/erpnext/issues/48991)) ([964f927](964f9275dc))
* Add non-negative constraint to completed qty fields in job card and time log (backport [#48946](https://github.com/frappe/erpnext/issues/48946)) ([#48989](https://github.com/frappe/erpnext/issues/48989)) ([84e91e0](84e91e0c7c))
* add show_amount_in_company_currency in gl report ([b964b12](b964b122ed))

### Performance Improvements

* process auto bank reconciliation in batches ([19a8dde](19a8ddef86))
* process_gl_map causing performance issues in the reposting ([a96fa55](a96fa55704))

### Reverts

* Revert "fix: set proper currency format" ([0355006](03550066a7))
2025-08-06 02:37:49 +00:00
ruthra kumar
53fef46f9a Merge pull request #48979 from frappe/version-15-hotfix
chore: release v15
2025-08-06 08:06:33 +05:30
ruthra kumar
1070322695 Merge branch 'version-15' into version-15-hotfix 2025-08-05 21:41:58 +05:30
ruthra kumar
3ea6278eb9 Merge pull request #48997 from frappe/mergify/bp/version-15-hotfix/pr-48901
fix: do not split round off when there is a cost center allocation (backport #48901)
2025-08-05 20:46:12 +05:30
ravibharathi656
e822a74479 test: add test for cost center allocation commercial rounding
(cherry picked from commit dd24cce509)

# Conflicts:
#	erpnext/accounts/doctype/cost_center_allocation/test_cost_center_allocation.py
2025-08-05 20:29:25 +05:30
venkat102
e36e5027d7 fix: do not split round off when there is a cost center allocation
(cherry picked from commit f0df41d521)
2025-08-05 14:47:51 +00:00
ruthra kumar
f97e29058c Merge pull request #48993 from frappe/mergify/bp/version-15-hotfix/pr-48947
fix(process statement of accounts): make date fields mandatory (backport #48947)
2025-08-05 17:08:55 +05:30
mergify[bot]
964f9275dc feat: add non-negative constraint to batch size and sub operation time fields (backport #48948) (#48991)
* feat: add non-negative constraint to batch size and sub operation time fields

(cherry picked from commit f4722d3b24)

# Conflicts:
#	erpnext/manufacturing/doctype/operation/operation.json
#	erpnext/manufacturing/doctype/sub_operation/sub_operation.json

* chore: resolve conflicts

* chore: resolve conflicts

* chore: resolve conflicts

---------

Co-authored-by: KerollesFathy <kerolles.f@outlook.com>
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-08-05 11:19:46 +00:00
Mihir Kandoi
f3895e9dc9 Merge pull request #48992 from frappe/mergify/bp/version-15-hotfix/pr-48949
feat: add Manufacture section to project dashboard to show linked Work Orders (backport #48949)
2025-08-05 16:48:33 +05:30
ravibharathi656
3e8deeed07 fix(process statement of accounts): make date fields mandatory
(cherry picked from commit 23bc180d98)
2025-08-05 11:06:47 +00:00
mergify[bot]
84e91e0c7c feat: Add non-negative constraint to completed qty fields in job card and time log (backport #48946) (#48989)
* feat: Add non-negative constraint to completed qty fields in job card and time log

(cherry picked from commit c30665fda7)

# Conflicts:
#	erpnext/manufacturing/doctype/job_card/job_card.json
#	erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json

* chore: resolve conflicts

* chore: resolve conflicts

---------

Co-authored-by: KerollesFathy <kerolles.f@outlook.com>
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-08-05 11:06:43 +00:00
KerollesFathy
83e9842dd3 feat: add 'Manufacture' section to project dashboard and show linked Work Orders
(cherry picked from commit 2729d7521d)
2025-08-05 10:59:44 +00:00
Khushi Rawat
3760ff8a7a Merge pull request #48977 from frappe/mergify/bp/version-15-hotfix/pr-48968
fix: validate asset before submitting depreciation schedule (backport #48968)
2025-08-05 16:28:03 +05:30
Khushi Rawat
ddecce400a Merge pull request #48987 from frappe/mergify/bp/version-15-hotfix/pr-48929
chore: add translation function on remarks in asset depreciation entry  (backport #48929)
2025-08-05 16:27:47 +05:30
ruthra kumar
6367bd9561 Merge pull request #48985 from frappe/mergify/bp/version-15-hotfix/pr-48798
feat: add show_amount_in_company_currency in gl report (backport #48798)
2025-08-05 16:26:37 +05:30
ruthra kumar
104569318e Merge pull request #48982 from frappe/mergify/bp/version-15-hotfix/pr-48909
fix(tax withholding details): avoid voucher duplication (backport #48909)
2025-08-05 16:25:48 +05:30
Khushi Rawat
4a8465df90 chore: resolved conflicts 2025-08-05 16:05:54 +05:30
Khushi Rawat
78857cd798 fix: add missing parentheses
(cherry picked from commit a60db40fd2)
2025-08-05 10:26:31 +00:00
Ernesto Ruiz
2c9ee7ae14 chore: add translation function on remark in setup_journal_entry_metadata in depreciation.py
(cherry picked from commit 803180d5de)

# Conflicts:
#	erpnext/assets/doctype/asset/depreciation.py
2025-08-05 10:26:31 +00:00
Ernesto Ruiz
4a5e0b181f chore: add translation function on remarks in make_journal_entry in asset.py
(cherry picked from commit 119904e44f)
2025-08-05 10:26:31 +00:00
Khushi Rawat
35f826c499 chore: remove duplicate code 2025-08-05 15:54:11 +05:30
Diptanil Saha
b565d4f0a8 Merge pull request #48983 from diptanilsaha/pos_grand_total_default_mop
refactor(pos): disable grand total to default mode of payment
2025-08-05 15:24:32 +05:30
l0gesh29
b964b122ed feat: add show_amount_in_company_currency in gl report
(cherry picked from commit 468e5e9b2e)
2025-08-05 09:52:53 +00:00
ravibharathi656
cee9f200ad fix(tax withholding details): avoid voucher duplication
(cherry picked from commit 8837016243)
2025-08-05 09:46:51 +00:00
ruthra kumar
214f15e700 Merge pull request #48972 from frappe/mergify/bp/version-15-hotfix/pr-48718
refactor: process subscriptions in batch wise (backport #48718)
2025-08-05 15:13:00 +05:30
ruthra kumar
0341941d3f Merge pull request #48973 from frappe/mergify/bp/version-15-hotfix/pr-48774
perf: process auto bank reconciliation in batches (backport #48774)
2025-08-05 15:12:46 +05:30
diptanilsaha
8d1b599d5f refactor(pos): disable grand total to default mode of payment 2025-08-05 15:09:55 +05:30
Khushi Rawat
4022fcb0d9 Merge pull request #48976 from frappe/mergify/bp/version-15-hotfix/pr-48974
fix: use maintenance_status filter for indicators (backport #48974)
2025-08-05 15:07:50 +05:30
Khushi Rawat
4f14651a42 chore: resolved conflicts 2025-08-05 15:06:57 +05:30
khushi8112
497247d89a chore: fetch docstatus to validate
(cherry picked from commit d6fb99916e)
2025-08-05 09:32:29 +00:00
khushi8112
137d2d4044 chore: add mistakenly removed test records
(cherry picked from commit f5a71c6b88)
2025-08-05 09:32:28 +00:00
khushi8112
37eaa07192 fix: validate if journal entry linked to schedule is in draft
(cherry picked from commit d5edca2022)
2025-08-05 09:32:28 +00:00
khushi8112
9d8cb2f57c fix: submit depreciation schedule only for submitted asset
(cherry picked from commit a4628c2024)

# Conflicts:
#	erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
2025-08-05 09:32:28 +00:00
khushi8112
eec327c02b fix: use maintenance_status filter for indicators
(cherry picked from commit 1b674a1051)
2025-08-05 09:32:22 +00:00
Diptanil Saha
093c94aa7c Merge pull request #48965 from frappe/mergify/bp/version-15-hotfix/pr-48964
fix: remove api call to set default payments (backport #48964)
2025-08-05 14:49:37 +05:30
ravibharathi656
19a8ddef86 perf: process auto bank reconciliation in batches
(cherry picked from commit 657de2cc7e)
2025-08-05 09:08:46 +00:00
ravibharathi656
0fdd944418 refactor: process subscriptions in batch wise
(cherry picked from commit 283d69c0bd)
2025-08-05 08:58:22 +00:00
ruthra kumar
f997393b0e Merge pull request #48971 from frappe/mergify/bp/version-15-hotfix/pr-48861
chore: correct description for `consider_party_ledger_amount` in Tax Withholding Category (backport #48861)
2025-08-05 14:25:46 +05:30
ljain112
0d02d7086c chore: correct description for consider_party_ledger_amount in Tax Withholding Category
(cherry picked from commit f619bca2d6)

# Conflicts:
#	erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
2025-08-05 14:25:23 +05:30
Mihir Kandoi
913bde0dfe Merge pull request #48967 from frappe/mergify/bp/version-15-hotfix/pr-48693
fix: Use correct Attachments folder in code list import (backport #48693)
2025-08-05 14:24:42 +05:30
Mihir Kandoi
21d33cf6b9 Merge pull request #48767 from WHWYIT/fix-issues-48765
Fix: Procurement Tracker - No permission to read Employee #48765
2025-08-05 14:20:33 +05:30
Corentin Forler
dc7ac3550e fix: Use correct Attachments folder in code list import
(cherry picked from commit bc2cb1737a)
2025-08-05 08:34:39 +00:00
Diptanil Saha
e8ba2b1576 chore: resolve conflict 2025-08-05 13:24:49 +05:30
diptanilsaha
d9c1ef0926 fix: remove api call to set default payments
(cherry picked from commit 871b8473fa)

# Conflicts:
#	erpnext/public/js/controllers/taxes_and_totals.js
2025-08-05 07:46:37 +00:00
ruthra kumar
0061bde950 Merge pull request #48962 from frappe/mergify/bp/version-15-hotfix/pr-48860
fix: add doctype fieldname in condition (backport #48860)
2025-08-05 12:17:56 +05:30
mergify[bot]
5a984de697 fix: failing subcontracting patch (backport #48940) (#48961)
* fix: failing subcontracting patch

(cherry picked from commit 14b47e81ce)

# Conflicts:
#	erpnext/patches.txt

* chore: resolve conflicts

---------

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-08-05 06:37:20 +00:00
l0gesh29
3603cdf457 fix: add doctype fieldname in condition
(cherry picked from commit e2d63e4c32)
2025-08-05 06:32:41 +00:00
ruthra kumar
a74b3e3602 Merge pull request #48939 from frappe/mergify/bp/version-15-hotfix/pr-48575
feat(payment gateway account): add company (backport #48575)
2025-08-05 10:43:12 +05:30
Ravibharathi
8259a748f6 Merge pull request #48575 from aerele/company-payment-gateway
feat(payment gateway account): add company

(cherry picked from commit 02380c3eab)
2025-08-05 10:12:39 +05:30
ruthra kumar
59c6e8f233 Merge pull request #48953 from frappe/mergify/bp/version-15-hotfix/pr-48951
chore: added now as default value for the posting time (backport #48951)
2025-08-05 10:08:55 +05:30
Rohit Waghchaure
dfa35363b9 chore: added now as default value for the posting time
(cherry picked from commit b3cebd87c8)

# Conflicts:
#	erpnext/accounts/doctype/pos_invoice/pos_invoice.json
#	erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
#	erpnext/stock/doctype/delivery_note/delivery_note.json
#	erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.json
2025-08-05 09:44:21 +05:30
mergify[bot]
bab2e86c01 chore: remove wrongly configured 'pos*' assignment from CODEOWNERS (backport #48954) (#48955)
chore: remove wrongly configured 'pos*' assignment from CODEOWNERS (#48954)

(cherry picked from commit cc26d5da14)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-08-05 00:10:09 +05:30
ruthra kumar
fc462d4526 Merge pull request #48937 from frappe/mergify/bp/version-15-hotfix/pr-48926
fix: provide missing `company` in report records that require reference to `Company:company:default_currency` (backport #48926)
2025-08-04 11:02:53 +05:30
Devin Slauenwhite
5b0486ca26 fix: payment ledger voucher seperator row currencies
(cherry picked from commit c03f1c25cf)
2025-08-04 05:00:08 +00:00
Devin Slauenwhite
dc4b236951 fix: provide company for outstanding record.
(cherry picked from commit 97959dbe75)
2025-08-04 05:00:08 +00:00
Devin Slauenwhite
070190d07b fix: provide missing company in report records that require reference to Company:company:default_currency
(cherry picked from commit 7f3905185c)
2025-08-04 05:00:08 +00:00
Devin Slauenwhite
03550066a7 Revert "fix: set proper currency format"
This reverts PR https://github.com/frappe/erpnext/pull/42458
This reverts commit 2533808f1e.

(cherry picked from commit 316470eee4)
2025-08-04 05:00:07 +00:00
ruthra kumar
b93cfc5d83 Merge pull request #48936 from frappe/mergify/bp/version-15-hotfix/pr-48136
fix(accounts):enable allow_on_submit for accounting dimensions in repost settings allowed doctypes (backport #48136)
2025-08-04 09:34:13 +05:30
ravibharathi656
ad56177234 fix: include child doctypes in allow_on_submit patch for accounting dimensions
(cherry picked from commit 1e37fd8991)
2025-08-04 09:14:13 +05:30
ravibharathi656
e22f93f1fb fix: enable allow_on_submit for accounting dimensions in allowed doctypes
(cherry picked from commit 55e79c4dfd)
2025-08-04 03:35:35 +00:00
ravibharathi656
56dca02cab fix: include child doctypes in repostable accounting types
(cherry picked from commit fbd8fd7d22)
2025-08-04 03:35:34 +00:00
Mihir Kandoi
c7db277aa8 Merge pull request #48928 from frappe/mergify/bp/version-15-hotfix/pr-48748
fix: account currency validation to exclude cancelled entries (backport #48748)
2025-08-02 22:34:05 +05:30
Dev Dusija
4ce4d345e7 fix: account currency validation to exclude cancelled entries
(cherry picked from commit c9c45fe89f)
2025-08-02 16:48:31 +00:00
Mihir Kandoi
f714888d48 Merge pull request #48924 from frappe/mergify/bp/version-15-hotfix/pr-48915
fix: set use_serial_batch_fields when creating PR from PO (backport #48915)
2025-08-02 20:57:46 +05:30
Kavin
0207b82f82 fix: set use_serial_batch_fields when creating PR from PO
(cherry picked from commit a384c96617)
2025-08-02 15:12:26 +00:00
rohitwaghchaure
7f1dbeee8b Merge pull request #48914 from rohitwaghchaure/fixed-support-45378
perf: process_gl_map causing performance issues in the reposting
2025-08-02 19:01:40 +05:30
Rohit Waghchaure
a96fa55704 perf: process_gl_map causing performance issues in the reposting 2025-08-02 18:44:32 +05:30
Mihir Kandoi
4488b27fe3 Merge pull request #48910 from frappe/mergify/bp/version-15-hotfix/pr-48908
fix: include Sales Invoice in SABB validation for packed items (backport #48908)
2025-08-01 17:34:59 +05:30
Mihir Kandoi
d862a742b0 fix: include Sales Invoice in SABB validation for packed items
(cherry picked from commit 2ce297aff8)
2025-08-01 11:50:21 +00:00
mergify[bot]
cb0addc122 fix: multiple fixes for advance payment accounting (backport #48341) (#48896)
* fix: multiple fixes for advance payment accounting

(cherry picked from commit e70caedddc)

# Conflicts:
#	erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
#	erpnext/accounts/doctype/payment_entry/payment_entry.py
#	erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
#	erpnext/accounts/utils.py
#	erpnext/controllers/accounts_controller.py
#	erpnext/patches/v15_0/create_advance_payment_ledger_records.py

* chore: resolve conflicts

* fix: do not execute patch if no advance doctypes

---------

Co-authored-by: Lakshit Jain <108322669+ljain112@users.noreply.github.com>
Co-authored-by: ljain112 <ljain112@gmail.com>
2025-08-01 15:30:30 +05:30
mergify[bot]
5de5a8bfd5 fix: prevent negative values in BOM fields (#48520, #48662) (backport #48696) (#48897)
* fix: prevent negative values in BOM fields (#48520, #48662) (#48696)

* fix: prevent negative values in BOM fields (#48520, #48662)

* fix: applied non_negative validation using Desk UI for BOM fields

(cherry picked from commit 3a80e116e8)

# Conflicts:
#	erpnext/manufacturing/doctype/bom_operation/bom_operation.json
#	erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.json

* chore: resolve conflicts

* chore: resolve conflicts

---------

Co-authored-by: Vishist16 <101823906+Vishist16@users.noreply.github.com>
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-07-31 15:42:23 +00:00
Mihir Kandoi
5291c66ea1 Merge pull request #48888 from frappe/mergify/bp/version-15-hotfix/pr-48887
fix: failing subcontracting patch (backport #48887)
2025-07-31 16:15:15 +05:30
Mihir Kandoi
ed927a2147 chore: add date so patch can rerun 2025-07-31 16:00:35 +05:30
Mihir Kandoi
2f4a9f283d fix: failing subcontracting patch
(cherry picked from commit bb43419944)
2025-07-31 10:10:40 +00:00
Mihir Kandoi
79bfcbf424 Merge pull request #48885 from mihir-kandoi/version-15-hotfix
fix: permission error on tests
2025-07-31 14:52:34 +05:30
Mihir Kandoi
c9d69d9629 fix: use checkout@v2 instead of v4 2025-07-31 14:19:44 +05:30
Mihir Kandoi
6f12029477 fix: permission error on tests 2025-07-31 14:04:02 +05:30
mergify[bot]
7bb127de63 Merge pull request #48876 from frappe/mergify/bp/version-15-hotfix/pr-48873
fix: return conversion factor of variant and not template (backport #48873)
2025-07-31 07:03:15 +00:00
Diptanil Saha
87de70f4fd Merge pull request #48877 from frappe/mergify/bp/version-15-hotfix/pr-48619
fix(accounts): allow default bank account per company (backport #48619)
2025-07-31 12:21:04 +05:30
Khushi Rawat
782fecca46 Merge pull request #48857 from khushi8112/asset-depreciation-on-cancel-of-sales-invoice
fix: do not recalculate depreciation on sale invoice cancellation for fully depreciated asset
2025-07-31 12:11:02 +05:30
Nikhil Kothari
8cd90de70b fix(accounts): allow default bank account per company
(cherry picked from commit 982550b92c)
2025-07-31 06:34:31 +00:00
Diptanil Saha
0b9a8ee67c Merge pull request #48859 from frappe/mergify/bp/version-15-hotfix/pr-48858
fix: server error on opportunity summary by sales stage report (backport #48858)
2025-07-30 16:04:47 +05:30
diptanilsaha
652589f636 fix: server error on opportunity summary by sales stage report
(cherry picked from commit 830b3ba1e5)
2025-07-30 10:20:05 +00:00
khushi8112
106f7ea112 test: test asset status after sales invoice creation and cancellation 2025-07-30 13:51:34 +05:30
khushi8112
db41b14317 fix: do not recalculate depreciation on sale invoice cancellation for fully depreciated asset 2025-07-30 13:50:32 +05:30
Mihir Kandoi
609191c3a5 Merge pull request #48852 from frappe/mergify/bp/version-15-hotfix/pr-48851 2025-07-29 22:37:58 +05:30
Mihir Kandoi
7489c9159d chore: resolve conflicts 2025-07-29 22:22:25 +05:30
Mihir Kandoi
b48619078d Update CODEOWNERS
(cherry picked from commit b9b3302b69)

# Conflicts:
#	CODEOWNERS
2025-07-29 16:49:03 +00:00
Diptanil Saha
523007588d Merge pull request #48850 from frappe/mergify/bp/version-15-hotfix/pr-48839
fix: change modified timestamp so migrations work (backport #48839)
2025-07-29 21:18:48 +05:30
Diptanil Saha
184cabdcb0 chore: resolve conflict 2025-07-29 21:02:04 +05:30
Ayush Chaudhari
f8ea431551 fix: change modified timestamp so migrations work
(cherry picked from commit c18d565d3e)

# Conflicts:
#	erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.json
2025-07-29 15:30:28 +00:00
Liuyang
284e45011e Fix: Procurement Tracker - No permission to read Employee #48765 2025-07-24 16:53:07 +08:00
220 changed files with 4210 additions and 951 deletions

View File

@@ -1,7 +1,6 @@
# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
name: Skipped Patch Test
permissions: none
on:
pull_request:
@@ -12,6 +11,9 @@ on:
- "**.html"
- "**.csv"
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest

View File

@@ -1,7 +1,6 @@
# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
name: Skipped Tests
permissions: {}
on:
pull_request:
@@ -11,6 +10,9 @@ on:
- "**.md"
- "**.html"
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest

View File

@@ -3,22 +3,21 @@
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
erpnext/accounts/ @deepeshgarg007 @ruthra-kumar
erpnext/assets/ @khushi8112 @deepeshgarg007
erpnext/regional @deepeshgarg007 @ruthra-kumar
erpnext/selling @deepeshgarg007 @ruthra-kumar
erpnext/support/ @deepeshgarg007
pos*
erpnext/accounts/ @ruthra-kumar
erpnext/assets/ @khushi8112
erpnext/regional @ruthra-kumar
erpnext/selling @ruthra-kumar
erpnext/support/ @ruthra-kumar
erpnext/buying/ @rohitwaghchaure
erpnext/buying/ @rohitwaghchaure @mihir-kandoi
erpnext/maintenance/ @rohitwaghchaure
erpnext/manufacturing/ @rohitwaghchaure
erpnext/manufacturing/ @rohitwaghchaure @mihir-kandoi
erpnext/quality_management/ @rohitwaghchaure
erpnext/stock/ @rohitwaghchaure
erpnext/subcontracting @rohitwaghchaure
erpnext/stock/ @rohitwaghchaure @mihir-kandoi
erpnext/subcontracting @mihir-kandoi
erpnext/controllers/ @deepeshgarg007 @rohitwaghchaure
erpnext/patches/ @deepeshgarg007
erpnext/controllers/ @ruthra-kumar @rohitwaghchaure @mihir-kandoi
erpnext/patches/ @ruthra-kumar
.github/ @deepeshgarg007
.github/ @ruthra-kumar
pyproject.toml @akhilnarang

View File

@@ -4,7 +4,7 @@ import inspect
import frappe
from frappe.utils.user import is_website_user
__version__ = "15.72.3"
__version__ = "15.80.0"
def get_default_company(user=None):

View File

@@ -169,7 +169,7 @@ class Account(NestedSet):
if par.root_type:
self.root_type = par.root_type
if self.is_group:
if cint(self.is_group):
db_value = self.get_doc_before_save()
if db_value:
if self.report_type != db_value.report_type:
@@ -212,7 +212,7 @@ class Account(NestedSet):
if doc_before_save and not doc_before_save.parent_account:
throw(_("Root cannot be edited."), RootNotEditable)
if not self.parent_account and not self.is_group:
if not self.parent_account and not cint(self.is_group):
throw(_("The root account {0} must be a group").format(frappe.bold(self.name)))
def validate_root_company_and_sync_account_to_children(self):
@@ -261,7 +261,7 @@ class Account(NestedSet):
if self.check_gle_exists():
throw(_("Account with existing transaction cannot be converted to ledger"))
elif self.is_group:
elif cint(self.is_group):
if self.account_type and not self.flags.exclude_account_type_check:
throw(_("Cannot covert to Group because Account Type is selected."))
elif self.check_if_child_exists():
@@ -304,7 +304,9 @@ class Account(NestedSet):
self.account_currency = frappe.get_cached_value("Company", self.company, "default_currency")
self.currency_explicitly_specified = False
gl_currency = frappe.db.get_value("GL Entry", {"account": self.name}, "account_currency")
gl_currency = frappe.db.get_value(
"GL Entry", {"account": self.name, "is_cancelled": 0}, "account_currency"
)
if gl_currency and self.account_currency != gl_currency:
if frappe.db.get_value("GL Entry", {"account": self.name}):

View File

@@ -252,10 +252,6 @@ frappe.treeview_settings["Account"] = {
root_company,
]);
} else {
const node = treeview.tree.get_selected_node();
if (node.is_root) {
frappe.throw(__("Cannot create root account."));
}
treeview.new_node();
}
},
@@ -274,8 +270,7 @@ frappe.treeview_settings["Account"] = {
].treeview.page.fields_dict.root_company.get_value() ||
frappe.flags.ignore_root_company_validation) &&
node.expandable &&
!node.hide_add &&
!node.is_root
!node.hide_add
);
},
click: function () {

View File

@@ -0,0 +1,817 @@
{
"country_code": "au",
"name": "Australia - Chart of Accounts with Account Numbers",
"tree": {
"Assets": {
"Current Assets": {
"Cash On Hand": {
"Cash On Hand": {
"account_number": "11010",
"account_type": "Cash"
},
"account_number": "110",
"is_group": 1
},
"Cash at Bank": {
"Every Day Bank Account": {
"account_number": "11510",
"account_type": "Bank"
},
"Business Savings Account": {
"account_number": "11520"
},
"Business Term Deposit": {
"account_number": "11530"
},
"account_number": "115",
"is_group": 1
},
"Trade Receivables": {
"Trade Debtors": {
"account_number": "12010",
"account_type": "Receivable"
},
"Provision for Doubtful Debts": {
"account_number": "12020"
},
"Sundry Debtors": {
"account_number": "12030"
},
"Debtor Refund": {
"account_number": "12040"
},
"account_number": "120",
"is_group": 1
},
"Inventory": {
"Stock On Hand": {
"account_number": "13010",
"account_type": "Stock"
},
"WIP - Work In Progress - Manufacturing": {
"account_number": "13020"
},
"account_number": "130",
"is_group": 1
},
"Prepayments": {
"Prepayments": {
"account_number": "14010"
},
"Provisional Tax Paid": {
"account_number": "14020"
},
"account_number": "140",
"is_group": 1
},
"account_number": "11",
"is_group": 1
},
"Non Current Assets": {
"Plant & Equipment": {
"Plant & Equipment": {
"account_number": "16010",
"account_type": "Fixed Asset"
},
"Accumulated Depreciation Plant & Equipment": {
"account_number": "16020",
"account_type": "Accumulated Depreciation"
},
"account_number": "160",
"is_group": 1
},
"Motor Vehicle": {
"Motor Vehicle": {
"account_number": "16110",
"account_type": "Fixed Asset"
},
"Accumulated Depreciation Motor Vehicle": {
"account_number": "16120",
"account_type": "Accumulated Depreciation"
},
"account_number": "161",
"is_group": 1
},
"Office Equipment": {
"Office Furniture & Equipment": {
"account_number": "16210",
"account_type": "Fixed Asset"
},
"Accumulated Depreciation Office Furniture & Equipment": {
"account_number": "16220",
"account_type": "Accumulated Depreciation"
},
"account_number": "162",
"is_group": 1
},
"Computer Equipment": {
"Computer Equipment": {
"account_number": "16310",
"account_type": "Fixed Asset"
},
"Accumulated Depreciation Computer Equipment": {
"account_number": "16320",
"account_type": "Accumulated Depreciation"
},
"account_number": "163",
"is_group": 1
},
"Building": {
"Buildings": {
"account_number": "16410",
"account_type": "Fixed Asset"
},
"Accumulated Depreciation Buildings": {
"account_number": "16420",
"account_type": "Accumulated Depreciation"
},
"CWIP - Construction Work In Progress": {
"account_number": "16430",
"account_type": "Capital Work in Progress"
},
"Accumulated Depreciation - Others": {
"account_number": "16440",
"account_type": "Accumulated Depreciation"
},
"account_number": "164",
"is_group": 1
},
"Related Party": {
"Loan to Party 1": {
"account_number": "17010"
},
"account_number": "170",
"is_group": 1
},
"Investments & Unlisted Entities": {
"Investment - Entity 1": {
"account_number": "17510"
},
"account_number": "175",
"is_group": 1
},
"Intagible Assets": {
"Goodwill": {
"account_number": "18010"
},
"Opening Balance Temporary ": {
"account_number": "18090",
"account_type": "Temporary"
},
"account_number": "180",
"is_group": 1
},
"account_number": "16",
"is_group": 1
},
"account_number": "1",
"root_type": "Asset"
},
"Liabilities": {
"Current Liabilities": {
"Trade Payables - Current": {
"Trade Creditors": {
"account_number": "21010",
"account_type": "Payable"
},
"Goods Received Not Invoiced": {
"account_number": "21050",
"account_type": "Stock Received But Not Billed"
},
"Service Received Not Invoiced": {
"account_number": "21060"
},
"Asset Received Not Invoiced": {
"account_number": "21070",
"account_type": "Asset Received But Not Billed"
},
"account_number": "210",
"is_group": 1
},
"Other Payables - Current": {
"Accrued Expenses": {
"account_number": "21510"
},
"Payroll - Wages Clearing": {
"account_number": "21550"
},
"Payroll - Superannuation Deductions": {
"account_number": "21555"
},
"Payroll - Misc Deductions": {
"account_number": "21560"
},
"Payroll - Withholding Tax Payable": {
"account_number": "21565"
},
"account_number": "215",
"is_group": 1
},
"GST": {
"GST Payments to ATO": {
"account_number": "22030"
},
"Provision for PAYG Tax": {
"account_number": "22040"
},
"account_number": "220",
"account_type": "Tax",
"is_group": 1
},
"Interest & Non Bearing Liabilities - Current": {
"Credit Card - VISA": {
"account_number": "22510"
},
"account_number": "225",
"is_group": 1
},
"Bank Overdraft": {
"Bank Overdraft Cash at Bank": {
"account_number": "23010"
},
"account_number": "230",
"is_group": 1
},
"Trade Finance": {
"Trade Finance": {
"account_number": "23510"
},
"account_number": "235",
"is_group": 1
},
"Lease Liabilities": {
"Finance Lease - Current": {
"account_number": "24010"
},
"account_number": "240",
"is_group": 1
},
"Provisions": {
"Provision for Long Service Leave": {
"account_number": "24510"
},
"Provision for Holiday Pay": {
"account_number": "24520"
},
"account_number": "245",
"is_group": 1
},
"account_number": "21",
"is_group": 1
},
"Non Current Liabilities": {
"Trade & Other Payables - Non Current": {
"Loan Account - Party 1": {
"account_number": "25010"
},
"account_number": "250",
"is_group": 1
},
"Interest & Non Bearing Liabilities - Non Current": {
"Non Current Liability - Director Loan": {
"account_number": "25510"
},
"account_number": "255",
"is_group": 1
},
"Bank Loans - Non Current": {
"Bank Loan 1 - Non Current": {
"account_number": "26010"
},
"account_number": "260",
"is_group": 1
},
"Lease Liabilities - Non Current": {
"Finance Lease - Non Current": {
"account_number": "27010"
},
"account_number": "270",
"is_group": 1
},
"Provisions - Non Current": {
"Provision for Long Service Leave": {
"account_number": "27510"
},
"Provision for Holiday Pay": {
"account_number": "27520"
},
"account_number": "275",
"is_group": 1
},
"account_number": "25",
"is_group": 1
},
"account_number": "2",
"root_type": "Liability"
},
"Equity": {
"Equity": {
"Owner's/Shareholder's Equity": {
"Owner's/Shareholders Capital": {
"account_number": "31010",
"account_type": "Equity"
},
"Owner's/Shareholders Drawings": {
"account_number": "31020",
"account_type": "Equity"
},
"account_number": "310",
"is_group": 1
},
"Earnings": {
"Current Year Earnings": {
"account_number": "35010",
"account_type": "Equity"
},
"Retained Earnings": {
"account_number": "35020",
"account_type": "Equity"
},
"account_number": "350",
"is_group": 1
},
"account_number": "31",
"is_group": 1
},
"account_number": "3",
"root_type": "Equity"
},
"Revenue": {
"Revenue": {
"Sales Revenue": {
"Sales Income": {
"account_number": "41010",
"account_type": "Income Account"
},
"Freight Income": {
"account_number": "41020",
"account_type": "Income Account"
},
"Other Income": {
"account_number": "41030",
"account_type": "Income Account"
},
"Service Income": {
"account_number": "41040",
"account_type": "Income Account"
},
"account_number": "410",
"is_group": 1
},
"Other Revenue": {
"Commission Received": {
"account_number": "42010"
},
"Discounts Received": {
"account_number": "42020"
},
"Interest received": {
"account_number": "42030"
},
"Profit/Loss on Sales of Assets": {
"account_number": "42040"
},
"Rent Received": {
"account_number": "42050"
},
"Sundry Income": {
"account_number": "42060"
},
"account_number": "420",
"is_group": 1
},
"account_number": "41",
"is_group": 1
},
"account_number": "4",
"root_type": "Income"
},
"Cost of Goods": {
"Cost of Goods": {
"Cost of Goods Sold": {
"Cost of Goods Sold": {
"account_number": "51010",
"account_type": "Cost of Goods Sold"
},
"Freight Expenses (sales related)": {
"account_number": "51020"
},
"Discounts Given": {
"account_number": "51030"
},
"Subcontracting Charges": {
"account_number": "51040"
},
"account_number": "510",
"is_group": 1
},
"Other COGS": {
"Purchases - Miscellaneous": {
"account_number": "52010"
},
"Duty & Customs Fees": {
"account_number": "52020",
"account_type": "Tax"
},
"Freight Inwards": {
"account_number": "52030",
"account_type": "Chargeable"
},
"Stock Adjustment": {
"account_number": "52040",
"account_type": "Stock Adjustment"
},
"Stock Wirte Off": {
"account_number": "52050",
"account_type": "Stock Adjustment"
},
"Stock Valuation Expenses": {
"account_number": "52060",
"account_type": "Expenses Included In Valuation"
},
"Asset Valuation Expenses": {
"account_number": "52070",
"account_type": "Expenses Included In Asset Valuation"
},
"account_number": "520",
"is_group": 1
},
"account_number": "51",
"is_group": 1
},
"account_number": "5",
"root_type": "Expense"
},
"Expenses": {
"Fixed Expenses": {
"Payroll & Related Expenses": {
"Salaries & Wages": {
"account_number": "61010"
},
"Superannuation": {
"account_number": "61015"
},
"Staff Amenities - GST Paid": {
"account_number": "61020"
},
"Staff Amenities - GST Free": {
"account_number": "61025"
},
"Staff Recruitment": {
"account_number": "61030"
},
"Staff Training": {
"account_number": "61035"
},
"Fringe Benefits Tax": {
"account_number": "61040"
},
"Payroll Tax": {
"account_number": "61045"
},
"Workers Compensation": {
"account_number": "61050"
},
"Long Service Leave": {
"account_number": "61060"
},
"Mileage Reimbursement": {
"account_number": "61070"
},
"Overtime": {
"account_number": "61080"
},
"Worksafe Insurance": {
"account_number": "61090"
},
"account_number": "610",
"is_group": 1
},
"Depreciation Expenses": {
"Depreciation - Plant & Equipment": {
"account_number": "62010",
"account_type": "Depreciation"
},
"Depreciation - Motor Vehicle": {
"account_number": "62020",
"account_type": "Depreciation"
},
"Depreciation - Office Equipment": {
"account_number": "62030",
"account_type": "Depreciation"
},
"Depreciation - Computer Equipment": {
"account_number": "62040",
"account_type": "Depreciation"
},
"Depreciation - Building": {
"account_number": "62050",
"account_type": "Depreciation"
},
"Depreciation - Others": {
"account_number": "62510",
"account_type": "Depreciation"
},
"account_number": "620",
"is_group": 1
},
"account_number": "61",
"is_group": 1
},
"Accrued Expenses": {
"Accrued Expenses": {
"Accrued Expenses - Salaries & Wages": {
"account_number": "63010"
},
"Accrued Expenses - Interest": {
"account_number": "63020"
},
"account_number": "630",
"is_group": 1
},
"account_number": "63",
"is_group": 1
},
"Operating Expenses": {
"General and Administrative Expenses": {
"Low Value Assets less than $300": {
"account_number": "64010"
},
"Office Supplies": {
"account_number": "64020"
},
"Postage & Courier": {
"account_number": "64025"
},
"Printing & Stationery": {
"account_number": "64030"
},
"Registration Fees / Filing Fees": {
"account_number": "64040"
},
"Travel & Accommodation - Local": {
"account_number": "64050"
},
"Travel & Accommodation - Overseas": {
"account_number": "64060"
},
"Relocation Costs": {
"account_number": "64070"
},
"Hire Charges": {
"account_number": "64080"
},
"Repairs & Maintenance": {
"account_number": "64210"
},
"Cleaning Expenses": {
"account_number": "64215"
},
"Uniforms": {
"account_number": "64220"
},
"Security": {
"account_number": "64225"
},
"Subscriptions & Licences": {
"account_number": "64510"
},
"Software Expenses": {
"account_number": "64515"
},
"Marketing Expenses": {
"account_number": "64520"
},
"Advertising Expenses": {
"account_number": "64525"
},
"Website Hosting & Domain Expenses": {
"account_number": "64530"
},
"Computer Repairs / Supplies": {
"account_number": "64540"
},
"Conferences": {
"account_number": "64550"
},
"Consultancy /Contract Services": {
"account_number": "64560"
},
"Training Services": {
"account_number": "64570"
},
"Workshop Supplies": {
"account_number": "64580"
},
"Consumables": {
"account_number": "64585"
},
"Entertainment Expenses - Deductible": {
"account_number": "64810"
},
"Entertainment Expenses - Non Deductible": {
"account_number": "64820"
},
"Amortisation Of Goodwill": {
"account_number": "64910"
},
"General / Miscellaneous Expenses": {
"account_number": "64915",
"account_type": "Chargeable"
},
"Donations": {
"account_number": "64920"
},
"Client Gifts": {
"account_number": "64930"
},
"Employee Gifts": {
"account_number": "64935"
},
"account_number": "640",
"is_group": 1
},
"Occupancy Expenses": {
"Rental Expenses": {
"account_number": "65010"
},
"Property Insurance": {
"account_number": "65020"
},
"Electricity Expenses": {
"account_number": "65030"
},
"Water Rates": {
"account_number": "65040"
},
"Gas Expenses": {
"account_number": "65050"
},
"Property Taxes": {
"account_number": "65060"
},
"Rates": {
"account_number": "65070"
},
"account_number": "650",
"is_group": 1
},
"Communication & Vehicle Expenses": {
"Internet Expenses": {
"account_number": "66010"
},
"Mobile Telephone": {
"account_number": "66020"
},
"Telephone Expenses": {
"account_number": "66030"
},
"Motor Vehicle - Fuel Expenses": {
"account_number": "66040"
},
"Motor Vehicle - Parking & Tolls": {
"account_number": "66050"
},
"Motor Vehicle - Registration & Insurance": {
"account_number": "66060"
},
"Motor Vehicle - Service & Repairs": {
"account_number": "66070"
},
"Taxi": {
"account_number": "66080"
},
"account_number": "660",
"is_group": 1
},
"account_number": "64",
"is_group": 1
},
"Non-Operating Expenses": {
"Finance Costs": {
"Interest - Bank Loans": {
"account_number": "67010"
},
"Interest - Finance Leases": {
"account_number": "67020"
},
"Interest - Other Loans": {
"account_number": "67025"
},
"Insurance": {
"account_number": "67030"
},
"Bank Charges": {
"account_number": "67050"
},
"Rounding off": {
"account_number": "67055",
"account_type": "Round Off"
},
"Audit Fees": {
"account_number": "67060"
},
"Accounting Fees": {
"account_number": "67070"
},
"Legal Fees": {
"account_number": "67080"
},
"Management Fees": {
"account_number": "67090"
},
"account_number": "670",
"is_group": 1
},
"Other Costs": {
"Doubtful Debts": {
"account_number": "67510"
},
"Fines": {
"account_number": "67520"
},
"Debt Collection": {
"account_number": "67530"
},
"Bad Debts": {
"account_number": "67540"
},
"account_number": "675",
"is_group": 1
},
"account_number": "67",
"is_group": 1
},
"Variable Expenses": {
"Variable Expenses": {
"Bonus & Commissions Paid": {
"account_number": "68010"
},
"Bonus & Commissions To be Paid": {
"account_number": "68020"
},
"Warranty Claims": {
"account_number": "68030"
},
"account_number": "680",
"is_group": 1
},
"account_number": "68",
"is_group": 1
},
"account_number": "6",
"root_type": "Expense"
},
"Other Income": {
"Other Income": {
"Interest Income": {
"Interest Income": {
"account_number": "71010"
},
"account_number": "710",
"is_group": 1
},
"Asset Disposal Income": {
"Gain on Asset Disposal": {
"account_number": "73010"
},
"account_number": "730",
"is_group": 1
},
"account_number": "71",
"is_group": 1
},
"account_number": "7",
"root_type": "Income"
},
"Other Expenses": {
"Other Expenses": {
"Income Tax Expenses": {
"Income Tax Expenses": {
"account_number": "81010"
},
"account_number": "810",
"is_group": 1
},
"Foreign Exchange Gain/Loss": {
"Exchange Loss/Gain - Realized": {
"account_number": "82010"
},
"account_number": "820",
"is_group": 1
},
"Asset Disposal Expenses": {
"Loss on Asset Disposal": {
"account_number": "83010"
},
"account_number": "830",
"is_group": 1
},
"account_number": "81",
"is_group": 1
},
"account_number": "8",
"root_type": "Expense"
}
}
}

View File

@@ -13,7 +13,7 @@ def get():
_("Bank Accounts"): {"account_type": "Bank", "is_group": 1},
_("Cash In Hand"): {_("Cash"): {"account_type": "Cash"}, "account_type": "Cash"},
_("Loans and Advances (Assets)"): {
_("Employee Advances"): {},
_("Employee Advances"): {"account_type": "Payable"},
},
_("Securities and Deposits"): {_("Earnest Money"): {}},
_("Stock Assets"): {

View File

@@ -20,7 +20,7 @@ def get():
"account_number": "1100",
},
_("Loans and Advances (Assets)"): {
_("Employee Advances"): {"account_number": "1610"},
_("Employee Advances"): {"account_number": "1610", "account_type": "Payable"},
"account_number": "1600",
},
_("Securities and Deposits"): {

View File

@@ -111,17 +111,15 @@ class AccountingDimension(Document):
def make_dimension_in_accounting_doctypes(doc, doclist=None):
if not doclist:
doclist = get_doctypes_with_dimensions()
doc_count = len(get_accounting_dimensions())
count = 0
repostable_doctypes = get_allowed_types_from_settings()
repostable_doctypes = get_allowed_types_from_settings(child_doc=True)
for doctype in doclist:
if (doc_count + 1) % 2 == 0:
insert_after_field = "dimension_col_break"
else:
insert_after_field = "accounting_dimensions_section"
df = {
"fieldname": doc.fieldname,
"label": doc.label,

View File

@@ -7,6 +7,7 @@
"engine": "InnoDB",
"field_order": [
"accounting_dimension",
"fieldname",
"disabled",
"column_break_2",
"company",
@@ -90,11 +91,17 @@
"fieldname": "apply_restriction_on_values",
"fieldtype": "Check",
"label": "Apply restriction on dimension values"
},
{
"fieldname": "fieldname",
"fieldtype": "Data",
"hidden": 1,
"label": "Fieldname"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2023-06-07 14:59:41.869117",
"modified": "2025-08-08 14:13:22.203011",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension Filter",
@@ -139,8 +146,8 @@
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -17,17 +17,16 @@ class AccountingDimensionFilter(Document):
from frappe.types import DF
from erpnext.accounts.doctype.allowed_dimension.allowed_dimension import AllowedDimension
from erpnext.accounts.doctype.applicable_on_account.applicable_on_account import (
ApplicableOnAccount,
)
from erpnext.accounts.doctype.applicable_on_account.applicable_on_account import ApplicableOnAccount
accounting_dimension: DF.Literal
accounting_dimension: DF.Literal[None]
accounts: DF.Table[ApplicableOnAccount]
allow_or_restrict: DF.Literal["Allow", "Restrict"]
apply_restriction_on_values: DF.Check
company: DF.Link
dimensions: DF.Table[AllowedDimension]
disabled: DF.Check
fieldname: DF.Data | None
# end: auto-generated types
def before_save(self):
@@ -37,6 +36,10 @@ class AccountingDimensionFilter(Document):
self.set("dimensions", [])
def validate(self):
self.fieldname = frappe.db.get_value(
"Accounting Dimension", {"document_type": self.accounting_dimension}, "fieldname"
) or frappe.scrub(self.accounting_dimension) # scrub to handle default accounting dimension
self.validate_applicable_accounts()
def validate_applicable_accounts(self):
@@ -72,7 +75,7 @@ def get_dimension_filter_map():
"""
SELECT
a.applicable_on_account, d.dimension_value, p.accounting_dimension,
p.allow_or_restrict, a.is_mandatory
p.allow_or_restrict, p.fieldname, a.is_mandatory
FROM
`tabApplicable On Account` a,
`tabAccounting Dimension Filter` p
@@ -87,8 +90,6 @@ def get_dimension_filter_map():
dimension_filter_map = {}
for f in filters:
f.fieldname = scrub(f.accounting_dimension)
build_map(
dimension_filter_map,
f.fieldname,

View File

@@ -4,7 +4,7 @@
import frappe
from frappe.model.document import Document
from erpnext.accounts.utils import update_voucher_outstanding
from erpnext.accounts.utils import get_advance_payment_doctypes, update_voucher_outstanding
class AdvancePaymentLedgerEntry(Document):
@@ -29,7 +29,7 @@ class AdvancePaymentLedgerEntry(Document):
def on_update(self):
if (
self.against_voucher_type in ["Purchase Order", "Sales Order"]
self.against_voucher_type in get_advance_payment_doctypes()
and self.flags.update_outstanding == "Yes"
and not frappe.flags.is_reverse_depr_entry
):

View File

@@ -16,6 +16,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"section_break_8",
"rate",
"section_break_9",
@@ -92,6 +93,13 @@
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 1,
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{
"fieldname": "section_break_8",
"fieldtype": "Section Break"

View File

@@ -109,6 +109,7 @@ class BankAccount(Document):
"party_type": self.party_type,
"party": self.party,
"is_company_account": self.is_company_account,
"company": self.company,
"is_default": 1,
"disabled": 0,
},

View File

@@ -137,8 +137,10 @@ def get_payment_entries_for_bank_clearance(
entries = []
condition = ""
pe_condition = ""
if not include_reconciled_entries:
condition = "and (clearance_date IS NULL or clearance_date='0000-00-00')"
pe_condition = "and (pe.clearance_date IS NULL or pe.clearance_date='0000-00-00')"
journal_entries = frappe.db.sql(
f"""
@@ -163,19 +165,20 @@ def get_payment_entries_for_bank_clearance(
payment_entries = frappe.db.sql(
f"""
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no as cheque_number, reference_date as cheque_date,
if(paid_from=%(account)s, paid_amount + total_taxes_and_charges, 0) as credit,
if(paid_from=%(account)s, 0, received_amount + total_taxes_and_charges) as debit,
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
from `tabPayment Entry`
"Payment Entry" as payment_document, pe.name as payment_entry,
pe.reference_no as cheque_number, pe.reference_date as cheque_date,
if(pe.paid_from=%(account)s, pe.paid_amount + if(pe.payment_type = 'Pay' and c.default_currency = pe.paid_from_account_currency, pe.base_total_taxes_and_charges, pe.total_taxes_and_charges) , 0) as credit,
if(pe.paid_from=%(account)s, 0, pe.received_amount + pe.total_taxes_and_charges) as debit,
pe.posting_date, ifnull(pe.party,if(pe.paid_from=%(account)s,pe.paid_to,pe.paid_from)) as against_account, pe.clearance_date,
if(pe.paid_to=%(account)s, pe.paid_to_account_currency, pe.paid_from_account_currency) as account_currency
from `tabPayment Entry` as pe
join `tabCompany` c on c.name = pe.company
where
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
and posting_date >= %(from)s and posting_date <= %(to)s
{condition}
(pe.paid_from=%(account)s or pe.paid_to=%(account)s) and pe.docstatus=1
and pe.posting_date >= %(from)s and pe.posting_date <= %(to)s
{pe_condition}
order by
posting_date ASC, name DESC
pe.posting_date ASC, pe.name DESC
""",
{
"account": account,

View File

@@ -9,7 +9,7 @@ from frappe import _
from frappe.model.document import Document
from frappe.query_builder.custom import ConstantColumn
from frappe.query_builder.functions import Sum
from frappe.utils import cint, flt
from frappe.utils import cint, create_batch, flt
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount
@@ -377,16 +377,17 @@ def auto_reconcile_vouchers(
bank_transactions = get_bank_transactions(bank_account)
if len(bank_transactions) > 10:
frappe.enqueue(
method="erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.start_auto_reconcile",
queue="long",
bank_transactions=bank_transactions,
from_date=from_date,
to_date=to_date,
filter_by_reference_date=filter_by_reference_date,
from_reference_date=from_reference_date,
to_reference_date=to_reference_date,
)
for bank_transaction_batch in create_batch(bank_transactions, 1000):
frappe.enqueue(
method="erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.start_auto_reconcile",
queue="long",
bank_transactions=bank_transaction_batch,
from_date=from_date,
to_date=to_date,
filter_by_reference_date=filter_by_reference_date,
from_reference_date=from_reference_date,
to_reference_date=to_reference_date,
)
frappe.msgprint(_("Auto Reconciliation has started in the background"))
else:
start_auto_reconcile(

View File

@@ -7,6 +7,9 @@ from frappe.utils import nowdate
from erpnext.accounts.doctype.bank_transaction.test_bank_transaction import create_bank_account
IBAN_1 = "DE02000000003716541159"
IBAN_2 = "DE02500105170137075030"
class TestAutoMatchParty(FrappeTestCase):
@classmethod
@@ -22,24 +25,24 @@ class TestAutoMatchParty(FrappeTestCase):
frappe.db.set_single_value("Accounts Settings", "enable_fuzzy_matching", 0)
def test_match_by_account_number(self):
create_supplier_for_match(account_no="000000003716541159")
create_supplier_for_match(account_no=IBAN_1[11:])
doc = create_bank_transaction(
withdrawal=1200,
transaction_id="562213b0ca1bf838dab8f2c6a39bbc3b",
account_no="000000003716541159",
iban="DE02000000003716541159",
account_no=IBAN_1[11:],
iban=IBAN_1,
)
self.assertEqual(doc.party_type, "Supplier")
self.assertEqual(doc.party, "John Doe & Co.")
def test_match_by_iban(self):
create_supplier_for_match(iban="DE02000000003716541159")
create_supplier_for_match(iban=IBAN_1)
doc = create_bank_transaction(
withdrawal=1200,
transaction_id="c5455a224602afaa51592a9d9250600d",
account_no="000000003716541159",
iban="DE02000000003716541159",
account_no=IBAN_1[11:],
iban=IBAN_1,
)
self.assertEqual(doc.party_type, "Supplier")
@@ -51,7 +54,7 @@ class TestAutoMatchParty(FrappeTestCase):
withdrawal=1200,
transaction_id="1f6f661f347ff7b1ea588665f473adb1",
party_name="Ella Jackson",
iban="DE04000000003716545346",
iban=IBAN_2,
)
self.assertEqual(doc.party_type, "Supplier")
self.assertEqual(doc.party, "Jackson Ella W.")

View File

@@ -142,8 +142,10 @@ def validate_expense_against_budget(args, expense_amount=0):
if not frappe.get_all("Budget", limit=1):
return
if args.get("company") and not args.fiscal_year:
if not args.fiscal_year:
args.fiscal_year = get_fiscal_year(args.get("posting_date"), company=args.get("company"))[0]
if args.get("company"):
frappe.flags.exception_approver_role = frappe.get_cached_value(
"Company", args.get("company"), "exception_budget_approver_role"
)

View File

@@ -462,9 +462,8 @@ def unset_existing_data(company):
"Sales Taxes and Charges Template",
"Purchase Taxes and Charges Template",
]:
frappe.db.sql(
f'''delete from `tab{doctype}` where `company`="%s"''' % (company) # nosec
)
dt = frappe.qb.DocType(doctype)
frappe.qb.from_(dt).where(dt.company == company).delete().run()
def set_default_accounts(company):

View File

@@ -4,6 +4,8 @@
import unittest
import frappe
from frappe.query_builder.functions import Sum
from frappe.tests.utils import change_settings
from frappe.utils import add_days, today
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
@@ -190,6 +192,31 @@ class TestCostCenterAllocation(unittest.TestCase):
coa2.cancel()
jv.cancel()
@change_settings("System Settings", {"rounding_method": "Commercial Rounding"})
def test_debit_credit_on_cost_center_allocation_for_commercial_rounding(self):
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
cca = create_cost_center_allocation(
"_Test Company",
"Main Cost Center 1 - _TC",
{"Sub Cost Center 2 - _TC": 50, "Sub Cost Center 3 - _TC": 50},
)
si = create_sales_invoice(rate=145.65, cost_center="Main Cost Center 1 - _TC")
gl_entry = frappe.qb.DocType("GL Entry")
gl_entries = (
frappe.qb.from_(gl_entry)
.select(Sum(gl_entry.credit).as_("cr"), Sum(gl_entry.debit).as_("dr"))
.where(gl_entry.voucher_type == "Sales Invoice")
.where(gl_entry.voucher_no == si.name)
).run(as_dict=1)
self.assertEqual(gl_entries[0].cr, gl_entries[0].dr)
si.cancel()
cca.cancel()
def create_cost_center_allocation(
company,

View File

@@ -11,6 +11,7 @@
-> Resolves dunning automatically
"""
import json
import frappe
@@ -156,40 +157,66 @@ class Dunning(AccountsController):
]
def resolve_dunning(doc, state):
"""
Check if all payments have been made and resolve dunning, if yes. Called
when a Payment Entry is submitted.
"""
for reference in doc.references:
# Consider partial and full payments:
# Submitting full payment: outstanding_amount will be 0
# Submitting 1st partial payment: outstanding_amount will be the pending installment
# Cancelling full payment: outstanding_amount will revert to total amount
# Cancelling last partial payment: outstanding_amount will revert to pending amount
submit_condition = reference.outstanding_amount < reference.total_amount
cancel_condition = reference.outstanding_amount <= reference.total_amount
def update_linked_dunnings(doc, previous_outstanding_amount):
if (
doc.doctype != "Sales Invoice"
or doc.is_return
or previous_outstanding_amount == doc.outstanding_amount
):
return
if reference.reference_doctype == "Sales Invoice" and (
submit_condition if doc.docstatus == 1 else cancel_condition
):
state = "Resolved" if doc.docstatus == 2 else "Unresolved"
dunnings = get_linked_dunnings_as_per_state(reference.reference_name, state)
to_resolve = doc.outstanding_amount < previous_outstanding_amount
state = "Unresolved" if to_resolve else "Resolved"
dunnings = get_linked_dunnings_as_per_state(doc.name, state)
if not dunnings:
return
for dunning in dunnings:
resolve = True
dunning = frappe.get_doc("Dunning", dunning.get("name"))
for overdue_payment in dunning.overdue_payments:
outstanding_inv = frappe.get_value(
"Sales Invoice", overdue_payment.sales_invoice, "outstanding_amount"
)
outstanding_ps = frappe.get_value(
"Payment Schedule", overdue_payment.payment_schedule, "outstanding"
)
resolve = False if (outstanding_ps > 0 and outstanding_inv > 0) else True
dunnings = [frappe.get_doc("Dunning", dunning.name) for dunning in dunnings]
invoices = set()
payment_schedule_ids = set()
dunning.status = "Resolved" if resolve else "Unresolved"
dunning.save()
for dunning in dunnings:
for overdue_payment in dunning.overdue_payments:
invoices.add(overdue_payment.sales_invoice)
if overdue_payment.payment_schedule:
payment_schedule_ids.add(overdue_payment.payment_schedule)
invoice_outstanding_amounts = dict(
frappe.get_all(
"Sales Invoice",
filters={"name": ["in", list(invoices)]},
fields=["name", "outstanding_amount"],
as_list=True,
)
)
ps_outstanding_amounts = (
dict(
frappe.get_all(
"Payment Schedule",
filters={"name": ["in", list(payment_schedule_ids)]},
fields=["name", "outstanding"],
as_list=True,
)
)
if payment_schedule_ids
else {}
)
for dunning in dunnings:
has_outstanding = False
for overdue_payment in dunning.overdue_payments:
invoice_outstanding = invoice_outstanding_amounts[overdue_payment.sales_invoice]
ps_outstanding = ps_outstanding_amounts.get(overdue_payment.payment_schedule, 0)
has_outstanding = invoice_outstanding > 0 and ps_outstanding > 0
if has_outstanding:
break
new_status = "Resolved" if not has_outstanding else "Unresolved"
if dunning.status != new_status:
dunning.status = new_status
dunning.save()
def get_linked_dunnings_as_per_state(sales_invoice, state):

View File

@@ -139,6 +139,64 @@ class TestDunning(FrappeTestCase):
self.assertEqual(sales_invoice.status, "Overdue")
self.assertEqual(dunning.status, "Unresolved")
def test_dunning_resolution_from_credit_note(self):
"""
Test that dunning is resolved when a credit note is issued against the original invoice.
"""
sales_invoice = create_sales_invoice_against_cost_center(
posting_date=add_days(today(), -10), qty=1, rate=100
)
dunning = create_dunning_from_sales_invoice(sales_invoice.name)
dunning.submit()
self.assertEqual(dunning.status, "Unresolved")
credit_note = frappe.copy_doc(sales_invoice)
credit_note.is_return = 1
credit_note.return_against = sales_invoice.name
credit_note.update_outstanding_for_self = 0
for item in credit_note.items:
item.qty = -item.qty
credit_note.save()
credit_note.submit()
dunning.reload()
self.assertEqual(dunning.status, "Resolved")
credit_note.cancel()
dunning.reload()
self.assertEqual(dunning.status, "Unresolved")
def test_dunning_not_affected_by_standalone_credit_note(self):
"""
Test that dunning is NOT resolved when a credit note has update_outstanding_for_self checked.
"""
sales_invoice = create_sales_invoice_against_cost_center(
posting_date=add_days(today(), -10), qty=1, rate=100
)
dunning = create_dunning_from_sales_invoice(sales_invoice.name)
dunning.submit()
self.assertEqual(dunning.status, "Unresolved")
credit_note = frappe.copy_doc(sales_invoice)
credit_note.is_return = 1
credit_note.return_against = sales_invoice.name
credit_note.update_outstanding_for_self = 1
for item in credit_note.items:
item.qty = -item.qty
credit_note.save()
credit_note = frappe.get_doc("Sales Invoice", credit_note.name)
credit_note.submit()
dunning.reload()
self.assertEqual(dunning.status, "Unresolved")
def create_dunning(overdue_days, dunning_type_name=None):
posting_date = add_days(today(), -1 * overdue_days)

View File

@@ -134,7 +134,8 @@ class ExchangeRateRevaluation(Document):
accounts = self.get_accounts_data()
if accounts:
for acc in accounts:
self.append("accounts", acc)
if acc.get("gain_loss"):
self.append("accounts", acc)
@frappe.whitelist()
def get_accounts_data(self):

View File

@@ -131,18 +131,20 @@ class GLEntry(Document):
if not self.is_cancelled and not (self.party_type and self.party):
account_type = frappe.get_cached_value("Account", self.account, "account_type")
if account_type == "Receivable":
frappe.throw(
_("{0} {1}: Customer is required against Receivable account {2}").format(
self.voucher_type, self.voucher_no, self.account
# skipping validation for payroll entry creation in case party is not required
if not frappe.flags.party_not_required_for_receivable_payable:
if account_type == "Receivable":
frappe.throw(
_("{0} {1}: Customer is required against Receivable account {2}").format(
self.voucher_type, self.voucher_no, self.account
)
)
)
elif account_type == "Payable":
frappe.throw(
_("{0} {1}: Supplier is required against Payable account {2}").format(
self.voucher_type, self.voucher_no, self.account
elif account_type == "Payable":
frappe.throw(
_("{0} {1}: Supplier is required against Payable account {2}").format(
self.voucher_type, self.voucher_no, self.account
)
)
)
# Zero value transaction is not allowed
if not (
@@ -311,7 +313,7 @@ def validate_balance_type(account, adv_adj=False):
if balance_must_be:
balance = frappe.db.sql(
"""select sum(debit) - sum(credit)
from `tabGL Entry` where account = %s""",
from `tabGL Entry` where is_cancelled = 0 and account = %s""",
account,
)[0][0]

View File

@@ -542,8 +542,11 @@ class JournalEntry(AccountsController):
def validate_party(self):
for d in self.get("accounts"):
account_type = frappe.get_cached_value("Account", d.account, "account_type")
# skipping validation for payroll entry creation
skip_validation = frappe.flags.party_not_required_for_receivable_payable
if account_type in ["Receivable", "Payable"]:
if not (d.party_type and d.party):
if not (d.party_type and d.party) and not skip_validation:
frappe.throw(
_(
"Row {0}: Party Type and Party is required for Receivable / Payable account {1}"
@@ -552,6 +555,8 @@ class JournalEntry(AccountsController):
elif (
d.party_type
and frappe.db.get_value("Party Type", d.party_type, "account_type") != account_type
and d.party_type
!= "Employee" # making an excpetion for employee since they can be both payable and receivable
):
frappe.throw(
_("Row {0}: Account {1} and Party Type {2} have different account types").format(

View File

@@ -24,6 +24,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"help_section",
"loyalty_program_help"
],
@@ -143,6 +144,12 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
}
],
"modified": "2019-05-26 09:11:46.120251",

View File

@@ -5,6 +5,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.query_builder.functions import Sum
from frappe.utils import flt, today
@@ -45,22 +46,30 @@ def get_loyalty_details(
if not expiry_date:
expiry_date = today()
condition = ""
if company:
condition = " and company=%s " % frappe.db.escape(company)
if not include_expired_entry:
condition += " and expiry_date>='%s' " % expiry_date
LoyaltyPointEntry = frappe.qb.DocType("Loyalty Point Entry")
loyalty_point_details = frappe.db.sql(
f"""select sum(loyalty_points) as loyalty_points,
sum(purchase_amount) as total_spent from `tabLoyalty Point Entry`
where customer=%s and loyalty_program=%s and posting_date <= %s
{condition}
group by customer""",
(customer, loyalty_program, expiry_date),
as_dict=1,
query = (
frappe.qb.from_(LoyaltyPointEntry)
.select(
Sum(LoyaltyPointEntry.loyalty_points).as_("loyalty_points"),
Sum(LoyaltyPointEntry.purchase_amount).as_("total_spent"),
)
.where(
(LoyaltyPointEntry.customer == customer)
& (LoyaltyPointEntry.loyalty_program == loyalty_program)
& (LoyaltyPointEntry.posting_date <= expiry_date)
)
.groupby(LoyaltyPointEntry.customer)
)
if company:
query = query.where(LoyaltyPointEntry.company == company)
if not include_expired_entry:
query = query.where(LoyaltyPointEntry.expiry_date >= expiry_date)
loyalty_point_details = query.run(as_dict=True)
if loyalty_point_details:
return loyalty_point_details[0]
else:

View File

@@ -13,6 +13,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"section_break_4",
"invoices"
],
@@ -62,6 +63,12 @@
"label": "Cost Center",
"options": "Cost Center"
},
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{
"collapsible": 1,
"fieldname": "accounting_dimensions_section",

View File

@@ -74,6 +74,6 @@ def create_party_link(primary_role, primary_party, secondary_party):
party_link.secondary_role = "Customer" if primary_role == "Supplier" else "Supplier"
party_link.secondary_party = secondary_party
party_link.save(ignore_permissions=True)
party_link.save()
return party_link

View File

@@ -118,9 +118,9 @@ class PaymentEntry(AccountsController):
if self.difference_amount:
frappe.throw(_("Difference Amount must be zero"))
self.update_payment_requests()
self.update_payment_schedule()
self.make_gl_entries()
self.update_outstanding_amounts()
self.update_payment_schedule()
self.set_status()
def validate_for_repost(self):
@@ -221,10 +221,10 @@ class PaymentEntry(AccountsController):
)
super().on_cancel()
self.update_payment_requests(cancel=True)
self.update_payment_schedule(cancel=1)
self.make_gl_entries(cancel=1)
self.update_outstanding_amounts()
self.delink_advance_entry_references()
self.update_payment_schedule(cancel=1)
self.set_status()
def update_payment_requests(self, cancel=False):

View File

@@ -8,4 +8,14 @@ frappe.ui.form.on("Payment Gateway Account", {
frm.set_df_property("payment_gateway", "read_only", 1);
}
},
setup(frm) {
frm.set_query("payment_account", function () {
return {
filters: {
company: frm.doc.company,
},
};
});
},
});

View File

@@ -6,6 +6,7 @@
"field_order": [
"payment_gateway",
"payment_channel",
"company",
"is_default",
"column_break_4",
"payment_account",
@@ -70,11 +71,21 @@
"fieldtype": "Select",
"label": "Payment Channel",
"options": "\nEmail\nPhone"
},
{
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
"options": "Company",
"print_hide": 1,
"remember_last_selected_value": 1,
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2020-09-20 13:30:27.722852",
"modified": "2025-07-14 16:49:55.210352",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Gateway Account",
@@ -95,4 +106,4 @@
],
"sort_field": "modified",
"sort_order": "DESC"
}
}

View File

@@ -15,6 +15,7 @@ class PaymentGatewayAccount(Document):
if TYPE_CHECKING:
from frappe.types import DF
company: DF.Link
currency: DF.ReadOnly | None
is_default: DF.Check
message: DF.SmallText | None
@@ -24,7 +25,8 @@ class PaymentGatewayAccount(Document):
# end: auto-generated types
def autoname(self):
self.name = self.payment_gateway + " - " + self.currency
abbr = frappe.db.get_value("Company", self.company, "abbr")
self.name = self.payment_gateway + " - " + self.currency + " - " + abbr
def validate(self):
self.currency = frappe.get_cached_value("Account", self.payment_account, "account_currency")
@@ -34,13 +36,15 @@ class PaymentGatewayAccount(Document):
def update_default_payment_gateway(self):
if self.is_default:
frappe.db.sql(
"""update `tabPayment Gateway Account` set is_default = 0
where is_default = 1 """
frappe.db.set_value(
"Payment Gateway Account",
{"is_default": 1, "name": ["!=", self.name], "company": self.company},
"is_default",
0,
)
def set_as_default_if_not_set(self):
if not frappe.db.get_value(
"Payment Gateway Account", {"is_default": 1, "name": ("!=", self.name)}, "name"
if not frappe.db.exists(
"Payment Gateway Account", {"is_default": 1, "name": ("!=", self.name), "company": self.company}
):
self.is_default = 1

View File

@@ -28,6 +28,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"sec_break1",
"invoice_name",
"invoices",
@@ -193,6 +194,12 @@
"label": "Cost Center",
"options": "Cost Center"
},
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{
"depends_on": "eval:doc.party",
"description": "Only 'Payment Entries' made against this advance account are supported.",

View File

@@ -5,6 +5,7 @@
import frappe
from frappe import _, msgprint, qb
from frappe.model.document import Document
from frappe.model.meta import get_field_precision
from frappe.query_builder import Criterion
from frappe.query_builder.custom import ConstantColumn
from frappe.utils import flt, fmt_money, get_link_to_form, getdate, nowdate, today
@@ -392,6 +393,12 @@ class PaymentReconciliation(Document):
inv.outstanding_amount = flt(entry.get("outstanding_amount"))
def get_difference_amount(self, payment_entry, invoice, allocated_amount):
allocated_amount_precision = get_field_precision(
frappe.get_meta("Payment Reconciliation Allocation").get_field("allocated_amount")
)
difference_amount_precision = get_field_precision(
frappe.get_meta("Payment Reconciliation Allocation").get_field("difference_amount")
)
difference_amount = 0
if frappe.get_cached_value(
"Account", self.receivable_payable_account, "account_currency"
@@ -399,8 +406,14 @@ class PaymentReconciliation(Document):
if invoice.get("exchange_rate") and payment_entry.get("exchange_rate", 1) != invoice.get(
"exchange_rate", 1
):
allocated_amount_in_ref_rate = payment_entry.get("exchange_rate", 1) * allocated_amount
allocated_amount_in_inv_rate = invoice.get("exchange_rate", 1) * allocated_amount
allocated_amount_in_ref_rate = flt(
payment_entry.get("exchange_rate", 1) * flt(allocated_amount, allocated_amount_precision),
difference_amount_precision,
)
allocated_amount_in_inv_rate = flt(
invoice.get("exchange_rate", 1) * flt(allocated_amount, allocated_amount_precision),
difference_amount_precision,
)
difference_amount = allocated_amount_in_ref_rate - allocated_amount_in_inv_rate
return difference_amount
@@ -576,6 +589,7 @@ class PaymentReconciliation(Document):
"difference_amount": flt(row.get("difference_amount")),
"difference_account": row.get("difference_account"),
"difference_posting_date": row.get("gain_loss_posting_date"),
"debit_or_credit_note_posting_date": row.get("debit_or_credit_note_posting_date"),
"cost_center": row.get("cost_center"),
}
)
@@ -765,7 +779,7 @@ def reconcile_dr_cr_note(dr_cr_notes, company, active_dimensions=None):
{
"doctype": "Journal Entry",
"voucher_type": voucher_type,
"posting_date": today(),
"posting_date": inv.get("debit_or_credit_note_posting_date") or today(),
"company": company,
"multi_currency": 1 if inv.currency != company_currency else 0,
"accounts": [

View File

@@ -20,6 +20,7 @@
"section_break_5",
"difference_amount",
"gain_loss_posting_date",
"debit_or_credit_note_posting_date",
"column_break_7",
"difference_account",
"exchange_rate",
@@ -168,12 +169,17 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"fieldname": "debit_or_credit_note_posting_date",
"fieldtype": "Date",
"label": "Debit / Credit Note Posting Date"
}
],
"is_virtual": 1,
"istable": 1,
"links": [],
"modified": "2023-12-14 13:38:26.104150",
"modified": "2025-08-20 19:12:50.406769",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation Allocation",
@@ -183,4 +189,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -18,6 +18,7 @@ class PaymentReconciliationAllocation(Document):
amount: DF.Currency
cost_center: DF.Link | None
currency: DF.Link | None
debit_or_credit_note_posting_date: DF.Date | None
difference_account: DF.Link | None
difference_amount: DF.Currency
exchange_rate: DF.Float

View File

@@ -9,6 +9,14 @@ frappe.ui.form.on("Payment Request", {
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
};
});
frm.set_query("payment_gateway_account", function () {
return {
filters: {
company: frm.doc.company,
},
};
});
},
});

View File

@@ -539,7 +539,9 @@ def make_payment_request(**args):
if args.dt not in ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST:
frappe.throw(_("Payment Requests cannot be created against: {0}").format(frappe.bold(args.dt)))
ref_doc = frappe.get_doc(args.dt, args.dn)
ref_doc = args.ref_doc or frappe.get_doc(args.dt, args.dn)
if not args.get("company"):
args.company = ref_doc.company
gateway_account = get_gateway_details(args) or frappe._dict()
grand_total = get_amount(ref_doc, gateway_account.get("payment_account"))
@@ -782,7 +784,7 @@ def get_gateway_details(args): # nosemgrep
"""
Return gateway and payment account of default payment gateway
"""
gateway_account = args.get("payment_gateway_account", {"is_default": 1})
gateway_account = args.get("payment_gateway_account", {"is_default": 1, "company": args.company})
if gateway_account:
return get_payment_gateway_account(gateway_account)

View File

@@ -28,12 +28,14 @@ payment_method = [
"payment_gateway": "_Test Gateway",
"payment_account": "_Test Bank - _TC",
"currency": "INR",
"company": "_Test Company",
},
{
"doctype": "Payment Gateway Account",
"payment_gateway": "_Test Gateway",
"payment_account": "_Test Bank USD - _TC",
"currency": "USD",
"company": "_Test Company",
},
]
@@ -46,7 +48,11 @@ class TestPaymentRequest(FrappeTestCase):
for method in payment_method:
if not frappe.db.get_value(
"Payment Gateway Account",
{"payment_gateway": method["payment_gateway"], "currency": method["currency"]},
{
"payment_gateway": method["payment_gateway"],
"currency": method["currency"],
"company": method["company"],
},
"name",
):
frappe.get_doc(method).insert(ignore_permissions=True)
@@ -60,7 +66,7 @@ class TestPaymentRequest(FrappeTestCase):
dt="Sales Order",
dn=so_inr.name,
recipient_id="saurabh@erpnext.com",
payment_gateway_account="_Test Gateway - INR",
payment_gateway_account="_Test Gateway - INR - _TC",
)
self.assertEqual(pr.reference_doctype, "Sales Order")
@@ -74,7 +80,7 @@ class TestPaymentRequest(FrappeTestCase):
dt="Sales Invoice",
dn=si_usd.name,
recipient_id="saurabh@erpnext.com",
payment_gateway_account="_Test Gateway - USD",
payment_gateway_account="_Test Gateway - USD - _TC",
)
self.assertEqual(pr.reference_doctype, "Sales Invoice")
@@ -95,7 +101,7 @@ class TestPaymentRequest(FrappeTestCase):
party="_Test Supplier USD",
recipient_id="user@example.com",
mute_email=1,
payment_gateway_account="_Test Gateway - USD",
payment_gateway_account="_Test Gateway - USD - _TC",
submit_doc=1,
return_doc=1,
)
@@ -119,7 +125,7 @@ class TestPaymentRequest(FrappeTestCase):
dn=purchase_invoice.name,
recipient_id="user@example.com",
mute_email=1,
payment_gateway_account="_Test Gateway - USD",
payment_gateway_account="_Test Gateway - USD - _TC",
return_doc=1,
)
@@ -138,7 +144,7 @@ class TestPaymentRequest(FrappeTestCase):
dn=purchase_invoice.name,
recipient_id="user@example.com",
mute_email=1,
payment_gateway_account="_Test Gateway - USD",
payment_gateway_account="_Test Gateway - USD - _TC",
return_doc=1,
)
@@ -162,7 +168,7 @@ class TestPaymentRequest(FrappeTestCase):
dn=so_inr.name,
recipient_id="saurabh@erpnext.com",
mute_email=1,
payment_gateway_account="_Test Gateway - INR",
payment_gateway_account="_Test Gateway - INR - _TC",
submit_doc=1,
return_doc=1,
)
@@ -184,7 +190,7 @@ class TestPaymentRequest(FrappeTestCase):
dn=si_usd.name,
recipient_id="saurabh@erpnext.com",
mute_email=1,
payment_gateway_account="_Test Gateway - USD",
payment_gateway_account="_Test Gateway - USD - _TC",
submit_doc=1,
return_doc=1,
)
@@ -228,7 +234,7 @@ class TestPaymentRequest(FrappeTestCase):
dn=si_usd.name,
recipient_id="saurabh@erpnext.com",
mute_email=1,
payment_gateway_account="_Test Gateway - USD",
payment_gateway_account="_Test Gateway - USD - _TC",
submit_doc=1,
return_doc=1,
)

View File

@@ -75,6 +75,17 @@ class PeriodClosingVoucher(AccountsController):
return
previous_fiscal_year_start_date = previous_fiscal_year[0][1]
previous_fiscal_year_closed = frappe.db.exists(
"Period Closing Voucher",
{
"period_end_date": ("between", [previous_fiscal_year_start_date, last_year_closing]),
"docstatus": 1,
"company": self.company,
},
)
if previous_fiscal_year_closed:
return
gle_exists_in_previous_year = frappe.db.exists(
"GL Entry",
{
@@ -86,16 +97,7 @@ class PeriodClosingVoucher(AccountsController):
if not gle_exists_in_previous_year:
return
previous_fiscal_year_closed = frappe.db.exists(
"Period Closing Voucher",
{
"period_end_date": ("between", [previous_fiscal_year_start_date, last_year_closing]),
"docstatus": 1,
"company": self.company,
},
)
if not previous_fiscal_year_closed:
frappe.throw(_("Previous Year is not closed, please close it first"))
frappe.throw(_("Previous Year is not closed, please close it first"))
def block_if_future_closing_voucher_exists(self):
future_closing_voucher = self.get_future_closing_voucher()

View File

@@ -55,6 +55,16 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
});
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
if (this.frm.doc.pos_profile) {
frappe.db
.get_value("POS Profile", this.frm.doc.pos_profile, "disable_grand_total_to_default_mop")
.then((r) => {
if (!r.exc) {
this.frm.skip_default_payment = r.message.disable_grand_total_to_default_mop;
}
});
}
}
onload_post_render(frm) {
@@ -113,6 +123,7 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
this.frm.meta.default_print_format = r.message.print_format || "";
this.frm.doc.campaign = r.message.campaign;
this.frm.allow_print_before_pay = r.message.allow_print_before_pay;
this.frm.skip_default_payment = r.message.skip_default_payment;
}
this.frm.script_manager.trigger("update_stock");
this.calculate_taxes_and_totals();

View File

@@ -62,6 +62,7 @@
"items_section",
"update_stock",
"scan_barcode",
"last_scanned_warehouse",
"items",
"pricing_rule_details",
"pricing_rules",
@@ -301,6 +302,7 @@
"search_index": 1
},
{
"default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -1568,12 +1570,19 @@
"label": "Company Contact Person",
"options": "Contact",
"print_hide": 1
},
{
"depends_on": "eval: doc.last_scanned_warehouse",
"fieldname": "last_scanned_warehouse",
"fieldtype": "Data",
"is_virtual": 1,
"label": "Last Scanned Warehouse"
}
],
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
"modified": "2025-07-17 16:51:40.886083",
"modified": "2025-08-04 22:22:31.471752",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",

View File

@@ -216,6 +216,7 @@ class POSInvoice(SalesInvoice):
self.validate_loyalty_transaction()
self.validate_company_with_pos_company()
self.validate_full_payment()
self.update_packing_list()
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
@@ -367,9 +368,9 @@ class POSInvoice(SalesInvoice):
)
elif is_stock_item and flt(available_stock) < flt(d.stock_qty):
frappe.throw(
_(
"Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}."
).format(d.idx, item_code, warehouse, available_stock),
_("Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}.").format(
d.idx, item_code, warehouse
),
title=_("Item Unavailable"),
)
@@ -667,7 +668,13 @@ class POSInvoice(SalesInvoice):
"Account", self.debit_to, "account_currency"
)
if not self.due_date and self.customer:
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
self.due_date = get_due_date(
self.posting_date,
"Customer",
self.customer,
self.company,
template_name=self.payment_terms_template,
)
super(SalesInvoice, self).set_missing_values(for_validate)
@@ -680,6 +687,7 @@ class POSInvoice(SalesInvoice):
"print_format": print_format,
"campaign": profile.get("campaign"),
"allow_print_before_pay": profile.get("allow_print_before_pay"),
"skip_default_payment": profile.get("disable_grand_total_to_default_mop"),
}
@frappe.whitelist()
@@ -774,10 +782,8 @@ def get_bundle_availability(bundle_item_code, warehouse):
bundle_bin_qty = 1000000
for item in product_bundle.items:
item_bin_qty = get_bin_qty(item.item_code, warehouse)
item_pos_reserved_qty = get_pos_reserved_qty(item.item_code, warehouse)
available_qty = item_bin_qty - item_pos_reserved_qty
max_available_bundles = available_qty / item.qty
max_available_bundles = item_bin_qty / item.qty
if bundle_bin_qty > max_available_bundles and frappe.get_value(
"Item", item.item_code, "is_stock_item"
):
@@ -800,13 +806,49 @@ def get_bin_qty(item_code, warehouse):
def get_pos_reserved_qty(item_code, warehouse):
"""
Calculate total quantity reserved for the given item and warehouse.
Includes:
- Direct sales of the item in submitted POS Invoices
- Sales of the item as a component of a Product Bundle
Excludes consolidated invoices (already merged into Sales Invoices via
POS Closing Entry). Used to reflect near real-time availability in the
POS UI and to prevent overselling while multiple sessions may be active.
"""
pinv_item_reserved_qty = get_pos_reserved_qty_from_table("POS Invoice Item", item_code, warehouse)
packed_item_reserved_qty = get_pos_reserved_qty_from_table("Packed Item", item_code, warehouse)
reserved_qty = pinv_item_reserved_qty + packed_item_reserved_qty
return reserved_qty
def get_pos_reserved_qty_from_table(child_table, item_code, warehouse):
"""
Get the total reserved quantity for a given item in POS Invoices
from a specific child table.
Args:
child_table (str): Name of the child table to query
(e.g., "POS Invoice Item", "Packed Item").
item_code (str): The Item Code to filter by.
warehouse (str): The Warehouse to filter by.
Returns:
float: The total reserved quantity for the item in the given
warehouse from submitted, unconsolidated POS Invoices.
"""
p_inv = frappe.qb.DocType("POS Invoice")
p_item = frappe.qb.DocType("POS Invoice Item")
p_item = frappe.qb.DocType(child_table)
qty_column = "qty" if child_table == "Packed Item" else "stock_qty"
reserved_qty = (
frappe.qb.from_(p_inv)
.from_(p_item)
.select(Sum(p_item.stock_qty).as_("stock_qty"))
.select(Sum(p_item[qty_column]).as_("stock_qty"))
.where(
(p_inv.name == p_item.parent)
& (IfNull(p_inv.consolidated_invoice, "") == "")

View File

@@ -174,6 +174,7 @@
},
{
"default": "0",
"depends_on": "eval:doc.apply_on != 'Transaction'",
"fieldname": "is_cumulative",
"fieldtype": "Check",
"label": "Is Cumulative"
@@ -656,7 +657,7 @@
"icon": "fa fa-gift",
"idx": 1,
"links": [],
"modified": "2025-02-17 18:15:39.824639",
"modified": "2025-08-20 11:40:07.096854",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",

View File

@@ -583,11 +583,7 @@ def apply_pricing_rule_on_transaction(doc):
if not d.get(pr_field):
continue
if (
d.validate_applied_rule
and doc.get(field) is not None
and doc.get(field) < d.get(pr_field)
):
if d.validate_applied_rule and (doc.get(field) or 0) < d.get(pr_field):
frappe.msgprint(_("User has not applied rule on the invoice {0}").format(doc.name))
else:
if not d.coupon_code_based:

View File

@@ -78,18 +78,18 @@
"reqd": 1
},
{
"depends_on": "eval:(doc.enable_auto_email == 0 && doc.report == 'General Ledger');",
"depends_on": "eval:(!doc.enable_auto_email && doc.report == 'General Ledger');",
"fieldname": "from_date",
"fieldtype": "Date",
"label": "From Date",
"mandatory_depends_on": "eval:doc.frequency == '';"
"mandatory_depends_on": "eval:(!doc.enable_auto_email && doc.report == \"General Ledger\") "
},
{
"depends_on": "eval:(doc.enable_auto_email == 0 && doc.report == 'General Ledger');",
"depends_on": "eval:(!doc.enable_auto_email && doc.report == 'General Ledger');",
"fieldname": "to_date",
"fieldtype": "Date",
"label": "To Date",
"mandatory_depends_on": "eval:doc.frequency == '';"
"mandatory_depends_on": "eval:(!doc.enable_auto_email && doc.report == \"General Ledger\") "
},
{
"fieldname": "cost_center",
@@ -330,7 +330,8 @@
"depends_on": "eval:(doc.report == 'Accounts Receivable');",
"fieldname": "posting_date",
"fieldtype": "Date",
"label": "Posting Date"
"label": "Posting Date",
"mandatory_depends_on": "eval:(doc.report == 'Accounts Receivable');"
},
{
"depends_on": "eval: (doc.report == 'Accounts Receivable');",
@@ -400,7 +401,7 @@
}
],
"links": [],
"modified": "2025-07-08 16:52:12.602384",
"modified": "2025-08-04 18:21:12.603623",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",

View File

@@ -550,7 +550,7 @@ def send_auto_email():
selected = frappe.get_list(
"Process Statement Of Accounts",
filters={"enable_auto_email": 1},
or_filters={"to_date": format_date(today()), "posting_date": format_date(today())},
or_filters={"to_date": today(), "posting_date": today()},
)
for entry in selected:
send_emails(entry.name, from_scheduler=True)

View File

@@ -3,7 +3,7 @@
import frappe
from frappe.model.document import Document
from frappe.utils import getdate
from frappe.utils import create_batch, getdate
from erpnext.accounts.doctype.subscription.subscription import DateTimeLikeObject, process_all
@@ -23,7 +23,23 @@ class ProcessSubscription(Document):
# end: auto-generated types
def on_submit(self):
process_all(subscription=self.subscription, posting_date=self.posting_date)
self.process_all_subscription()
def process_all_subscription(self):
filters = {"status": ("!=", "Cancelled")}
if self.subscription:
filters["name"] = self.subscription
subscriptions = frappe.get_all("Subscription", filters, pluck="name")
for subscription in create_batch(subscriptions, 500):
frappe.enqueue(
method="erpnext.accounts.doctype.subscription.subscription.process_all",
queue="long",
subscription=subscription,
posting_date=self.posting_date,
)
def create_subscription_process(

View File

@@ -93,12 +93,14 @@
},
{
"default": "0",
"depends_on": "eval:doc.apply_on != 'Transaction'",
"fieldname": "mixed_conditions",
"fieldtype": "Check",
"label": "Mixed Conditions"
},
{
"default": "0",
"depends_on": "eval:doc.apply_on != 'Transaction'",
"fieldname": "is_cumulative",
"fieldtype": "Check",
"label": "Is Cumulative"
@@ -278,7 +280,7 @@
}
],
"links": [],
"modified": "2021-05-06 16:20:22.039078",
"modified": "2025-08-20 11:48:23.231081",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme",
@@ -336,4 +338,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@@ -35,7 +35,10 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
this.frm.set_query("expense_account", "items", function () {
return {
query: "erpnext.controllers.queries.get_expense_account",
filters: { company: doc.company },
filters: {
company: doc.company,
disabled: 0,
},
};
});
}
@@ -150,6 +153,9 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
per_billed: ["<", 99.99],
company: me.frm.doc.company,
},
allow_child_item_selection: true,
child_fieldname: "items",
child_columns: ["item_code", "item_name", "qty", "amount", "billed_amt"],
});
},
__("Get Items From")
@@ -172,6 +178,9 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
company: me.frm.doc.company,
is_return: 0,
},
allow_child_item_selection: true,
child_fieldname: "items",
child_columns: ["item_code", "item_name", "qty", "amount", "billed_amt"],
});
},
__("Get Items From")
@@ -635,7 +644,7 @@ frappe.ui.form.on("Purchase Invoice", {
},
add_custom_buttons: function (frm) {
if (frm.doc.docstatus == 1 && frm.doc.per_received < 100) {
if (frm.doc.docstatus == 1 && frm.doc.per_received < 100 && frm.doc.update_stock == 0) {
frm.add_custom_button(
__("Purchase Receipt"),
() => {

View File

@@ -47,6 +47,7 @@
"ignore_pricing_rule",
"sec_warehouse",
"scan_barcode",
"last_scanned_warehouse",
"col_break_warehouse",
"update_stock",
"set_warehouse",
@@ -319,6 +320,7 @@
"search_index": 1
},
{
"default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -1643,6 +1645,13 @@
"label": "Select Dispatch Address ",
"options": "Address",
"print_hide": 1
},
{
"depends_on": "eval: doc.last_scanned_warehouse",
"fieldname": "last_scanned_warehouse",
"fieldtype": "Data",
"is_virtual": 1,
"label": "Last Scanned Warehouse"
}
],
"grid_page_length": 50,
@@ -1650,7 +1659,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2025-04-09 16:49:22.175081",
"modified": "2025-08-04 19:19:11.380664",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -2,6 +2,8 @@
# License: GNU General Public License v3. See license.txt
import json
import frappe
from frappe import _, qb, throw
from frappe.model.mapper import get_mapped_doc
@@ -338,7 +340,12 @@ class PurchaseInvoice(BuyingController):
)
if not self.due_date:
self.due_date = get_due_date(
self.posting_date, "Supplier", self.supplier, self.company, self.bill_date
self.posting_date,
"Supplier",
self.supplier,
self.company,
self.bill_date,
template_name=self.payment_terms_template,
)
tds_category = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category")
@@ -2070,7 +2077,12 @@ def make_inter_company_sales_invoice(source_name, target_doc=None):
@frappe.whitelist()
def make_purchase_receipt(source_name, target_doc=None):
def make_purchase_receipt(source_name, target_doc=None, args=None):
if args is None:
args = {}
if isinstance(args, str):
args = json.loads(args)
def update_item(obj, target, source_parent):
target.qty = flt(obj.qty) - flt(obj.received_qty)
target.received_qty = flt(obj.qty) - flt(obj.received_qty)
@@ -2080,6 +2092,11 @@ def make_purchase_receipt(source_name, target_doc=None):
(flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate) * flt(source_parent.conversion_rate)
)
def select_item(d):
filtered_items = args.get("filtered_children", [])
child_filter = d.name in filtered_items if filtered_items else True
return child_filter
doc = get_mapped_doc(
"Purchase Invoice",
source_name,
@@ -2103,7 +2120,7 @@ def make_purchase_receipt(source_name, target_doc=None):
"wip_composite_asset": "wip_composite_asset",
},
"postprocess": update_item,
"condition": lambda doc: abs(doc.received_qty) < abs(doc.qty),
"condition": lambda doc: abs(doc.received_qty) < abs(doc.qty) and select_item(doc),
},
"Purchase Taxes and Charges": {"doctype": "Purchase Taxes and Charges"},
},

View File

@@ -22,6 +22,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"section_break_9",
"account_currency",
"tax_amount",
@@ -211,6 +212,13 @@
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 1,
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{
"default": "0",
"depends_on": "eval:['Purchase Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)",

View File

@@ -5,6 +5,7 @@ import inspect
import frappe
from frappe import _, qb
from frappe.desk.form.linked_with import get_child_tables_of_doctypes
from frappe.model.document import Document
from frappe.utils.data import comma_and
@@ -177,7 +178,7 @@ def start_repost(account_repost_doc=str) -> None:
if doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
if not repost_doc.delete_cancelled_entries:
doc.docstatus = 2
doc.make_gl_entries_on_cancel()
doc.make_gl_entries_on_cancel(from_repost=True)
doc.docstatus = 1
if doc.doctype == "Sales Invoice":
@@ -189,7 +190,7 @@ def start_repost(account_repost_doc=str) -> None:
elif doc.doctype == "Purchase Receipt":
if not repost_doc.delete_cancelled_entries:
doc.docstatus = 2
doc.make_gl_entries_on_cancel()
doc.make_gl_entries_on_cancel(from_repost=True)
doc.docstatus = 1
doc.make_gl_entries(from_repost=True)
@@ -208,13 +209,29 @@ def start_repost(account_repost_doc=str) -> None:
doc.make_gl_entries()
def get_allowed_types_from_settings():
return [
def get_allowed_types_from_settings(child_doc: bool = False):
repost_docs = [
x.document_type
for x in frappe.db.get_all(
"Repost Allowed Types", filters={"allowed": True}, fields=["distinct(document_type)"]
)
]
result = repost_docs
if repost_docs and child_doc:
result.extend(get_child_docs(repost_docs))
return result
def get_child_docs(doc: list) -> list:
child_doc = []
doc = get_child_tables_of_doctypes(doc)
for child_list in doc.values():
for child in child_list:
if child.get("child_table"):
child_doc.append(child["child_table"])
return child_doc
def validate_docs_for_deferred_accounting(sales_docs, purchase_docs):

View File

@@ -1,9 +1,14 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
import frappe
from frappe.model.document import Document
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
)
from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import get_child_docs
class RepostAccountingLedgerSettings(Document):
# begin: auto-generated types
@@ -17,6 +22,24 @@ class RepostAccountingLedgerSettings(Document):
from erpnext.accounts.doctype.repost_allowed_types.repost_allowed_types import RepostAllowedTypes
allowed_types: DF.Table[RepostAllowedTypes]
# end: auto-generated types
pass
# end: auto-generated types
def validate(self):
self.update_property_for_accounting_dimension()
def update_property_for_accounting_dimension(self):
doctypes = [entry.document_type for entry in self.allowed_types if entry.allowed]
if not doctypes:
return
doctypes += get_child_docs(doctypes)
set_allow_on_submit_for_dimension_fields(doctypes)
def set_allow_on_submit_for_dimension_fields(doctypes):
for dt in doctypes:
meta = frappe.get_meta(dt)
for dimension in get_accounting_dimensions():
df = meta.get_field(dimension)
if df and not df.allow_on_submit:
frappe.db.set_value("Custom Field", dt + "-" + dimension, "allow_on_submit", 1)

View File

@@ -58,6 +58,13 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
me.frm.script_manager.trigger("is_pos");
me.frm.refresh_fields();
frappe.db
.get_value("POS Profile", this.frm.doc.pos_profile, "disable_grand_total_to_default_mop")
.then((r) => {
if (!r.exc) {
me.frm.skip_default_payment = r.message.disable_grand_total_to_default_mop;
}
});
}
erpnext.queries.setup_warehouse_query(this.frm);
}
@@ -259,6 +266,9 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
per_billed: ["<", 99.99],
company: me.frm.doc.company,
},
allow_child_item_selection: true,
child_fieldname: "items",
child_columns: ["item_code", "item_name", "qty", "amount", "billed_amt"],
});
},
__("Get Items From")
@@ -288,6 +298,9 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
status: ["!=", "Lost"],
company: me.frm.doc.company,
},
allow_child_item_selection: true,
child_fieldname: "items",
child_columns: ["item_code", "item_name", "qty", "rate", "amount"],
});
},
__("Get Items From")
@@ -319,6 +332,9 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
filters: filters,
};
},
allow_child_item_selection: true,
child_fieldname: "items",
child_columns: ["item_code", "item_name", "qty", "amount", "billed_amt"],
});
},
__("Get Items From")
@@ -497,8 +513,9 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
},
callback: function (r) {
if (!r.exc) {
if (r.message && r.message.print_format) {
if (r.message) {
me.frm.pos_print_format = r.message.print_format;
me.frm.skip_default_payment = r.message.skip_default_payment;
}
me.frm.trigger("update_stock");
if (me.frm.doc.taxes_and_charges) {

View File

@@ -45,6 +45,7 @@
"items_section",
"scan_barcode",
"update_stock",
"last_scanned_warehouse",
"column_break_39",
"set_warehouse",
"set_target_warehouse",
@@ -280,6 +281,7 @@
"read_only": 1
},
{
"fetch_from": "customer.tax_id",
"fieldname": "tax_id",
"fieldtype": "Data",
"hide_days": 1,
@@ -379,6 +381,7 @@
"search_index": 1
},
{
"default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"hide_days": 1,
@@ -2176,6 +2179,13 @@
"label": "Company Contact Person",
"options": "Contact",
"print_hide": 1
},
{
"depends_on": "eval: doc.last_scanned_warehouse",
"fieldname": "last_scanned_warehouse",
"fieldtype": "Data",
"is_virtual": 1,
"label": "Last Scanned Warehouse"
}
],
"grid_page_length": 50,
@@ -2189,7 +2199,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2025-06-26 14:06:56.773552",
"modified": "2025-09-09 14:48:59.472826",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -700,6 +700,7 @@ class SalesInvoice(SellingController):
"allow_edit_discount": pos.get("allow_user_to_edit_discount"),
"campaign": pos.get("campaign"),
"allow_print_before_pay": pos.get("allow_print_before_pay"),
"skip_default_payment": pos.get("disable_grand_total_to_default_mop"),
}
def update_time_sheet(self, sales_invoice):
@@ -1206,7 +1207,6 @@ class SalesInvoice(SellingController):
self.make_exchange_gain_loss_journal()
elif self.docstatus == 2:
cancel_exchange_gain_loss_journal(frappe._dict(doctype=self.doctype, name=self.name))
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
if update_outstanding == "No":
@@ -1370,8 +1370,9 @@ class SalesInvoice(SellingController):
)
asset.db_set("disposal_date", None)
add_asset_activity(asset.name, _("Asset returned"))
asset_status = asset.get_status()
if asset.calculate_depreciation:
if asset.calculate_depreciation and not asset_status == "Fully Depreciated":
posting_date = (
frappe.db.get_value("Sales Invoice", self.return_against, "posting_date")
if self.is_return

View File

@@ -8,7 +8,7 @@ import frappe
from frappe import qb
from frappe.model.dynamic_links import get_dynamic_link_map
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, flt, format_date, getdate, nowdate, today
from frappe.utils import add_days, cint, flt, format_date, getdate, nowdate, today
import erpnext
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
@@ -4575,6 +4575,152 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(stock_ledger_entry.qty, 2.0)
self.assertEqual(stock_ledger_entry.stock_value_difference, 0.0)
def test_non_batchwise_valuation_for_moving_average(self):
from erpnext.stock.doctype.item.test_item import make_item
item_code = "_Test Item for Non Batchwise Valuation"
make_item_for_si(
item_code,
{
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "TBATCH-TCNV.####",
"valuation_method": "Moving Average",
},
)
doc = frappe.get_doc("Stock Settings")
original_value = cint(doc.do_not_use_batchwise_valuation)
doc.db_set("do_not_use_batchwise_valuation", 1)
se = make_stock_entry(
item_code=item_code,
qty=10,
target="_Test Warehouse - _TC",
rate=13.02,
valuation_method="Moving Average",
use_serial_batch_fields=True,
)
se_batch = get_batch_from_bundle(se.items[0].serial_and_batch_bundle)
# without use serial and batch fields
si = create_sales_invoice(
item=item_code,
qty=1,
rate=120,
update_stock=1,
use_serial_batch_fields=False,
warehouse="_Test Warehouse - _TC",
)
si.reload()
si_batch = get_batch_from_bundle(si.items[0].serial_and_batch_bundle)
self.assertEqual(se_batch, si_batch)
self.assertEqual(si.items[0].use_serial_batch_fields, 0)
serial_and_batch_bundle = si.items[0].serial_and_batch_bundle
change_in_value = frappe.db.get_value(
"Stock Ledger Entry",
{
"voucher_type": "Sales Invoice",
"voucher_no": si.name,
"item_code": item_code,
"warehouse": "_Test Warehouse - _TC",
"serial_and_batch_bundle": serial_and_batch_bundle,
},
"stock_value_difference",
)
self.assertEqual(change_in_value, 13.02 * -1)
# with use serial and batch fields
si = create_sales_invoice(
item=item_code,
qty=1,
rate=120,
update_stock=1,
use_serial_batch_fields=True,
warehouse="_Test Warehouse - _TC",
)
si.reload()
self.assertEqual(si.items[0].use_serial_batch_fields, 1)
serial_and_batch_bundle = si.items[0].serial_and_batch_bundle
change_in_value = frappe.db.get_value(
"Stock Ledger Entry",
{
"voucher_type": "Sales Invoice",
"voucher_no": si.name,
"item_code": item_code,
"warehouse": "_Test Warehouse - _TC",
"serial_and_batch_bundle": serial_and_batch_bundle,
},
"stock_value_difference",
)
self.assertEqual(change_in_value, 13.02 * -1)
doc.db_set("do_not_use_batchwise_valuation", original_value)
def test_system_generated_exchange_gain_or_loss_je_after_repost(self):
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.doctype.repost_accounting_ledger.test_repost_accounting_ledger import (
update_repost_settings,
)
update_repost_settings()
si = create_sales_invoice(
customer="_Test Customer USD",
debit_to="_Test Receivable USD - _TC",
currency="USD",
conversion_rate=80,
)
pe = get_payment_entry("Sales Invoice", si.name)
pe.reference_no = "10"
pe.reference_date = nowdate()
pe.paid_from_account_currency = si.currency
pe.paid_to_account_currency = "INR"
pe.source_exchange_rate = 85
pe.target_exchange_rate = 1
pe.paid_amount = si.outstanding_amount
pe.insert()
pe.submit()
ral = frappe.new_doc("Repost Accounting Ledger")
ral.company = si.company
ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name})
ral.save()
ral.submit()
je = frappe.qb.DocType("Journal Entry")
jea = frappe.qb.DocType("Journal Entry Account")
q = (
(
frappe.qb.from_(je)
.join(jea)
.on(je.name == jea.parent)
.select(je.docstatus)
.where(
(je.voucher_type == "Exchange Gain Or Loss")
& (jea.reference_name == si.name)
& (jea.reference_type == "Sales Invoice")
& (je.is_system_generated == 1)
)
)
.limit(1)
.run()
)
self.assertEqual(q[0][0], 1)
def make_item_for_si(item_code, properties=None):
from erpnext.stock.doctype.item.test_item import make_item
@@ -4690,6 +4836,7 @@ def create_sales_invoice(**args):
"incoming_rate": args.incoming_rate or 0,
"serial_and_batch_bundle": bundle_id,
"allow_zero_valuation_rate": args.allow_zero_valuation_rate or 0,
"use_serial_batch_fields": args.use_serial_batch_fields or 0,
},
)

View File

@@ -16,6 +16,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"section_break_8",
"rate",
"section_break_9",
@@ -188,6 +189,13 @@
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 1,
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{
"default": "0",
"depends_on": "eval:['Sales Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)",

View File

@@ -16,6 +16,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"shipping_amount_section",
"calculate_based_on",
"column_break_8",
@@ -136,6 +137,12 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
}
],
"icon": "fa fa-truck",

View File

@@ -756,18 +756,14 @@ def get_prorata_factor(
return diff / plan_days
def process_all(subscription: str | None = None, posting_date: DateTimeLikeObject | None = None) -> None:
def process_all(subscription: list, posting_date: DateTimeLikeObject | None = None) -> None:
"""
Task to updates the status of all `Subscription` apart from those that are cancelled
"""
filters = {"status": ("!=", "Cancelled")}
if subscription:
filters["name"] = subscription
for subscription in frappe.get_all("Subscription", filters, pluck="name"):
for subscription_name in subscription:
try:
subscription = frappe.get_doc("Subscription", subscription)
subscription = frappe.get_doc("Subscription", subscription_name)
subscription.process(posting_date)
frappe.db.commit()
except frappe.ValidationError:

View File

@@ -75,7 +75,7 @@
},
{
"default": "0",
"description": "Even invoices with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
"description": "Only payment entries with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
"fieldname": "consider_party_ledger_amount",
"fieldtype": "Check",
"label": "Consider Entire Party Ledger Amount",
@@ -102,10 +102,11 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-07-27 21:47:34.396071",
"modified": "2025-07-30 07:13:51.785735",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Category",
"naming_rule": "Set by user",
"owner": "Administrator",
"permissions": [
{
@@ -148,4 +149,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@@ -18,7 +18,7 @@ from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_f
)
from erpnext.accounts.doctype.accounting_period.accounting_period import ClosedAccountingPeriod
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
from erpnext.accounts.utils import create_payment_ledger_entry
from erpnext.accounts.utils import create_payment_ledger_entry, is_immutable_ledger_enabled
from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
@@ -186,6 +186,15 @@ def process_gl_map(gl_map, merge_entries=True, precision=None, from_repost=False
def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None, from_repost=False):
round_off_account, default_currency = frappe.get_cached_value(
"Company", gl_map[0].company, ["round_off_account", "default_currency"]
)
if not precision:
precision = get_field_precision(
frappe.get_meta("GL Entry").get_field("debit"),
currency=default_currency,
)
new_gl_map = []
for d in gl_map:
cost_center = d.get("cost_center")
@@ -203,6 +212,11 @@ def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None, from_r
new_gl_map.append(d)
continue
if d.account == round_off_account:
d.cost_center = cost_center_allocation[0][0]
new_gl_map.append(d)
continue
for sub_cost_center, percentage in cost_center_allocation:
gle = copy.deepcopy(d)
gle.cost_center = sub_cost_center
@@ -824,7 +838,3 @@ def validate_allowed_dimensions(gl_entry, dimension_filter_map):
),
InvalidAccountDimensionError,
)
def is_immutable_ledger_enabled():
return frappe.db.get_single_value("Accounts Settings", "enable_immutable_ledger")

View File

@@ -164,6 +164,12 @@
{% } %}
</tr>
</thead>
<div class="show-filters">
{% if subtitle %}
{{ subtitle }}
<hr>
{% endif %}
</div>
<tbody>
{% for(var i=0, l=data.length; i<l; i++) { %}
<tr>

View File

@@ -974,6 +974,7 @@ class ReceivablePayableReport:
if self.account_type == "Receivable":
self.add_customer_filters()
self.exclude_employee_transaction()
elif self.account_type == "Payable":
self.add_supplier_filters()
@@ -1053,6 +1054,9 @@ class ReceivablePayableReport:
)
)
def exclude_employee_transaction(self):
self.qb_selection_filter.append(self.ple.party_type != "Employee")
def add_supplier_filters(self):
supplier = qb.DocType("Supplier")
if self.filters.get("supplier_group"):

View File

@@ -25,17 +25,25 @@ def get_group_by_asset_category_data(filters):
asset_categories = get_asset_categories_for_grouped_by_category(filters)
assets = get_assets_for_grouped_by_category(filters)
asset_value_adjustment_map = get_asset_value_adjustment_map_by_category(filters)
for asset_category in asset_categories:
row = frappe._dict()
row.update(asset_category)
adjustments = asset_value_adjustment_map.get(asset_category.get("asset_category"), {})
row.adjustment_before_from_date = flt(adjustments.get("adjustment_before_from_date", 0))
row.adjustment_till_to_date = flt(adjustments.get("adjustment_till_to_date", 0))
row.adjustment_during_period = row.adjustment_till_to_date - row.adjustment_before_from_date
row.value_as_on_from_date += row.adjustment_before_from_date
row.value_as_on_to_date = (
flt(row.value_as_on_from_date)
+ flt(row.value_of_new_purchase)
- flt(row.value_of_sold_asset)
- flt(row.value_of_scrapped_asset)
- flt(row.value_of_capitalized_asset)
+ flt(row.adjustment_during_period)
)
row.update(
@@ -229,26 +237,93 @@ def get_assets_for_grouped_by_category(filters):
)
def get_asset_value_adjustment_map_by_category(filters):
asset_value_adjustments = frappe.db.sql(
"""
SELECT
a.asset_category AS asset_category,
IFNULL(
SUM(
CASE
WHEN gle.posting_date < %(from_date)s
AND (a.disposal_date IS NULL OR a.disposal_date >= %(from_date)s)
THEN gle.debit - gle.credit
ELSE 0
END
),
0) AS value_adjustment_before_from_date,
IFNULL(
SUM(
CASE
WHEN gle.posting_date <= %(to_date)s
AND (a.disposal_date IS NULL OR a.disposal_date >= %(to_date)s)
THEN gle.debit - gle.credit
ELSE 0
END
),
0) AS value_adjustment_till_to_date
FROM `tabGL Entry` gle
JOIN `tabAsset` a ON gle.against_voucher = a.name
JOIN `tabAsset Category Account` aca
ON aca.parent = a.asset_category
AND aca.company_name = %(company)s
WHERE gle.is_cancelled = 0
AND a.docstatus = 1
AND a.company = %(company)s
AND a.purchase_date <= %(to_date)s
AND gle.account = aca.fixed_asset_account
GROUP BY a.asset_category
""",
{"from_date": filters.from_date, "to_date": filters.to_date, "company": filters.company},
as_dict=1,
)
category_value_adjustment_map = {}
for r in asset_value_adjustments:
category_value_adjustment_map[r["asset_category"]] = {
"adjustment_before_from_date": flt(r.get("value_adjustment_before_from_date", 0)),
"adjustment_till_to_date": flt(r.get("value_adjustment_till_to_date", 0)),
}
return category_value_adjustment_map
def get_group_by_asset_data(filters):
data = []
asset_details = get_asset_details_for_grouped_by_category(filters)
assets = get_assets_for_grouped_by_asset(filters)
asset_value_adjustment_map = get_asset_value_adjustment_map(filters)
for asset_detail in asset_details:
row = frappe._dict()
row.update(asset_detail)
row.update(next(asset for asset in assets if asset["asset"] == asset_detail.get("name", "")))
adjustments = asset_value_adjustment_map.get(
asset_detail.get("name", ""),
{
"adjustment_before_from_date": 0.0,
"adjustment_till_to_date": 0.0,
},
)
row.adjustment_before_from_date = adjustments["adjustment_before_from_date"]
row.adjustment_till_to_date = adjustments["adjustment_till_to_date"]
row.adjustment_during_period = flt(row.adjustment_till_to_date) - flt(row.adjustment_before_from_date)
row.value_as_on_from_date += row.adjustment_before_from_date
row.value_as_on_to_date = (
flt(row.value_as_on_from_date)
+ flt(row.value_of_new_purchase)
- flt(row.value_of_sold_asset)
- flt(row.value_of_scrapped_asset)
- flt(row.value_of_capitalized_asset)
+ flt(row.adjustment_during_period)
)
row.update(next(asset for asset in assets if asset["asset"] == asset_detail.get("name", "")))
row.accumulated_depreciation_as_on_to_date = (
flt(row.accumulated_depreciation_as_on_from_date)
+ flt(row.depreciation_amount_during_the_period)
@@ -432,6 +507,59 @@ def get_assets_for_grouped_by_asset(filters):
)
def get_asset_value_adjustment_map(filters):
asset_with_value_adjustments = frappe.db.sql(
"""
SELECT
a.name AS asset,
IFNULL(
SUM(
CASE
WHEN gle.posting_date < %(from_date)s
AND (a.disposal_date IS NULL OR a.disposal_date >= %(from_date)s)
THEN gle.debit - gle.credit
ELSE 0
END
),
0) AS value_adjustment_before_from_date,
IFNULL(
SUM(
CASE
WHEN gle.posting_date <= %(to_date)s
AND (a.disposal_date IS NULL OR a.disposal_date >= %(to_date)s)
THEN gle.debit - gle.credit
ELSE 0
END
),
0) AS value_adjustment_till_to_date
FROM `tabGL Entry` gle
JOIN `tabAsset` a ON gle.against_voucher = a.name
JOIN `tabAsset Category Account` aca
ON aca.parent = a.asset_category
AND aca.company_name = %(company)s
WHERE gle.is_cancelled = 0
AND a.docstatus = 1
AND a.company = %(company)s
AND a.purchase_date <= %(to_date)s
AND gle.account = aca.fixed_asset_account
GROUP BY a.name
""",
{"from_date": filters.from_date, "to_date": filters.to_date, "company": filters.company},
as_dict=1,
)
asset_value_adjustment_map = {}
for r in asset_with_value_adjustments:
asset_value_adjustment_map[r["asset"]] = {
"adjustment_before_from_date": flt(r.get("value_adjustment_before_from_date", 0)),
"adjustment_till_to_date": flt(r.get("value_adjustment_till_to_date", 0)),
}
return asset_value_adjustment_map
def get_columns(filters):
columns = []

View File

@@ -38,6 +38,7 @@ from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement
get_report_summary as get_pl_summary,
)
from erpnext.accounts.report.utils import convert, convert_to_presentation_currency
from erpnext.accounts.utils import get_zero_cutoff
def execute(filters=None):
@@ -563,7 +564,7 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com
row[company] = flt(d.get(company, 0.0), 3)
if abs(row[company]) >= 0.005:
if abs(row[company]) >= get_zero_cutoff(filters.presentation_currency):
# ignore zero values
has_value = True
total += flt(row[company])

View File

@@ -12,6 +12,7 @@ from erpnext.accounts.report.financial_statements import (
filter_out_zero_value_rows,
)
from erpnext.accounts.report.trial_balance.trial_balance import validate_filters
from erpnext.accounts.utils import get_zero_cutoff
def execute(filters=None):
@@ -154,7 +155,7 @@ def prepare_data(accounts, filters, company_currency, dimension_list):
for dimension in dimension_list:
row[frappe.scrub(dimension)] = flt(d.get(frappe.scrub(dimension), 0.0), 3)
if abs(row[frappe.scrub(dimension)]) >= 0.005:
if abs(row[frappe.scrub(dimension)]) >= get_zero_cutoff(company_currency):
# ignore zero values
has_value = True
total += flt(d.get(frappe.scrub(dimension), 0.0), 3)

View File

@@ -34,6 +34,12 @@
</h5>
{% } %}
<hr>
<div class="show-filters">
{% if subtitle %}
{{ subtitle }}
<hr>
{% endif %}
</div>
<table class="table table-bordered">
<thead>
<tr>

View File

@@ -18,7 +18,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_dimension_with_children,
)
from erpnext.accounts.report.utils import convert_to_presentation_currency, get_currency
from erpnext.accounts.utils import get_fiscal_year
from erpnext.accounts.utils import get_fiscal_year, get_zero_cutoff
def get_period_list(
@@ -304,7 +304,7 @@ def prepare_data(accounts, balance_must_be, period_list, company_currency, accum
row[period.key] = flt(d.get(period.key, 0.0), 3)
if abs(row[period.key]) >= 0.005:
if abs(row[period.key]) >= get_zero_cutoff(company_currency):
# ignore zero values
has_value = True
total += flt(row[period.key])
@@ -532,6 +532,7 @@ def get_accounting_entries(
query = query.select(gl_entry.posting_date, gl_entry.is_opening, gl_entry.fiscal_year)
query = query.where(gl_entry.is_cancelled == 0)
query = query.where(gl_entry.posting_date <= to_date)
query = query.force_index("posting_date_company_index")
if ignore_opening_entries and not ignore_is_opening:
query = query.where(gl_entry.is_opening == "No")

View File

@@ -21,6 +21,12 @@
{%= frappe.datetime.str_to_user(filters.to_date) %}
</h5>
<hr>
<div class="show-filters">
{% if subtitle %}
{{ subtitle }}
<hr>
{% endif %}
</div>
<table class="table table-bordered">
<thead>
<tr>

View File

@@ -197,6 +197,11 @@ frappe.query_reports["General Ledger"] = {
label: __("Show Net Values in Party Account"),
fieldtype: "Check",
},
{
fieldname: "show_amount_in_company_currency",
label: __("Show Credit / Debit in Company Currency"),
fieldtype: "Check",
},
{
fieldname: "add_values_in_transaction_currency",
label: __("Add Columns in Transaction Currency"),

View File

@@ -1,29 +1,34 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2013-12-06 13:22:23",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-02-24 20:17:51.995451",
"modified_by": "Administrator",
"module": "Accounts",
"name": "General Ledger",
"owner": "Administrator",
"ref_doctype": "GL Entry",
"report_name": "General Ledger",
"report_type": "Script Report",
"add_total_row": 1,
"add_translate_data": 0,
"columns": [],
"creation": "2013-12-06 13:22:23",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 3,
"is_standard": "Yes",
"letterhead": null,
"modified": "2025-08-13 12:47:27.645023",
"modified_by": "Administrator",
"module": "Accounts",
"name": "General Ledger",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "GL Entry",
"report_name": "General Ledger",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts User"
},
},
{
"role": "Accounts Manager"
},
},
{
"role": "Auditor"
}
]
}
],
"timeout": 0
}

View File

@@ -203,6 +203,12 @@ def get_gl_entries(filters, accounting_dimensions):
as_dict=1,
)
party_name_map = get_party_name_map()
for gl_entry in gl_entries:
if gl_entry.party_type and gl_entry.party:
gl_entry.party_name = party_name_map.get(gl_entry.party_type, {}).get(gl_entry.party)
if filters.get("presentation_currency"):
return convert_to_presentation_currency(gl_entries, currency_map, filters)
else:
@@ -337,6 +343,20 @@ def get_conditions(filters):
return "and {}".format(" and ".join(conditions)) if conditions else ""
def get_party_name_map():
party_map = {}
customers = frappe.get_all("Customer", fields=["name", "customer_name"])
party_map["Customer"] = {c.name: c.customer_name for c in customers}
suppliers = frappe.get_all("Supplier", fields=["name", "supplier_name"])
party_map["Supplier"] = {s.name: s.supplier_name for s in suppliers}
employees = frappe.get_all("Employee", fields=["name", "employee_name"])
party_map["Employee"] = {e.name: e.employee_name for e in employees}
return party_map
def get_accounts_with_children(accounts):
if not isinstance(accounts, list):
accounts = [d.strip() for d in accounts.strip().split(",") if d]
@@ -605,6 +625,18 @@ def get_columns(filters):
company = filters.get("company") or get_default_company()
filters["presentation_currency"] = currency = get_company_currency(company)
company_currency = get_company_currency(filters.get("company") or get_default_company())
if (
filters.get("show_amount_in_company_currency")
and filters["presentation_currency"] != company_currency
):
frappe.throw(
_(
f'Presentation Currency cannot be {frappe.bold(filters["presentation_currency"])} , When {frappe.bold("Show Credit / Debit in Company Currency")} is enabled.'
)
)
columns = [
{
"label": _("GL Entry"),
@@ -613,7 +645,7 @@ def get_columns(filters):
"options": "GL Entry",
"hidden": 1,
},
{"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 100},
{"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 120},
{
"label": _("Account"),
"fieldname": "account",
@@ -689,6 +721,19 @@ def get_columns(filters):
{"label": _("Party"), "fieldname": "party", "width": 100},
]
supplier_master_name = frappe.db.get_single_value("Buying Settings", "supp_master_name")
customer_master_name = frappe.db.get_single_value("Selling Settings", "cust_master_name")
if supplier_master_name != "Supplier Name" or customer_master_name != "Customer Name":
columns.append(
{
"label": _("Party Name"),
"fieldname": "party_name",
"fieldtype": "Data",
"width": 150,
}
)
if filters.get("include_dimensions"):
columns.append({"label": _("Project"), "options": "Project", "fieldname": "project", "width": 100})

View File

@@ -33,6 +33,7 @@ def execute(filters=None):
"invoice_or_item",
"customer",
"customer_group",
"customer_name",
"posting_date",
"item_code",
"item_name",
@@ -95,6 +96,7 @@ def execute(filters=None):
"customer": [
"customer",
"customer_group",
"customer_name",
"qty",
"base_rate",
"buying_rate",
@@ -250,6 +252,10 @@ def get_data_when_not_grouped_by_invoice(gross_profit_data, filters, group_wise_
def get_columns(group_wise_columns, filters):
columns = []
supplier_master_name = frappe.db.get_single_value("Buying Settings", "supp_master_name")
customer_master_name = frappe.db.get_single_value("Selling Settings", "cust_master_name")
column_map = frappe._dict(
{
"parent": {
@@ -395,6 +401,12 @@ def get_columns(group_wise_columns, filters):
"options": "Customer Group",
"width": 100,
},
"customer_name": {
"label": _("Customer Name"),
"fieldname": "customer_name",
"fieldtype": "Data",
"width": 150,
},
"territory": {
"label": _("Territory"),
"fieldname": "territory",
@@ -419,6 +431,10 @@ def get_columns(group_wise_columns, filters):
)
for col in group_wise_columns.get(scrub(filters.group_by)):
if col == "customer_name" and (
supplier_master_name == "Supplier Name" and customer_master_name == "Customer Name"
):
continue
columns.append(column_map.get(col))
columns.append(
@@ -440,6 +456,7 @@ def get_column_names():
"invoice_or_item": "sales_invoice",
"customer": "customer",
"customer_group": "customer_group",
"customer_name": "customer_name",
"posting_date": "posting_date",
"item_code": "item_code",
"item_name": "item_name",
@@ -905,7 +922,7 @@ class GrossProfitGenerator:
`tabSales Invoice Item`.parenttype, `tabSales Invoice Item`.parent,
`tabSales Invoice`.posting_date, `tabSales Invoice`.posting_time,
`tabSales Invoice`.project, `tabSales Invoice`.update_stock,
`tabSales Invoice`.customer, `tabSales Invoice`.customer_group,
`tabSales Invoice`.customer, `tabSales Invoice`.customer_group, `tabSales Invoice`.customer_name,
`tabSales Invoice`.territory, `tabSales Invoice Item`.item_code,
`tabSales Invoice`.base_net_total as "invoice_base_net_total",
`tabSales Invoice Item`.item_name, `tabSales Invoice Item`.description,
@@ -1003,6 +1020,7 @@ class GrossProfitGenerator:
"update_stock": row.update_stock,
"customer": row.customer,
"customer_group": row.customer_group,
"customer_name": row.customer_name,
"item_code": None,
"item_name": None,
"description": None,
@@ -1032,6 +1050,7 @@ class GrossProfitGenerator:
"project": row.project,
"customer": row.customer,
"customer_group": row.customer_group,
"customer_name": row.customer_name,
"item_code": item.item_code,
"item_name": item.item_name,
"description": item.description,

View File

@@ -9,7 +9,6 @@ from frappe.query_builder import functions as fn
from frappe.utils import cstr, flt
from frappe.utils.nestedset import get_descendants_of
from frappe.utils.xlsxutils import handle_html
from pypika import Order
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
from erpnext.accounts.report.utils import get_values_for_columns
@@ -355,7 +354,13 @@ def apply_conditions(query, si, sii, sip, filters, additional_conditions=None):
query = query.where(si.posting_date <= filters.get("to_date"))
if filters.get("mode_of_payment"):
query = query.where(sip.mode_of_payment == filters.get("mode_of_payment"))
subquery = (
frappe.qb.from_(sip)
.select(sip.parent)
.where(sip.mode_of_payment == filters.get("mode_of_payment"))
.groupby(sip.parent)
)
query = query.where(si.name.isin(subquery))
if filters.get("warehouse"):
if frappe.db.get_value("Warehouse", filters.get("warehouse"), "is_group"):
@@ -424,8 +429,6 @@ def get_items(filters, additional_query_columns, additional_conditions=None):
frappe.qb.from_(si)
.join(sii)
.on(si.name == sii.parent)
.left_join(sip)
.on(sip.parent == si.name)
.left_join(item)
.on(sii.item_code == item.name)
.select(
@@ -465,7 +468,6 @@ def get_items(filters, additional_query_columns, additional_conditions=None):
si.update_stock,
sii.uom,
sii.qty,
sip.mode_of_payment,
)
.where(si.docstatus == 1)
.where(sii.parenttype == doctype)

View File

@@ -46,6 +46,7 @@ def get_ordered_to_be_billed_data(args, filters=None):
child_doctype.item_name,
child_doctype.description,
project_field,
doctype.company,
)
.where(
(doctype.docstatus == 1)

View File

@@ -46,6 +46,7 @@ class PaymentLedger:
against_voucher_no=ple.against_voucher_no,
amount=ple.amount,
currency=ple.account_currency,
company=ple.company,
)
if self.filters.include_account_currency:
@@ -77,6 +78,7 @@ class PaymentLedger:
against_voucher_no="Outstanding:",
amount=total,
currency=voucher_data[0].currency,
company=voucher_data[0].company,
)
if self.filters.include_account_currency:
@@ -85,7 +87,12 @@ class PaymentLedger:
voucher_data.append(entry)
# empty row
voucher_data.append(frappe._dict())
voucher_data.append(
frappe._dict(
currency=voucher_data[0].currency,
company=voucher_data[0].company,
)
)
self.data.extend(voucher_data)
def build_conditions(self):
@@ -130,7 +137,6 @@ class PaymentLedger:
)
def get_columns(self):
company_currency = frappe.get_cached_value("Company", self.filters.get("company"), "default_currency")
options = None
self.columns.append(
dict(
@@ -195,7 +201,7 @@ class PaymentLedger:
label=_("Amount"),
fieldname="amount",
fieldtype="Currency",
options=company_currency,
options="Company:company:default_currency",
width="100",
)
)

View File

@@ -12,6 +12,7 @@ from erpnext.accounts.report.financial_statements import (
filter_out_zero_value_rows,
)
from erpnext.accounts.report.trial_balance.trial_balance import validate_filters
from erpnext.accounts.utils import get_zero_cutoff
value_fields = ("income", "expense", "gross_profit_loss")
@@ -149,7 +150,7 @@ def prepare_data(accounts, filters, total_row, parent_children_map, based_on):
for key in value_fields:
row[key] = flt(d.get(key, 0.0), 3)
if abs(row[key]) >= 0.005:
if abs(row[key]) >= get_zero_cutoff(company_currency):
# ignore zero values
has_value = True

View File

@@ -45,6 +45,7 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
gle_map = get_gle_map(tds_docs)
out = []
entries = {}
for name, details in gle_map.items():
for entry in details:
tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
@@ -119,8 +120,13 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
"supplier_invoice_date": bill_date,
}
)
out.append(row)
key = entry.voucher_no
if key in entries:
entries[key]["tax_amount"] += tax_amount
else:
entries[key] = row
out = list(entries.values())
out.sort(key=lambda x: (x["section_code"], x["transaction_date"]))
return out

View File

@@ -18,6 +18,7 @@ from erpnext.accounts.report.financial_statements import (
set_gl_entries_by_account,
)
from erpnext.accounts.report.utils import convert_to_presentation_currency, get_currency
from erpnext.accounts.utils import get_zero_cutoff
value_fields = (
"opening_debit",
@@ -413,7 +414,7 @@ def prepare_data(accounts, filters, parent_children_map, company_currency):
for key in value_fields:
row[key] = flt(d.get(key, 0.0), 3)
if abs(row[key]) >= 0.005:
if abs(row[key]) >= get_zero_cutoff(company_currency):
# ignore zero values
has_value = True

View File

@@ -4,15 +4,25 @@
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"mandatory": 1,
"options": "Company",
"wildcard_filter": 0
}
],
"idx": 0,
"is_standard": "Yes",
"modified": "2019-01-17 17:20:42.374958",
"modified": "2025-08-28 19:06:54.273322",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Trial Balance (Simple)",
"owner": "Administrator",
"prepared_report": 0,
"query": "select fiscal_year as \"Fiscal Year:Data:80\",\n\tcompany as \"Company:Data:220\",\n\tposting_date as \"Posting Date:Date:100\",\n\taccount as \"Account:Data:380\",\n\tsum(debit) as \"Debit:Currency:140\",\n\tsum(credit) as \"Credit:Currency:140\",\n\tfinance_book as \"Finance Book:Link/Finance Book:140\"\nfrom `tabGL Entry`\ngroup by fiscal_year, company, posting_date, account\norder by fiscal_year, company, posting_date, account",
"query": "select fiscal_year as \"Fiscal Year:Data:80\",\n\tcompany as \"Company:Data:220\",\n\tposting_date as \"Posting Date:Date:100\",\n\taccount as \"Account:Data:380\",\n\tsum(debit) as \"Debit:Currency:140\",\n\tsum(credit) as \"Credit:Currency:140\",\n\tfinance_book as \"Finance Book:Link/Finance Book:140\"\nfrom `tabGL Entry`\nwhere is_cancelled = 0 and company = %(company)s\ngroup by fiscal_year, company, posting_date, account\norder by fiscal_year, company, posting_date, account",
"ref_doctype": "GL Entry",
"report_name": "Trial Balance (Simple)",
"report_type": "Query Report",

View File

@@ -118,7 +118,7 @@ def convert_to_presentation_currency(gl_entries, currency_info, filters=None):
len(account_currencies) == 1
and account_currency == presentation_currency
and not exchange_gain_or_loss
):
) and not (filters and filters.get("show_amount_in_company_currency")):
entry["debit"] = debit_in_account_currency
entry["credit"] = credit_in_account_currency
else:

View File

@@ -9,6 +9,7 @@ from erpnext.accounts.party import get_party_shipping_address
from erpnext.accounts.utils import (
get_future_stock_vouchers,
get_voucherwise_gl_entries,
get_zero_cutoff,
sort_stock_vouchers_by_posting_date,
)
from erpnext.stock.doctype.item.test_item import make_item
@@ -156,6 +157,11 @@ class TestUtils(unittest.TestCase):
self.assertSequenceEqual(doc_name[0:2], ("SUP", fiscal_year))
frappe.db.set_default("supp_master_name", "Supplier Name")
def test_get_zero_cutoff(self):
self.assertEqual(get_zero_cutoff(None), 0.005)
self.assertEqual(get_zero_cutoff("EUR"), 0.005)
self.assertEqual(get_zero_cutoff("BHD"), 0.0005)
ADDRESS_RECORDS = [
{

View File

@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from collections import defaultdict
from json import loads
from typing import TYPE_CHECKING, Optional
@@ -26,6 +27,7 @@ from frappe.utils import (
now,
nowdate,
)
from frappe.utils.caching import site_cache
from pypika import Order
from pypika.functions import Coalesce
from pypika.terms import ExistsCriterion
@@ -469,7 +471,6 @@ def reconcile_against_document(
reconciled_entries[(row.voucher_type, row.voucher_no)] = []
reconciled_entries[(row.voucher_type, row.voucher_no)].append(row)
for key, entries in reconciled_entries.items():
voucher_type, voucher_no = key
@@ -1130,6 +1131,29 @@ def get_currency_precision():
return precision
def get_fraction_units(currency: str) -> int:
"""Returns the number of fraction units for a currency."""
fraction_units = frappe.db.get_value("Currency", currency, "fraction_units")
if fraction_units is None:
fraction_units = 100
return fraction_units
@site_cache()
def get_zero_cutoff(currency: str) -> float:
"""Returns the zero cutoff for a currency.
For example, if the Fraction Units for a currency are set to 100, then the zero cutoff is 0.005.
We don't want to display values less than the zero cutoff.
This value was chosen for compatibility with the previous hard-coded value of 0.005.
"""
fraction_units = get_fraction_units(currency)
return 0.5 / (fraction_units or 1)
def get_held_invoices(party_type, party):
"""
Returns a list of names Purchase Invoices for the given party that are on hold
@@ -1339,6 +1363,7 @@ def create_payment_gateway_account(gateway, payment_channel="Email"):
"payment_account": bank_account.name,
"currency": bank_account.account_currency,
"payment_channel": payment_channel,
"company": company,
}
).insert(ignore_permissions=True, ignore_if_duplicate=True)
@@ -1742,40 +1767,38 @@ def create_err_and_its_journals(companies: list | None = None) -> None:
jv and frappe.get_doc("Journal Entry", jv).submit()
def _auto_create_exchange_rate_revaluation_for(frequency: str) -> None:
"""
Internal helper to avoid code duplication and typos.
Fetches companies by frequency and triggers ERR.
"""
companies = frappe.db.get_all(
"Company",
filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": frequency},
fields=["name", "submit_err_jv"],
)
create_err_and_its_journals(companies)
def auto_create_exchange_rate_revaluation_daily() -> None:
"""
Executed by background job
"""
companies = frappe.db.get_all(
"Company",
filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Daily"},
fields=["name", "submit_err_jv"],
)
create_err_and_its_journals(companies)
_auto_create_exchange_rate_revaluation_for("Daily")
def auto_create_exchange_rate_revaluation_weekly() -> None:
"""
Executed by background job
"""
companies = frappe.db.get_all(
"Company",
filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Weekly"},
fields=["name", "submit_err_jv"],
)
create_err_and_its_journals(companies)
_auto_create_exchange_rate_revaluation_for("Weekly")
def auto_create_exchange_rate_revaluation_monthly() -> None:
"""
Executed by background job
"""
companies = frappe.db.get_all(
"Company",
filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Montly"},
fields=["name", "submit_err_jv"],
)
create_err_and_its_journals(companies)
_auto_create_exchange_rate_revaluation_for("Monthly")
def get_payment_ledger_entries(gl_entries, cancel=0):
@@ -1803,6 +1826,7 @@ def get_payment_ledger_entries(gl_entries, cancel=0):
dr_or_cr = 0
account_type = None
for gle in gl_entries:
if gle.account in receivable_or_payable_accounts:
account_type = get_account_type(gle.account)
@@ -1895,6 +1919,9 @@ def create_payment_ledger_entry(
if cancel:
delink_original_entry(ple, partial_cancel=partial_cancel)
if is_immutable_ledger_enabled():
ple.delinked = 0
ple.posting_date = frappe.form_dict.get("posting_date") or getdate()
ple.flags.ignore_permissions = 1
ple.flags.adv_adj = adv_adj
@@ -1904,10 +1931,12 @@ def create_payment_ledger_entry(
def update_voucher_outstanding(voucher_type, voucher_no, account, party_type, party):
from erpnext.accounts.doctype.dunning.dunning import update_linked_dunnings
if not voucher_type or not voucher_no:
return
if voucher_type in ["Purchase Order", "Sales Order"]:
if voucher_type in get_advance_payment_doctypes():
ref_doc = frappe.get_lazy_doc(voucher_type, voucher_no)
ref_doc.set_total_advance_paid()
return
@@ -1936,6 +1965,7 @@ def update_voucher_outstanding(voucher_type, voucher_no, account, party_type, pa
):
outstanding = voucher_outstanding[0]
ref_doc = frappe.get_doc(voucher_type, voucher_no)
previous_outstanding_amount = ref_doc.outstanding_amount
outstanding_amount = flt(
outstanding["outstanding_in_account_currency"], ref_doc.precision("outstanding_amount")
)
@@ -1949,6 +1979,7 @@ def update_voucher_outstanding(voucher_type, voucher_no, account, party_type, pa
outstanding_amount,
)
update_linked_dunnings(ref_doc, previous_outstanding_amount)
ref_doc.set_status(update=True)
ref_doc.notify_update()
@@ -1978,7 +2009,6 @@ def delink_original_entry(pl_entry, partial_cancel=False):
ple = qb.DocType("Payment Ledger Entry")
query = (
qb.update(ple)
.set(ple.delinked, True)
.set(ple.modified, now())
.set(ple.modified_by, frappe.session.user)
.where(
@@ -1997,6 +2027,9 @@ def delink_original_entry(pl_entry, partial_cancel=False):
if partial_cancel:
query = query.where(ple.voucher_detail_no == pl_entry.voucher_detail_no)
if not is_immutable_ledger_enabled():
query = query.set(ple.delinked, True)
query.run()
@@ -2419,25 +2452,46 @@ def sync_auto_reconcile_config(auto_reconciliation_job_trigger: int = 15):
).save()
def get_link_fields_grouped_by_option(doctype):
meta = frappe.get_meta(doctype)
link_fields_map = defaultdict(list)
for df in meta.fields:
if df.fieldtype == "Link" and df.options and not df.ignore_user_permissions:
link_fields_map[df.options].append(df.fieldname)
return link_fields_map
def build_qb_match_conditions(doctype, user=None) -> list:
match_filters = build_match_conditions(doctype, user, False)
link_fields_map = get_link_fields_grouped_by_option(doctype)
criterion = []
apply_strict_user_permissions = frappe.get_system_settings("apply_strict_user_permissions")
if match_filters:
from frappe import qb
_dt = qb.DocType(doctype)
for filter in match_filters:
for d, names in filter.items():
fieldname = d.lower().replace(" ", "_")
field = _dt[fieldname]
for link_option, allowed_values in filter.items():
fieldnames = link_fields_map.get(link_option, [])
cond = None
cond = field.isin(names)
if not apply_strict_user_permissions:
cond = (Coalesce(field, "") == "") | field.isin(names)
if link_option == doctype:
cond = _dt["name"].isin(allowed_values)
criterion.append(cond)
for fieldname in fieldnames:
field = _dt[fieldname]
cond = field.isin(allowed_values)
if not apply_strict_user_permissions:
cond = (Coalesce(field, "") == "") | cond
if cond:
criterion.append(cond)
return criterion
def is_immutable_ledger_enabled():
return frappe.get_single_value("Accounts Settings", "enable_immutable_ledger")

View File

@@ -122,6 +122,7 @@ class Asset(AccountsController):
def validate(self):
self.validate_category()
self.validate_precision()
self.validate_linked_purchase_docs()
self.set_purchase_doc_row_item()
self.validate_asset_values()
self.validate_asset_and_reference()
@@ -321,6 +322,9 @@ class Asset(AccountsController):
finance_books = get_item_details(self.item_code, self.asset_category, self.gross_purchase_amount)
self.set("finance_books", finance_books)
if self.asset_owner == "Company" and not self.asset_owner_company:
self.asset_owner_company = self.company
def validate_finance_books(self):
if not self.calculate_depreciation or len(self.finance_books) == 1:
return
@@ -409,6 +413,21 @@ class Asset(AccountsController):
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
frappe.throw(_("Available-for-use Date should be after purchase date"))
def validate_linked_purchase_docs(self):
for doctype_field, doctype_name in [
("purchase_receipt", "Purchase Receipt"),
("purchase_invoice", "Purchase Invoice"),
]:
linked_doc = getattr(self, doctype_field, None)
if linked_doc:
docstatus = frappe.db.get_value(doctype_name, linked_doc, "docstatus")
if docstatus == 0:
frappe.throw(
_("{0} is still in Draft. Please submit it before saving the Asset.").format(
get_link_to_form(doctype_name, linked_doc)
)
)
def validate_gross_and_purchase_amount(self):
if self.is_existing_asset:
return
@@ -1083,7 +1102,7 @@ def get_asset_account(account_name, asset=None, asset_category=None, company=Non
def make_journal_entry(asset_name):
asset = frappe.get_doc("Asset", asset_name)
(
_,
fixed_asset_account,
accumulated_depreciation_account,
depreciation_expense_account,
) = get_depreciation_accounts(asset.asset_category, asset.company)
@@ -1097,7 +1116,7 @@ def make_journal_entry(asset_name):
je.voucher_type = "Depreciation Entry"
je.naming_series = depreciation_series
je.company = asset.company
je.remark = f"Depreciation Entry against asset {asset_name}"
je.remark = _("Depreciation Entry against asset {0}").format(asset_name)
je.append(
"accounts",

View File

@@ -277,7 +277,9 @@ def _make_journal_entry_for_depreciation(
je.posting_date = depr_schedule.schedule_date
je.company = asset.company
je.finance_book = asset_depr_schedule_doc.finance_book
je.remark = f"Depreciation Entry against {asset.name} worth {depr_schedule.depreciation_amount}"
je.remark = _("Depreciation Entry against {0} worth {1}").format(
asset.name, depr_schedule.depreciation_amount
)
credit_entry = {
"account": credit_account,

View File

@@ -346,6 +346,33 @@ class TestAsset(AssetSetup):
si.cancel()
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
def test_asset_status_after_sales_invoice_cancel(self):
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
asset = create_asset(
calculate_depreciation=1,
available_for_use_date="2020-04-01",
purchase_date="2020-04-01",
expected_value_after_useful_life=0,
total_number_of_depreciations=5,
opening_number_of_booked_depreciations=2,
frequency_of_depreciation=12,
depreciation_start_date="2023-03-31",
opening_accumulated_depreciation=24000,
gross_purchase_amount=60000,
submit=1,
)
si = create_sales_invoice(
item_code="Macbook Pro", asset=asset.name, qty=1, rate=40000, posting_date=getdate("2023-05-23")
)
asset.load_from_db()
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
si.cancel()
asset.load_from_db()
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
def test_gle_made_by_asset_sale_for_existing_asset(self):
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice

View File

@@ -44,6 +44,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"target_fixed_asset_account"
],
"fields": [
@@ -288,6 +289,12 @@
"label": "Cost Center",
"options": "Cost Center"
},
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"

View File

@@ -18,6 +18,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"fixed_asset_account"
],
"fields": [
@@ -98,6 +99,13 @@
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 1,
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{
"fieldname": "finance_book",
"fieldtype": "Link",

View File

@@ -98,20 +98,41 @@ class AssetDepreciationSchedule(Document):
)
def on_submit(self):
self.validate_asset()
self.db_set("status", "Active")
def before_cancel(self):
def validate_asset(self):
asset = frappe.get_doc("Asset", self.asset)
if not asset.calculate_depreciation:
frappe.throw(
_("Asset {0} is not set to calculate depreciation.").format(
get_link_to_form("Asset", self.asset)
)
)
if asset.docstatus != 1:
frappe.throw(
_("Asset {0} is not submitted. Please submit the asset before proceeding.").format(
get_link_to_form("Asset", self.asset)
)
)
def on_cancel(self):
self.db_set("status", "Cancelled")
if not self.flags.should_not_cancel_depreciation_entries:
self.cancel_depreciation_entries()
def cancel_depreciation_entries(self):
for d in self.get("depreciation_schedule"):
if d.journal_entry:
je_status = frappe.db.get_value("Journal Entry", d.journal_entry, "docstatus")
if je_status == 0:
frappe.throw(
_(
"Cannot cancel Asset Depreciation Schedule {0} as it has a draft journal entry {1}."
).format(self.name, d.journal_entry)
)
frappe.get_doc("Journal Entry", d.journal_entry).cancel()
def on_cancel(self):
self.db_set("status", "Cancelled")
def update_shift_depr_schedule(self):
if not self.shift_based or self.docstatus != 0:
return
@@ -348,6 +369,10 @@ class AssetDepreciationSchedule(Document):
original_schedule_date=schedule_date,
)
depreciation_amount = flt(depreciation_amount, asset_doc.precision("gross_purchase_amount"))
if depreciation_amount > row.value_after_depreciation - row.expected_value_after_useful_life:
depreciation_amount = row.value_after_depreciation - row.expected_value_after_useful_life
if depreciation_amount > 0:
self.add_depr_schedule_row(date_of_disposal, depreciation_amount, n)
@@ -435,7 +460,7 @@ class AssetDepreciationSchedule(Document):
continue
depreciation_amount = flt(depreciation_amount, asset_doc.precision("gross_purchase_amount"))
value_after_depreciation = flt(
value_after_depreciation - flt(depreciation_amount),
flt(value_after_depreciation) - flt(depreciation_amount),
asset_doc.precision("gross_purchase_amount"),
)
@@ -633,6 +658,7 @@ def _get_pro_rata_amt(
total_days = get_total_days(original_schedule_date or to_date, 12)
else:
total_days = get_total_days(original_schedule_date or to_date, row.frequency_of_depreciation)
return (depreciation_amount * flt(days)) / flt(total_days), days, months

View File

@@ -3,13 +3,13 @@ frappe.listview_settings["Asset Maintenance Log"] = {
has_indicator_for_draft: 1,
get_indicator: function (doc) {
if (doc.maintenance_status == "Planned") {
return [__(doc.maintenance_status), "orange", "status,=," + doc.maintenance_status];
return [__(doc.maintenance_status), "orange", "maintenance_status,=," + doc.maintenance_status];
} else if (doc.maintenance_status == "Completed") {
return [__(doc.maintenance_status), "green", "status,=," + doc.maintenance_status];
return [__(doc.maintenance_status), "green", "maintenance_status,=," + doc.maintenance_status];
} else if (doc.maintenance_status == "Cancelled") {
return [__(doc.maintenance_status), "red", "status,=," + doc.maintenance_status];
return [__(doc.maintenance_status), "red", "maintenance_status,=," + doc.maintenance_status];
} else if (doc.maintenance_status == "Overdue") {
return [__(doc.maintenance_status), "red", "status,=," + doc.maintenance_status];
return [__(doc.maintenance_status), "red", "maintenance_status,=," + doc.maintenance_status];
}
},
};

View File

@@ -61,7 +61,7 @@ class AssetMovement(Document):
if d.source_location:
if current_location != d.source_location:
frappe.throw(
_("Asset {0} does not belongs to the location {1}").format(d.asset, d.source_location)
_("Asset {0} does not belong to the location {1}").format(d.asset, d.source_location)
)
else:
d.source_location = current_location
@@ -75,11 +75,11 @@ class AssetMovement(Document):
frappe.throw(_("Target Location is required while receiving Asset {0}").format(d.asset))
if d.to_employee and frappe.db.get_value("Employee", d.to_employee, "company") != self.company:
frappe.throw(
_("Employee {0} does not belongs to the company {1}").format(d.to_employee, self.company)
_("Employee {0} does not belong to the company {1}").format(d.to_employee, self.company)
)
def validate_employee(self, d):
if self.purpose == "Tranfer and Issue":
if self.purpose == "Transfer and Issue":
if not d.from_employee:
frappe.throw(_("From Employee is required while issuing Asset {0}").format(d.asset))
@@ -88,7 +88,7 @@ class AssetMovement(Document):
if current_custodian != d.from_employee:
frappe.throw(
_("Asset {0} does not belongs to the custodian {1}").format(d.asset, d.from_employee)
_("Asset {0} does not belong to the custodian {1}").format(d.asset, d.from_employee)
)
if not d.to_employee:
@@ -96,7 +96,7 @@ class AssetMovement(Document):
if d.to_employee and frappe.db.get_value("Employee", d.to_employee, "company") != self.company:
frappe.throw(
_("Employee {0} does not belongs to the company {1}").format(d.to_employee, self.company)
_("Employee {0} does not belong to the company {1}").format(d.to_employee, self.company)
)
def on_submit(self):

View File

@@ -31,6 +31,91 @@ def execute(filters=None):
return columns, data, None, chart
def get_data(filters):
data = []
conditions = get_conditions(filters)
pr_supplier_map = get_purchase_receipt_supplier_map()
pi_supplier_map = get_purchase_invoice_supplier_map()
assets_linked_to_fb = get_assets_linked_to_fb(filters)
company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
if filters.include_default_book_assets and company_fb:
finance_book = company_fb
elif filters.finance_book:
finance_book = filters.finance_book
else:
finance_book = None
depreciation_amount_map = get_asset_depreciation_amount_map(filters, finance_book)
revaluation_amount_map = get_asset_value_adjustment_map(filters, finance_book)
group_by = frappe.scrub(filters.get("group_by"))
if group_by in ("asset_category", "location"):
data = get_group_by_data(
group_by, conditions, assets_linked_to_fb, depreciation_amount_map, revaluation_amount_map
)
return data
fields = [
"name as asset_id",
"asset_name",
"status",
"department",
"company",
"cost_center",
"calculate_depreciation",
"purchase_receipt",
"asset_category",
"purchase_date",
"gross_purchase_amount",
"location",
"available_for_use_date",
"purchase_invoice",
"opening_accumulated_depreciation",
]
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields)
for asset in assets_record:
if assets_linked_to_fb and asset.calculate_depreciation and asset.asset_id not in assets_linked_to_fb:
continue
depreciation_amount = depreciation_amount_map.get(asset.asset_id) or 0.0
revaluation_amount = revaluation_amount_map.get(asset.asset_id, 0.0)
asset_value = (
asset.gross_purchase_amount
- asset.opening_accumulated_depreciation
- depreciation_amount
+ revaluation_amount
)
row = {
"asset_id": asset.asset_id,
"asset_name": asset.asset_name,
"status": asset.status,
"department": asset.department,
"cost_center": asset.cost_center,
"vendor_name": pr_supplier_map.get(asset.purchase_receipt)
or pi_supplier_map.get(asset.purchase_invoice),
"gross_purchase_amount": asset.gross_purchase_amount,
"opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
"depreciated_amount": depreciation_amount,
"available_for_use_date": asset.available_for_use_date,
"location": asset.location,
"asset_category": asset.asset_category,
"purchase_date": asset.purchase_date,
"asset_value": asset_value,
"company": asset.company,
}
data.append(row)
return data
def get_conditions(filters):
conditions = {"docstatus": 1}
status = filters.status
@@ -76,83 +161,6 @@ def get_conditions(filters):
return conditions
def get_data(filters):
data = []
conditions = get_conditions(filters)
pr_supplier_map = get_purchase_receipt_supplier_map()
pi_supplier_map = get_purchase_invoice_supplier_map()
assets_linked_to_fb = get_assets_linked_to_fb(filters)
company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
if filters.include_default_book_assets and company_fb:
finance_book = company_fb
elif filters.finance_book:
finance_book = filters.finance_book
else:
finance_book = None
depreciation_amount_map = get_asset_depreciation_amount_map(filters, finance_book)
group_by = frappe.scrub(filters.get("group_by"))
if group_by in ("asset_category", "location"):
data = get_group_by_data(group_by, conditions, assets_linked_to_fb, depreciation_amount_map)
return data
fields = [
"name as asset_id",
"asset_name",
"status",
"department",
"company",
"cost_center",
"calculate_depreciation",
"purchase_receipt",
"asset_category",
"purchase_date",
"gross_purchase_amount",
"location",
"available_for_use_date",
"purchase_invoice",
"opening_accumulated_depreciation",
]
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields)
for asset in assets_record:
if assets_linked_to_fb and asset.calculate_depreciation and asset.asset_id not in assets_linked_to_fb:
continue
depreciation_amount = depreciation_amount_map.get(asset.asset_id) or 0.0
asset_value = (
asset.gross_purchase_amount - asset.opening_accumulated_depreciation - depreciation_amount
)
row = {
"asset_id": asset.asset_id,
"asset_name": asset.asset_name,
"status": asset.status,
"department": asset.department,
"cost_center": asset.cost_center,
"vendor_name": pr_supplier_map.get(asset.purchase_receipt)
or pi_supplier_map.get(asset.purchase_invoice),
"gross_purchase_amount": asset.gross_purchase_amount,
"opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
"depreciated_amount": depreciation_amount,
"available_for_use_date": asset.available_for_use_date,
"location": asset.location,
"asset_category": asset.asset_category,
"purchase_date": asset.purchase_date,
"asset_value": asset_value,
"company": asset.company,
}
data.append(row)
return data
def prepare_chart_data(data, filters):
if not data:
return
@@ -290,7 +298,59 @@ def get_asset_depreciation_amount_map(filters, finance_book):
return dict(asset_depr_amount_map)
def get_group_by_data(group_by, conditions, assets_linked_to_fb, depreciation_amount_map):
def get_asset_value_adjustment_map(filters, finance_book):
start_date = filters.from_date if filters.filter_based_on == "Date Range" else filters.year_start_date
end_date = filters.to_date if filters.filter_based_on == "Date Range" else filters.year_end_date
asset = frappe.qb.DocType("Asset")
gle = frappe.qb.DocType("GL Entry")
aca = frappe.qb.DocType("Asset Category Account")
company = frappe.qb.DocType("Company")
query = (
frappe.qb.from_(gle)
.join(asset)
.on(gle.against_voucher == asset.name)
.join(aca)
.on((aca.parent == asset.asset_category) & (aca.company_name == asset.company))
.join(company)
.on(company.name == asset.company)
.select(asset.name.as_("asset"), Sum(gle.debit - gle.credit).as_("adjustment_amount"))
.where(gle.account == aca.fixed_asset_account)
.where(gle.is_cancelled == 0)
.where(company.name == filters.company)
.where(asset.docstatus == 1)
)
if filters.only_existing_assets:
query = query.where(asset.is_existing_asset == 1)
if filters.asset_category:
query = query.where(asset.asset_category == filters.asset_category)
if filters.cost_center:
query = query.where(asset.cost_center == filters.cost_center)
if filters.status:
if filters.status == "In Location":
query = query.where(asset.status.notin(["Sold", "Scrapped", "Capitalized"]))
else:
query = query.where(asset.status.isin(["Sold", "Scrapped", "Capitalized"]))
if finance_book:
query = query.where((gle.finance_book.isin([cstr(finance_book), ""])) | (gle.finance_book.isnull()))
else:
query = query.where((gle.finance_book.isin([""])) | (gle.finance_book.isnull()))
if filters.filter_based_on in ("Date Range", "Fiscal Year"):
query = query.where(gle.posting_date >= start_date)
query = query.where(gle.posting_date <= end_date)
query = query.groupby(asset.name)
asset_adjustment_map = query.run()
return dict(asset_adjustment_map)
def get_group_by_data(
group_by, conditions, assets_linked_to_fb, depreciation_amount_map, revaluation_amount_map
):
fields = [
group_by,
"name",
@@ -307,8 +367,12 @@ def get_group_by_data(group_by, conditions, assets_linked_to_fb, depreciation_am
continue
a["depreciated_amount"] = depreciation_amount_map.get(a["name"], 0.0)
a["revaluation_amount"] = revaluation_amount_map.get(a["name"], 0.0)
a["asset_value"] = (
a["gross_purchase_amount"] - a["opening_accumulated_depreciation"] - a["depreciated_amount"]
a["gross_purchase_amount"]
- a["opening_accumulated_depreciation"]
- a["depreciated_amount"]
+ a["revaluation_amount"]
)
del a["name"]

View File

@@ -39,7 +39,9 @@
"section_break_xcug",
"auto_create_subcontracting_order",
"column_break_izrr",
"auto_create_purchase_receipt"
"auto_create_purchase_receipt",
"request_for_quotation_tab",
"fixed_email"
],
"fields": [
{
@@ -255,6 +257,19 @@
"fieldname": "set_valuation_rate_for_rejected_materials",
"fieldtype": "Check",
"label": "Set Valuation Rate for Rejected Materials"
},
{
"fieldname": "request_for_quotation_tab",
"fieldtype": "Tab Break",
"label": "Request for Quotation"
},
{
"description": "If set, the system does not use the user's Email or the standard outgoing Email account for sending request for quotations.",
"fieldname": "fixed_email",
"fieldtype": "Link",
"label": "Fixed Outgoing Email Account",
"link_filters": "[[\"Email Account\",\"enable_outgoing\",\"=\",1]]",
"options": "Email Account"
}
],
"grid_page_length": 50,
@@ -263,7 +278,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-05-16 15:56:38.321369",
"modified": "2025-08-20 22:13:38.506889",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",

View File

@@ -30,6 +30,7 @@ class BuyingSettings(Document):
blanket_order_allowance: DF.Float
buying_price_list: DF.Link | None
disable_last_purchase_rate: DF.Check
fixed_email: DF.Link | None
maintain_same_rate: DF.Check
maintain_same_rate_action: DF.Literal["Stop", "Warn"]
over_transfer_allowance: DF.Float

View File

@@ -463,8 +463,8 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends (
if (internal) {
let button_label =
me.frm.doc.company === me.frm.doc.represents_company
? "Internal Sales Order"
: "Inter Company Sales Order";
? __("Internal Sales Order")
: __("Inter Company Sales Order");
me.frm.add_custom_button(
button_label,
@@ -578,7 +578,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends (
},
allow_child_item_selection: true,
child_fieldname: "items",
child_columns: ["item_code", "qty", "ordered_qty"],
child_columns: ["item_code", "item_name", "qty", "ordered_qty"],
});
},
__("Get Items From")
@@ -599,6 +599,9 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends (
docstatus: 1,
status: ["not in", ["Stopped", "Expired"]],
},
allow_child_item_selection: true,
child_fieldname: "items",
child_columns: ["item_code", "item_name", "qty", "rate", "amount"],
});
},
__("Get Items From")

Some files were not shown because too many files have changed in this diff Show More