Compare commits

...

1044 Commits

Author SHA1 Message Date
coderabbitai[bot]
16f13c75de 📝 Add docstrings to fix-mt940-statement-number-parsing
Docstrings generation was requested by @srujan00123.

* https://github.com/frappe/erpnext/pull/49682#issuecomment-3322321445

The following files were modified:

* `erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py`
* `erpnext/accounts/doctype/bank_statement_import/test_bank_statement_import.py`
2025-09-23 03:58:23 +00:00
MochaMind
609164fb9a fix: sync translations from crowdin (#49660) 2025-09-22 16:21:27 +02:00
ruthra kumar
993ba4cf45 Merge pull request #49643 from aerele/po-super-class
fix(purchase order): invoke superclass onload method
2025-09-22 13:40:55 +05:30
ruthra kumar
bb081e46d7 Merge pull request #49644 from aerele/po-party-currency
fix(purchase order): get party type based on supplier field
2025-09-22 13:35:10 +05:30
ruthra kumar
6985f0efc3 Merge pull request #49653 from aerele/ar-exclude-employee
fix(accounts receivable): exclude employee transactions
2025-09-22 13:34:53 +05:30
Ravibharathi
302ff49b7f Merge pull request #49470 from aerele/bank-clearance-tax-calculation
fix(bank clearance): use base total taxes and charges if exists
2025-09-22 11:26:56 +05:30
Diptanil Saha
ee2b65806b Merge pull request #49649 from diptanilsaha/issue-replied
fix: set first_response_time on set_first_response
2025-09-22 00:05:07 +05:30
diptanilsaha
ba459204b0 fix: set first_response_time on status change of issue 2025-09-21 23:44:33 +05:30
MochaMind
7d4785784b fix: sync translations from crowdin (#49625) 2025-09-21 14:01:24 +02:00
MochaMind
35b503932d chore: update POT file (#49655) 2025-09-21 13:59:21 +02:00
venkat102
736a776d3d fix(accounts receivable): exclude employee transactions 2025-09-21 11:14:06 +05:30
venkat102
11b9b1adc5 fix(purchase order): get party type based on supplier field 2025-09-20 13:16:28 +05:30
venkat102
9f6bc7fe49 fix(purchase order): invoke superclass onload method 2025-09-20 13:07:57 +05:30
Mihir Kandoi
7e63f1d220 Merge pull request #49615 from aerele/fixed-support-48949
fix(stock): NoneType object error on stock entry
2025-09-18 20:16:40 +05:30
MochaMind
3d8502f408 fix: sync translations from crowdin (#49607) 2025-09-18 15:44:21 +02:00
ruthra kumar
c3e869c701 Merge pull request #49467 from aerele/qb-user-perm
fix: add condition for name
2025-09-18 16:41:16 +05:30
Kavin
aee03417de fix(stock): NoneType object error on stock entry 2025-09-18 16:31:07 +05:30
Diptanil Saha
14d8b87c8e Merge pull request #49608 from diptanilsaha/psoa_ar_show_future_payments
fix(process statement of accounts): total row in accounts receivable with future payments
2025-09-18 15:31:16 +05:30
rohitwaghchaure
2a86a1fb98 Merge pull request #49609 from rohitwaghchaure/fixed-drop-indexes-from-sle
fix: drop index batch_no_item_code_warehouse_index
2025-09-18 13:26:19 +05:30
Rohit Waghchaure
28180ccaa4 fix: drop index batch_no_item_code_warehouse_index 2025-09-18 13:08:26 +05:30
diptanilsaha
7bf17372b0 fix(process statement of accounts): total row in accounts receivable with future payments 2025-09-18 11:30:53 +05:30
venkat102
a5b881ea74 test: add test to validate user permission in qb 2025-09-18 00:02:10 +05:30
rohitwaghchaure
ac40b46a6d Merge pull request #49589 from rohitwaghchaure/fixed-op-cost-for-sfg
fix: operation cost for Semi FG item
2025-09-17 22:18:51 +05:30
Rohit Waghchaure
69682cb064 fix: operation cost for Semi FG item 2025-09-17 21:57:34 +05:30
Raheel Khan
8b543e5503 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
2025-09-17 13:06:00 +00:00
Diógenes Souza
c4f90c3b34 fix: 'NoneType' object has no attribute 'get' in get_item_details.py (#49381) 2025-09-17 18:05:49 +05:30
Anwar Patel
244dce5098 fix: Incorrect filters in Voucher Child Table of Land Cost Voucher DocType (#49500)
* fix: company filter in receipt_document in landed cost voucher

* refactor: use strict equality
2025-09-17 17:43:29 +05:30
Bhavansathru
194ab87fef 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
2025-09-17 17:04:02 +05:30
Logesh Periyasamy
e0299e1cbd fix: add option for currency field (#49572) 2025-09-17 17:01:53 +05:30
MochaMind
9c970acbda fix: sync translations from crowdin (#49581)
* fix: Norwegian Bokmal translations

* fix: French translations
2025-09-17 17:01:18 +05:30
rohitwaghchaure
06dde659c2 Merge pull request #49587 from rohitwaghchaure/fixed-support-48584
fix: incorrect current qty calculation for the batch
2025-09-17 17:00:23 +05:30
Logesh Periyasamy
9fc17e0e3a 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
2025-09-17 16:57:48 +05:30
Rohit Waghchaure
535f8657ed fix: incorrect current qty calculation for the batch 2025-09-17 16:33:26 +05:30
Diptanil Saha
c77781a14f Merge pull request #49584 from diptanilsaha/custom-print-format-psoa
feat(accounts): enable print format selection in Process Statement of Accounts
2025-09-17 12:19:04 +05:30
diptanilsaha
c9d22386ed fix: added print format validation on process statement of accounts 2025-09-17 11:42:36 +05:30
diptanilsaha
2e7c3207c4 feat(accounts): enable print format selection in Process Statement of Accounts 2025-09-17 11:23:44 +05:30
Diptanil Saha
0aef591f5d Merge pull request #49281 from diptanilsaha/reporting_currency
feat: adding reporting_currency and dr/cr in reporting currency fields in GL Entry and Account Closing Balance
2025-09-17 10:44:04 +05:30
rohitwaghchaure
39049948b8 Merge pull request #49558 from rohitwaghchaure/fixed-valuation-rate-issue
fix: set basic rate on selection of the batch
2025-09-16 12:55:04 +05:30
ruthra kumar
39b9d798d9 Merge pull request #49511 from aerele/sales-invoice-tax-id
fix(sales invoice): fetch tax id from customer
2025-09-16 12:01:33 +05:30
Rohit Waghchaure
bebb8ae1ea fix: set basic rate on selection of the batch 2025-09-16 11:57:43 +05:30
ruthra kumar
1c8266af39 Merge pull request #49557 from frappe/l10n_develop
fix: sync translations from crowdin
2025-09-16 10:17:44 +05:30
MochaMind
73729f6ab0 fix: French translations 2025-09-16 07:06:51 +05:30
MochaMind
a287201011 fix: Norwegian Bokmal translations 2025-09-16 07:06:45 +05:30
MochaMind
a4e2fbdcf9 fix: Persian translations 2025-09-16 07:06:34 +05:30
MochaMind
21dc0a0b1a fix: Swedish translations 2025-09-16 07:06:18 +05:30
MochaMind
98626aaa6c fix: Portuguese translations 2025-09-16 07:06:09 +05:30
MochaMind
86a8015cea fix: German translations 2025-09-16 07:05:56 +05:30
MochaMind
8330b349d2 fix: Danish translations 2025-09-16 07:05:53 +05:30
Diptanil Saha
29197af11a Merge pull request #49438 from pipech/fix-thai-fiscal-year
fix(acc): thai fiscal year
2025-09-16 00:50:30 +05:30
rohitwaghchaure
a00a3868ed Merge pull request #49549 from rohitwaghchaure/fixed-not-allow-backdated-entries
fix: do not allow backdated entries if stock reco exists in future for serial or batch
2025-09-15 15:40:42 +05:30
Rohit Waghchaure
335dcc976c fix: do not allow backdated entries if stock reco exists in future for serial or batch 2025-09-15 15:22:41 +05:30
Raffael Meyer
6972f161b8 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
2025-09-15 08:33:03 +02:00
Khushi Rawat
79b8505972 Merge pull request #49524 from KerollesFathy/fix-assets-movement-typos
fix: Assets Movement Typos
2025-09-15 11:54:56 +05:30
MochaMind
fe7b797e5f fix: sync translations from crowdin (#49550)
* fix: Spanish translations

* fix: Arabic translations

* fix: Czech translations

* fix: Danish translations

* fix: German translations

* fix: Hungarian translations

* fix: Italian translations

* fix: Dutch translations

* fix: Polish translations

* fix: Portuguese translations

* fix: Russian translations

* fix: Serbian (Cyrillic) translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Chinese Simplified translations

* fix: Vietnamese translations

* fix: Portuguese, Brazilian translations

* fix: Indonesian translations

* fix: Persian translations

* fix: Thai translations

* fix: Croatian translations

* fix: Bosnian translations

* fix: Norwegian Bokmal translations

* fix: Serbian (Latin) translations

* fix: French translations

* fix: Esperanto translations
2025-09-15 07:45:05 +02:00
ravibharathi656
df329964dd fix(sales invoice): fetch tax id from customer 2025-09-15 10:12:20 +05:30
MochaMind
1845d12951 Merge pull request #49532 from frappe/l10n_develop 2025-09-14 20:33:38 +02:00
Raffael Meyer
67c2ab4c9f Merge pull request #49546 from frappe/pot_develop_2025-09-14
chore: update POT file
2025-09-14 13:40:25 +02:00
frappe-pr-bot
405e1ab6d3 chore: update POT file 2025-09-14 09:35:06 +00:00
rohitwaghchaure
cf066edd7f Merge pull request #49542 from rohitwaghchaure/fixed-validation-place
fix: validation for document status
2025-09-14 12:26:43 +05:30
Rohit Waghchaure
96e2e356b6 fix: validation for document status 2025-09-14 11:55:08 +05:30
rohitwaghchaure
0fef2d4b02 Merge pull request #49539 from rohitwaghchaure/fixed-support-48168
fix: precision issue for valuation rate calculation
2025-09-14 11:51:03 +05:30
rohitwaghchaure
b265b82f0b Merge pull request #49538 from rohitwaghchaure/fixed-docstatus-issue-of-sabb
fix: SABB document status validation
2025-09-14 11:25:33 +05:30
Rohit Waghchaure
c92a06d77d fix: precision issue for valuation rate calculation 2025-09-14 11:22:14 +05:30
Rohit Waghchaure
c0236191aa fix: SABB document status validation 2025-09-14 10:53:38 +05:30
KerollesFathy
5f083d55b5 fix: correct grammatical errors in asset movement validation messages 2025-09-10 18:00:44 +00:00
KerollesFathy
56da3bd2e4 fix: correct typo in asset movement purpose validation 2025-09-10 17:57:30 +00:00
Raffael Meyer
f27077a45f Merge pull request #49505 from frappe/l10n_develop
fix: sync translations from crowdin
2025-09-10 17:08:15 +02:00
MochaMind
38b51df17e fix: Norwegian Bokmal translations 2025-09-10 06:21:56 +05:30
rohitwaghchaure
f145e6267b Merge pull request #49503 from rohitwaghchaure/feat-allow-to-transfer-additonal-materials
Feat allow to transfer additional materials
2025-09-09 14:13:24 +05:30
Sagar Vora
09d9c0ddd3 Merge pull request #49506 from sagarvora/extend-not-override
fix: use the new `extend_doctype_class` hook
2025-09-09 06:21:19 +00:00
Rohit Waghchaure
e4b5507446 test: test case for additional material transfer 2025-09-09 11:44:17 +05:30
Sagar Vora
a028d856bc fix: use the new extend_doctype_class hook 2025-09-09 11:34:49 +05:30
MochaMind
e3e4680ad2 fix: Norwegian Bokmal translations 2025-09-09 06:13:49 +05:30
MochaMind
276406bc1c fix: Danish translations 2025-09-09 06:13:46 +05:30
MochaMind
156e46ccb0 fix: Esperanto translations 2025-09-09 06:13:42 +05:30
MochaMind
07a5aba2aa fix: Dutch translations 2025-09-09 06:13:38 +05:30
MochaMind
4ce8d9af6a fix: Serbian (Latin) translations 2025-09-09 06:13:35 +05:30
MochaMind
0474b8595b fix: Bosnian translations 2025-09-09 06:13:32 +05:30
MochaMind
ca8677a0ff fix: Croatian translations 2025-09-09 06:13:28 +05:30
MochaMind
03e5467ba2 fix: Thai translations 2025-09-09 06:13:25 +05:30
MochaMind
e960f8217b fix: Persian translations 2025-09-09 06:13:21 +05:30
MochaMind
a81e807a70 fix: Indonesian translations 2025-09-09 06:13:17 +05:30
MochaMind
3b4ee30dd7 fix: Portuguese, Brazilian translations 2025-09-09 06:13:14 +05:30
MochaMind
521ebc25aa fix: Vietnamese translations 2025-09-09 06:13:11 +05:30
MochaMind
1291df9a63 fix: Chinese Simplified translations 2025-09-09 06:13:08 +05:30
MochaMind
70d7ceb2f2 fix: Turkish translations 2025-09-09 06:13:04 +05:30
MochaMind
512419eee7 fix: Swedish translations 2025-09-09 06:13:01 +05:30
MochaMind
c6be380e83 fix: Serbian (Cyrillic) translations 2025-09-09 06:12:57 +05:30
MochaMind
200496254b fix: Russian translations 2025-09-09 06:12:53 +05:30
MochaMind
2596ef202b fix: Portuguese translations 2025-09-09 06:12:50 +05:30
MochaMind
ac71969512 fix: Polish translations 2025-09-09 06:12:46 +05:30
MochaMind
734a7b8be9 fix: Italian translations 2025-09-09 06:12:43 +05:30
MochaMind
aa9c4555fd fix: Hungarian translations 2025-09-09 06:12:39 +05:30
MochaMind
7e5be50997 fix: German translations 2025-09-09 06:12:36 +05:30
MochaMind
03e3a693ff fix: Czech translations 2025-09-09 06:12:33 +05:30
MochaMind
d4ae2f89b2 fix: Arabic translations 2025-09-09 06:12:30 +05:30
MochaMind
17c24a4168 fix: Spanish translations 2025-09-09 06:12:26 +05:30
MochaMind
c41824c4d0 fix: French translations 2025-09-09 06:12:23 +05:30
Rohit Waghchaure
3ad611966e feat: allow to transfer additional materials 2025-09-08 20:54:43 +05:30
Raffael Meyer
ddc97df31a Merge pull request #49355 from frappe/l10n_develop 2025-09-08 06:59:23 +02:00
Raffael Meyer
c21ebafaa5 Merge pull request #49494 from frappe/pot_develop_2025-09-07 2025-09-08 06:58:57 +02:00
MochaMind
17276a2c0c fix: Norwegian Bokmal translations 2025-09-08 05:47:32 +05:30
MochaMind
4ecdd1fd0e fix: Danish translations 2025-09-08 05:47:29 +05:30
MochaMind
7e093d08a9 fix: Swedish translations 2025-09-08 05:46:59 +05:30
rohitwaghchaure
955e8714ee Merge pull request #49477 from rohitwaghchaure/fixed-batch-qty-calculation
fix: batch qty calculation performance issue
2025-09-07 16:49:07 +05:30
Rohit Waghchaure
1a262483a4 fix: batch qty calculation performance issue 2025-09-07 16:24:00 +05:30
frappe-pr-bot
eead27560c chore: update POT file 2025-09-07 09:35:18 +00:00
MochaMind
b658330881 fix: Norwegian Bokmal translations 2025-09-07 05:45:53 +05:30
MochaMind
4f968f5c65 fix: Danish translations 2025-09-07 05:45:50 +05:30
MochaMind
838183941a fix: Swedish translations 2025-09-07 05:45:46 +05:30
Diptanil Saha
92d86eb30b Merge pull request #49485 from diptanilsaha/skip_bank_ac_creation
fix: skip 'Bank Account' creation on setup
2025-09-06 13:13:24 +05:30
diptanilsaha
efeda90cad fix: renamed temporary bank account to 'Demo Bank Account' 2025-09-06 02:38:53 +05:30
diptanilsaha
47d4319f83 fix: skip 'Bank Account' creation on setup 2025-09-06 02:03:03 +05:30
MochaMind
eb5a9db749 fix: Norwegian Bokmal translations 2025-09-05 05:50:49 +05:30
MochaMind
a2ccb5fa87 fix: Hungarian translations 2025-09-05 05:50:45 +05:30
MochaMind
b56dbe98cf fix: German translations 2025-09-05 05:50:42 +05:30
venkat102
cf5a2d6351 fix: add condition for name 2025-09-04 21:00:52 +05:30
rohitwaghchaure
564de01463 Merge pull request #49453 from rohitwaghchaure/fixed-fifo-valuation-for-non-batchwise-valuation
fix: non batch-wise valuation for batch item
2025-09-04 14:30:17 +05:30
rohitwaghchaure
ac8637d5a0 chore: fix test case 2025-09-04 13:00:32 +05:30
MochaMind
7c10775bc8 fix: Norwegian Bokmal translations 2025-09-04 05:09:55 +05:30
MochaMind
49a96f4306 fix: Serbian (Latin) translations 2025-09-04 05:09:52 +05:30
MochaMind
161ed5290e fix: Serbian (Cyrillic) translations 2025-09-04 05:09:48 +05:30
MochaMind
a0d3b931f3 fix: Hungarian translations 2025-09-04 05:09:44 +05:30
Rohit Waghchaure
11b82ba008 fix: non batch-wise valuation for batch item 2025-09-04 00:48:45 +05:30
rohitwaghchaure
1b73170e8c Merge pull request #49449 from rohitwaghchaure/fixed-support-46728
fix: incorrect stock value in the report
2025-09-04 00:47:16 +05:30
rohitwaghchaure
59c46a1789 Merge pull request #49425 from rohitwaghchaure/fixed-valuation-for-batch
fix: valuation for batch items
2025-09-04 00:47:02 +05:30
Rohit Waghchaure
24e0e3505d fix: valuation for batch items 2025-09-03 19:20:56 +05:30
Rohit Waghchaure
5824b5effd fix: incorrect stock value in the report 2025-09-03 19:03:08 +05:30
rohitwaghchaure
fba16efc07 Merge pull request #49442 from rohitwaghchaure/fixed-incorrect-batch-qty-issue
fix: incorrect batch qty
2025-09-03 16:42:09 +05:30
Mihir Kandoi
9aeb21d0c8 Merge pull request #49441 from mihir-kandoi/fix-wrong-wh-sre-transfer
fix: incorrect warehouse passed during SRE transfer in WO
2025-09-03 16:14:38 +05:30
Rohit Waghchaure
000135a3d4 fix: incorrect batch qty 2025-09-03 16:04:13 +05:30
Mihir Kandoi
260574719e fix: incorect warehouse passed during SRE transfer in WO 2025-09-03 15:53:53 +05:30
Mihir Kandoi
ead1ce2742 Merge pull request #49437 from mihir-kandoi/refactor-49320
refactor: PR 49320
2025-09-03 14:20:29 +05:30
Mihir Kandoi
991413608b refactor: PR 49320 2025-09-03 13:07:08 +05:30
pipech
fe74e0888b fix: thai fiscal year 2025-09-03 14:27:02 +07:00
diptanilsaha
ceff8c92fd fix: used wrong parameter for get_value to fetch previous fiscal year 2025-09-03 12:36:44 +05:30
diptanilsaha
d8babf66ae feat: add patch to set reporting_currency on GL Entry and Account Closing Balance 2025-09-03 12:36:44 +05:30
diptanilsaha
8dbbcf5ffb feat: dr/cr amounts in reporting_currency on account_closing_balance 2025-09-03 12:36:44 +05:30
diptanilsaha
fab9c4d7df feat: dr/cr amounts in reporting_currency on gl entries 2025-09-03 12:36:44 +05:30
diptanilsaha
2383051b74 feat: reporting_currency on company 2025-09-03 12:36:39 +05:30
MochaMind
d2d3294f02 fix: Norwegian Bokmal translations 2025-09-03 05:05:41 +05:30
MochaMind
62037301ee fix: Serbian (Latin) translations 2025-09-03 05:05:38 +05:30
MochaMind
b860f3d31d fix: Serbian (Cyrillic) translations 2025-09-03 05:05:34 +05:30
MochaMind
b8c72c05bb fix: Hungarian translations 2025-09-03 05:05:28 +05:30
Raffael Meyer
f1eda7c4ec Merge pull request #49374 from MarcCon/fix/ignore-permissions 2025-09-02 19:19:27 +02:00
Raffael Meyer
83eafe118e Merge pull request #49432 from barredterra/use-valid-ibans 2025-09-02 19:15:39 +02:00
barredterra
0b178b9449 test: use valid IBANs in party matching test case 2025-09-02 17:41:29 +02:00
ruthra kumar
1e7f374d6e Merge pull request #49306 from aerele/exchange-rate-revaluation-check-gain-loss
fix(exchange rate revaluation): add check for gain_loss
2025-09-02 13:33:55 +05:30
ruthra kumar
fcb86023cb Merge pull request #49332 from aerele/ticket-47028
perf: check PCV (smaller) table before checking GL Entries
2025-09-02 13:16:05 +05:30
Diptanil Saha
2dba591d37 Merge pull request #49407 from diptanilsaha/force_index_fetch_gle
fix(perf): applying consistent index to fetch gl entries for financial statements
2025-09-02 12:11:48 +05:30
ruthra kumar
385a2beaf9 Merge pull request #49379 from aerele/balance-type
fix: add is_cancelled in condition
2025-09-02 10:56:32 +05:30
MochaMind
cc2cc812cc fix: Norwegian Bokmal translations 2025-09-02 05:07:26 +05:30
MochaMind
a1c3c60fca fix: Danish translations 2025-09-02 05:07:23 +05:30
MochaMind
bbbd693c1c fix: Serbian (Latin) translations 2025-09-02 05:07:19 +05:30
MochaMind
f42f59a6b2 fix: Serbian (Cyrillic) translations 2025-09-02 05:07:16 +05:30
MochaMind
886cec797c fix: Hungarian translations 2025-09-02 05:07:10 +05:30
Raffael Meyer
2ea2c5c11e Merge pull request #49377 from barredterra/iban-options 2025-09-01 15:16:13 +02:00
ruthra kumar
b0f59ebf79 Merge pull request #49366 from aerele/tb-simple
fix(trial-balance-simple): ignore cancelled gl and add company filter
2025-09-01 16:45:38 +05:30
rohitwaghchaure
35fee187b6 Merge pull request #49403 from rohitwaghchaure/fixed-support-47626
fix: validation for Recreate Stock Ledgers
2025-09-01 16:12:10 +05:30
diptanilsaha
3e2fb85ae6 fix(perf): applying consistent index to fetch gl entries for financial statements 2025-09-01 15:15:42 +05:30
ruthra kumar
0cb5b571b0 Merge pull request #49335 from aerele/ticket-47331
fix: show company currency symbol
2025-09-01 15:06:10 +05:30
ruthra kumar
3131cf335e Merge pull request #49331 from aerele/patch-sync-auto-reconcile-config
fix: run sync auto reconcile config with force
2025-09-01 14:41:56 +05:30
Rohit Waghchaure
785845a425 fix: validation for Recreate Stock Ledgers 2025-09-01 13:39:35 +05:30
ruthra kumar
fa3ee91414 Merge pull request #49302 from aerele/fix/budget-warning
fix(budget):  fiscal year assignment and approver role in budget
2025-09-01 12:34:07 +05:30
MochaMind
f8fa8bdda7 fix: Norwegian Bokmal translations 2025-09-01 04:54:02 +05:30
MochaMind
69d509a098 fix: Danish translations 2025-09-01 04:53:59 +05:30
MochaMind
5a9fb3db1f fix: Esperanto translations 2025-09-01 04:53:56 +05:30
MochaMind
8c8bfd4277 fix: Dutch translations 2025-09-01 04:53:53 +05:30
MochaMind
47f0507643 fix: Serbian (Latin) translations 2025-09-01 04:53:50 +05:30
MochaMind
cb68c784fe fix: Bosnian translations 2025-09-01 04:53:47 +05:30
MochaMind
b1d3d39a11 fix: Croatian translations 2025-09-01 04:53:43 +05:30
MochaMind
31d9fc5367 fix: Thai translations 2025-09-01 04:53:40 +05:30
MochaMind
80a38732f9 fix: Persian translations 2025-09-01 04:53:37 +05:30
MochaMind
c228d1a05a fix: Indonesian translations 2025-09-01 04:53:33 +05:30
MochaMind
6bbba727a5 fix: Portuguese, Brazilian translations 2025-09-01 04:53:30 +05:30
MochaMind
0149bc633c fix: Vietnamese translations 2025-09-01 04:53:28 +05:30
MochaMind
574198bceb fix: Chinese Simplified translations 2025-09-01 04:53:24 +05:30
MochaMind
edd3383f7d fix: Turkish translations 2025-09-01 04:53:21 +05:30
MochaMind
2384b37305 fix: Swedish translations 2025-09-01 04:53:18 +05:30
MochaMind
c71dd00cc3 fix: Serbian (Cyrillic) translations 2025-09-01 04:53:14 +05:30
MochaMind
bd18ce7326 fix: Russian translations 2025-09-01 04:53:11 +05:30
MochaMind
9a85e1a811 fix: Portuguese translations 2025-09-01 04:53:08 +05:30
MochaMind
ad1b77f280 fix: Polish translations 2025-09-01 04:53:05 +05:30
MochaMind
99d89b207e fix: Italian translations 2025-09-01 04:53:02 +05:30
MochaMind
66f60c64bd fix: Hungarian translations 2025-09-01 04:52:58 +05:30
MochaMind
9f8abd585a fix: German translations 2025-09-01 04:52:55 +05:30
MochaMind
1f937a7c76 fix: Czech translations 2025-09-01 04:52:52 +05:30
MochaMind
9234e27a70 fix: Arabic translations 2025-09-01 04:52:49 +05:30
MochaMind
6ba476a3cd fix: Spanish translations 2025-09-01 04:52:46 +05:30
MochaMind
5f4c1f331d fix: French translations 2025-09-01 04:52:43 +05:30
MochaMind
c95b8e8d30 chore: update POT file (#49396) 2025-08-31 14:05:57 +02:00
Mihir Kandoi
b1d91f429c Merge pull request #49394 from fawaaaz111/patch-1
chore: remove unused import (Order) module
2025-08-31 13:19:47 +05:30
Fawaz Alhafiz
4e86a46008 chore: remove unused import (Order) module 2025-08-31 09:43:01 +03:00
MochaMind
0ad348d714 fix: Bosnian translations 2025-08-31 04:28:37 +05:30
MochaMind
7f1240e2eb fix: Croatian translations 2025-08-31 04:28:34 +05:30
MochaMind
6806c5e977 fix: Swedish translations 2025-08-31 04:28:31 +05:30
Mihir Kandoi
4bdb4fb170 fix(repost item valuation): validate voucher type in transaction (#49388) 2025-08-30 23:25:24 +05:30
rohitwaghchaure
06a999ebaa Merge pull request #49386 from rohitwaghchaure/fixed-support-47111
fix: Issue with Barcode Scanning in Stock Entry
2025-08-30 12:35:55 +05:30
ravibharathi656
5663c2a1ca fix(repost item valuation): validate voucher type in transaction 2025-08-29 23:27:14 +05:30
Rohit Waghchaure
13e3db3730 fix: Issue with Barcode Scanning in Stock Entry 2025-08-29 23:11:16 +05:30
rohitwaghchaure
bba77529f8 Merge pull request #49376 from aerele/reorder-repost-item-valuation-function
fix(repost item valuation): reorder function call
2025-08-29 22:21:28 +05:30
Raffael Meyer
625321ba8a fix: stop creating transaction logs (#49383) 2025-08-29 15:33:07 +00:00
barredterra
4dd428de41 chore(Bank Account): remove IBAN validation
This is now handled by the Frappe Framework.
2025-08-29 15:23:13 +02:00
Diptanil Saha
9ece6ebef8 Merge pull request #49373 from diptanilsaha/psoa_ar_future_payments
feat(Process Statment of Accounts): added show_future_payments filter for account_receivable report type
2025-08-29 18:02:26 +05:30
diptanilsaha
155bdd0251 refactor: renamed variables 2025-08-29 17:35:31 +05:30
l0gesh29
77a9cf6398 fix: add is_cancelled in condition 2025-08-29 16:30:29 +05:30
barredterra
c45ea53889 fix(Bank Account): length of IBAN field 2025-08-29 12:32:29 +02:00
ravibharathi656
d117411070 chore: remove console log 2025-08-29 15:31:47 +05:30
barredterra
cab262c147 feat: set options for IBAN fields
Sets options to "IBAN" for the respective Data fields to take advantage of a new formatting feature provided by the  Frappe Framework.
2025-08-29 11:56:42 +02:00
ravibharathi656
aaa4f0ae26 fix(repost item valuation): reorder function call 2025-08-29 14:56:29 +05:30
Marc-Constantin Enke
00fd1d2f26 feat: add permission check for custom button 2025-08-29 11:09:22 +02:00
Marc-Constantin Enke
7f55f421ab fix: remove ignore_permissions 2025-08-29 11:07:37 +02:00
diptanilsaha
170fe86f38 feat(Process Statment of Accounts): added show_future_payments filter for account_receivable report type 2025-08-29 13:34:03 +05:30
MochaMind
781c377588 fix: Norwegian Bokmal translations 2025-08-29 03:50:30 +05:30
MochaMind
7318c6007d fix: Danish translations 2025-08-29 03:50:27 +05:30
jll-02
aedb171dd4 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>
2025-08-28 23:37:42 +05:30
Anwar Patel
1fbde7b8c6 Merge pull request #49289 from anwarpatelnoori/stage
fix: Company currency label is not displayed in Landed Cost Voucher doctype for the field Total Vendor Invoices Cost
2025-08-28 23:36:38 +05:30
ravibharathi656
e8288a2f63 fix: run config with force 2025-08-28 19:41:13 +05:30
l0gesh29
afb067ce50 fix: ignore cancelled gl and add company filter 2025-08-28 19:16:10 +05:30
rohitwaghchaure
0c400f9355 Merge pull request #49345 from rohitwaghchaure/fxied-minor-fixes-08-27
chore: minor fixes
2025-08-28 07:35:29 +05:30
MochaMind
e36cc5641c fix: Norwegian Bokmal translations 2025-08-28 03:55:18 +05:30
MochaMind
a98eb60a27 fix: Danish translations 2025-08-28 03:55:14 +05:30
Mihir Kandoi
147e99a0cc Merge pull request #49308 from lauty95/settings_workspace
Removing Newsletter from Settings Workspace
2025-08-27 22:17:52 +05:30
Mihir Kandoi
b38b2d2283 fix: show create purchase receipt button in purchase invoice only when update stock is not checked (#49254)
fix: show create purchase receipt button only when update stock is not checked
2025-08-27 22:09:22 +05:30
Khushi Rawat
e065794838 Merge pull request #49190 from KerollesFathy/prevent-negative-repair-cost
fix: add non-negative constraint to Repair Cost field
2025-08-27 22:08:10 +05:30
Mihir Kandoi
903194abed Merge pull request #49244 from elshafei-developer/fix-convert-NaN-to-numerical-in-number_card
fix: convert NaN to numerical
2025-08-27 22:06:00 +05:30
0xD0M1M0
2bf0ba9802 feat: optional fixed outgoing email for RfQ (#49258)
* feat: optional fixed outgoing email for RfQ

* fix: linters

* fix: select only outgoing account

* fix: linters
2025-08-27 22:01:54 +05:30
Rohit Waghchaure
39ec44f169 chore: minor fixes 2025-08-27 19:39:59 +05:30
Raffael Meyer
e1cac75f85 fix: add option to disable Transaction Log (#49342) 2025-08-27 11:44:03 +00:00
MochaMind
5e9e95e00b fix: sync translations from crowdin (#49339) 2025-08-27 00:10:31 +02:00
rohitwaghchaure
58d9113fd6 Merge pull request #49320 from mihir-kandoi/fix-swh-scrap-reqd
fix: source warehouse in manufacture entry and reqd prop of scrap warehouse
2025-08-26 21:30:03 +05:30
Navin-S-R
49bb095152 fix: show company currency symbol 2025-08-26 20:29:24 +05:30
rohitwaghchaure
2f4caf755e Merge pull request #49333 from rohitwaghchaure/fixed-stock-reservation-issue
fix: validation issue for reserved batch
2025-08-26 19:47:44 +05:30
Rohit Waghchaure
f38abe38d7 fix: validation issue for reserved batch 2025-08-26 19:20:34 +05:30
Mihir Kandoi
fe0722c4f1 fix: source warehouse in manufacture entry and reqd prop of scrap warehouse 2025-08-26 17:34:30 +05:30
ruthra kumar
c585903a4a Merge pull request #49236 from aerele/immutable-ledger-ple
fix: handle ple for immutable ledger
2025-08-26 16:03:44 +05:30
l0gesh29
48eb488918 fix: handle ple for immutable ledger 2025-08-26 15:48:03 +05:30
Khushi Rawat
68e1f9d4b0 Merge pull request #49319 from khushi8112/set-value-for-asset-owner-company
fix: set value for asset owner company field
2025-08-26 14:36:01 +05:30
khushi8112
a24f1d056b fix: set value for asset owner company field 2025-08-26 12:35:37 +05:30
ruthra kumar
0b0365d559 Merge pull request #49316 from frappe/l10n_develop
fix: sync translations from crowdin
2025-08-26 11:05:09 +05:30
MochaMind
3401438878 fix: Persian translations 2025-08-26 03:12:01 +05:30
rohitwaghchaure
00ea513546 Merge pull request #48875 from aerele/sales-order-to-sales-invoice-item-quantity
fix: incorrect pending qty when creating sales invoice from sales order
2025-08-26 01:08:00 +05:30
Sagar Vora
4bf3a73b50 Merge pull request #49312 from sagarvora/fix-pick-list-scanning 2025-08-25 19:07:43 +00:00
Sagar Vora
72a38929e5 fix: correct logic for warehouse field label 2025-08-26 00:29:26 +05:30
Vignesh Sekar
4d3ddeae8d perf: check PCV (smaller) table before checking GL Entries 2025-08-26 00:14:15 +05:30
Sagar Vora
4005e4412d fix: match warehouse only when last_scanned_warehouse field exists 2025-08-26 00:10:16 +05:30
rohitwaghchaure
470efbeaf5 Merge pull request #49310 from rohitwaghchaure/fixed-sre-issues
fix: SRE status and delivered qty
2025-08-25 23:50:52 +05:30
ravibharathi656
368dbe3bbf chore: remove update_stock 2025-08-25 21:23:14 +05:30
ravibharathi656
e5affb16c7 fix(exchange rate revaluation): add check for gain_loss 2025-08-25 21:12:26 +05:30
ravibharathi656
e5d4b4f0f0 test: add pending quantity check for invoice creation 2025-08-25 21:05:12 +05:30
ravibharathi656
a5138f4899 fix: incorrect pending qty when creating sales invoice from sales order 2025-08-25 21:05:11 +05:30
Rohit Waghchaure
4cac80a968 fix: sre status and delivered qty 2025-08-25 21:00:08 +05:30
Lautaro Juarez
f74d8439a1 removing newsletter from workspace 2025-08-25 10:55:35 -03:00
ruthra kumar
fa182395f6 Merge pull request #49301 from aerele/fix/set-valid-naming-series-in-test
fix: set valid serial no naming series format
2025-08-25 17:21:48 +05:30
ruthra kumar
ed84d33b28 Merge pull request #49296 from emmanuel-mwendwa/fix/monthly-err-filter
fix(accounts): correct typo in monthly auto exchange rate revaluation filter
2025-08-25 17:07:05 +05:30
Bhavan23
770d6dd8e2 fix(budget): always set fiscal year before fetching company approver role 2025-08-25 11:14:44 +00:00
Kavin
46b85c7857 fix: set valid serial no naming series format 2025-08-25 16:37:59 +05:30
ruthra kumar
626be61218 Merge pull request #49252 from aerele/dr/cr-posting-date
feat(payment-reconciliation): add posting date field for debit/credit…
2025-08-25 16:08:40 +05:30
Diptanil Saha
9a5348b0e0 Merge pull request #49297 from diptanilsaha/test-sabb-serial-no
test: fix naming series for serial no on test_serial_no_valuation_for_legacy_ledgers
2025-08-25 15:28:39 +05:30
diptanilsaha
5ebd7d72fc test: fix naming series for serial no on test_serial_no_valuation_for_legacy_ledgers 2025-08-25 15:10:03 +05:30
ruthra kumar
a3bd10f6c6 Merge pull request #49295 from frappe/l10n_develop
fix: sync translations from crowdin
2025-08-25 11:00:56 +05:30
CoiledCoder
15040a362d 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
2025-08-25 03:35:55 +00:00
CoiledCoder
19729a307f 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.
2025-08-25 02:07:05 +00:00
MochaMind
42710f9ba1 fix: Esperanto translations 2025-08-25 02:16:10 +05:30
MochaMind
b2e94ed29d fix: Dutch translations 2025-08-25 02:16:06 +05:30
MochaMind
6908101735 fix: Serbian (Latin) translations 2025-08-25 02:16:03 +05:30
MochaMind
d211641ce2 fix: Bosnian translations 2025-08-25 02:16:00 +05:30
MochaMind
c3bca6ed60 fix: Croatian translations 2025-08-25 02:15:57 +05:30
MochaMind
9423f37e12 fix: Thai translations 2025-08-25 02:15:54 +05:30
MochaMind
c93da6cbbc fix: Persian translations 2025-08-25 02:15:51 +05:30
MochaMind
709ae67b3f fix: Indonesian translations 2025-08-25 02:15:48 +05:30
MochaMind
efad850ef3 fix: Portuguese, Brazilian translations 2025-08-25 02:15:44 +05:30
MochaMind
622eafdcc0 fix: Vietnamese translations 2025-08-25 02:15:41 +05:30
MochaMind
5cddf86c7c fix: Chinese Simplified translations 2025-08-25 02:15:38 +05:30
MochaMind
28931bd49a fix: Turkish translations 2025-08-25 02:15:34 +05:30
MochaMind
61360fa813 fix: Swedish translations 2025-08-25 02:15:31 +05:30
MochaMind
a41f6c7fcd fix: Serbian (Cyrillic) translations 2025-08-25 02:15:28 +05:30
MochaMind
22aa830f53 fix: Russian translations 2025-08-25 02:15:25 +05:30
MochaMind
5aaf1501a2 fix: Portuguese translations 2025-08-25 02:15:22 +05:30
MochaMind
6781c69d33 fix: Polish translations 2025-08-25 02:15:18 +05:30
MochaMind
9a1f033fb4 fix: Italian translations 2025-08-25 02:15:15 +05:30
MochaMind
259c74eb3a fix: Hungarian translations 2025-08-25 02:15:12 +05:30
MochaMind
b107cf7d03 fix: German translations 2025-08-25 02:15:09 +05:30
MochaMind
97b0985261 fix: Czech translations 2025-08-25 02:15:06 +05:30
MochaMind
055b1c3bdc fix: Arabic translations 2025-08-25 02:15:03 +05:30
MochaMind
fa0856de8b fix: Spanish translations 2025-08-25 02:14:59 +05:30
MochaMind
db1d77269a fix: French translations 2025-08-25 02:14:56 +05:30
MochaMind
44634cde63 chore: update POT file (#49292) 2025-08-24 15:32:02 +02:00
Raffael Meyer
eabf69ea00 Merge pull request #49285 from barredterra/create-pricing-rule 2025-08-22 20:01:18 +02:00
barredterra
7bc508004b chore!: remove unused utils 2025-08-22 19:44:14 +02:00
barredterra
831dfc8f6d perf: create Pricing Rule from Customer and Supplier 2025-08-22 19:44:14 +02:00
mergify[bot]
7435b28092 fix(Supplier): add make_method for Pricing Rule (backport #49282) (#49284)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-08-22 19:38:12 +02:00
Raffael Meyer
34584cd8f8 refactor!: remove whitelisted method make_bank_account (#49001) 2025-08-22 16:15:19 +00:00
MochaMind
677a5e829e fix: sync translations from crowdin (#49238) 2025-08-22 12:04:33 +02:00
Raffael Meyer
d1f8105abf ci: make coderabbit less chatty (#49203)
* ci: make coderabbit less chatty

* ci: disable high level summary

* ci: disable reviews on style PRs

* ci: fake tests on ignored paths

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Ankush Menat <ankush@frappe.io>
2025-08-22 03:37:31 +00:00
Raffael Meyer
c54ccc56c7 feat: add make methods for Bank Account (#49000)
* perf(make_bank_account): remove useless roundtrip to server

* feat: add make methods for Bank Account

Auto-fill Party Type and Party when creating a Bank Account from Customer, Supplier or Employee.
2025-08-22 01:09:47 +02:00
Mihir Kandoi
e909fd352a Merge pull request #49050 from mihir-kandoi/48873
fix: ensure variant conversion factor is returned before the template's
2025-08-22 00:23:52 +05:30
rohitwaghchaure
916ed3d6aa Merge pull request #49269 from rohitwaghchaure/fixed-github-49237
fix: Serial Nos popup only appears 1 time
2025-08-21 23:28:10 +05:30
Rohit Waghchaure
5503d4b05b fix: Serial Nos popup only appears 1 time 2025-08-21 23:24:35 +05:30
Hussain Nagaria
a5f200636a feat: show title in link field for Project DocType (#49265) 2025-08-21 12:47:06 +00:00
KerollesFathy
673bb99573 Merge branch 'develop' into prevent-negative-repair-cost 2025-08-20 22:58:19 +00:00
rohitwaghchaure
d64cd86f52 Merge pull request #49255 from rohitwaghchaure/fixed-github-49034
fix: sub-operation not working
2025-08-20 22:55:24 +05:30
rohitwaghchaure
3ddd5bb65a Merge pull request #49243 from aerele/transaction-cumulative
fix: hide is_cumulative for apply_on is set to Transaction
2025-08-20 22:54:32 +05:30
Rohit Waghchaure
876598f714 fix: sub-operation not working 2025-08-20 22:19:03 +05:30
anwarpatelnoori
ed550bb633 fix: show create purchase receipt button only when update stock is not checked 2025-08-20 14:18:35 +00:00
l0gesh29
6b4004b127 feat(payment-reconciliation): add posting date field for debit/credit note auto jv creation 2025-08-20 19:25:38 +05:30
Mihir Kandoi
96feae60da Merge pull request #49250 from mihir-kandoi/fix-child-item-picker-pr-pi
fix: child item picker picking all items when creating PI from PR
2025-08-20 17:48:04 +05:30
rohitwaghchaure
fb1bf29136 Merge pull request #49249 from rohitwaghchaure/fixed-stock-reservation
fix: stock reservation
2025-08-20 17:21:51 +05:30
Mihir Kandoi
738c1e0d0a fix: child item picker picking all items when creating PI from PR 2025-08-20 17:20:03 +05:30
Rohit Waghchaure
19b64d4b0f fix: stock reservation 2025-08-20 16:58:13 +05:30
Kavin
67e57018bc Merge pull request #49183 from aerele/fix/mr-status-from-wo
Fix/mr status from wo
2025-08-20 15:12:18 +05:30
El-Shafei H.
fac8013dba fix: convert NaN to numerical 2025-08-20 10:15:27 +03:00
Diptanil Saha
3c6b2a7c03 Merge pull request #49235 from barredterra/prty
style: format controllers with prettier
2025-08-20 12:03:38 +05:30
Navin-S-R
699d42b26c fix: hide is_cumulative for apply_on is set to Transaction 2025-08-20 11:56:13 +05:30
barredterra
1cdf32d807 style: format controllers with prettier 2025-08-19 15:43:35 +02:00
barredterra
a0f23339cc ci: update pre-commit config 2025-08-19 15:43:24 +02:00
Raffael Meyer
77478303fe fix: set missing due date in Purchase Invoice and POS Invoice (#49232) 2025-08-19 14:29:59 +02:00
rohitwaghchaure
3f354b78dc Merge pull request #49228 from rohitwaghchaure/fixed-set-default-company
fix: company issue in setup wizard
2025-08-19 16:21:22 +05:30
rohitwaghchaure
c7a2a26f50 Merge pull request #49223 from aerele/fix/putaway-rule-in-se
fix(stock): don't override t_warehouse if no rules found
2025-08-19 16:08:01 +05:30
Rohit Waghchaure
1fb0d1460a fix: company issue in setup wizard 2025-08-19 16:02:54 +05:30
rohitwaghchaure
acab260762 Merge pull request #49213 from rohitwaghchaure/feat-workstation-operating-component
refactor: workstation operating component
2025-08-19 14:26:21 +05:30
ruthra kumar
a7ec036d95 Merge pull request #49121 from rehanrehman389/je-reversal-duplicate
fix: prevent duplicate reverse Journal Entry
2025-08-19 14:10:07 +05:30
ruthra kumar
bb2236ba85 Merge pull request #49102 from aerele/duplicate-quotation-currency
fix(quotation): update currency on duplicate
2025-08-19 14:04:04 +05:30
Kavin
66f217c8e6 fix(stock): don't override t_warehouse if no rules found 2025-08-19 13:46:41 +05:30
Rohit Waghchaure
7cd0db219a refactor: workstation operating component 2025-08-19 13:29:32 +05:30
Logesh Periyasamy
d656e02441 Merge pull request #49185 from aerele/mop-sales-register
fix: handle mode of payment filter
2025-08-19 12:02:31 +05:30
ruthra kumar
67d3ad47d7 Merge pull request #49055 from aerele/accounting-dimension-filer-fieldname
fix: fetch fieldname in accounting dimension filter
2025-08-19 10:48:09 +05:30
ruthra kumar
4ec2e16b98 Merge pull request #49192 from diptanilsaha/sql_qb
fix: improve queries with query builder and input sanitization
2025-08-19 10:30:13 +05:30
rohitwaghchaure
645abe0c77 Merge pull request #49216 from aerele/pick-list-update-warehouse-property
fix(pick list): update warehouse property on refresh
2025-08-19 10:27:37 +05:30
ruthra kumar
e623b262ab Merge pull request #49214 from frappe/l10n_develop
fix: sync translations from crowdin
2025-08-19 10:11:55 +05:30
ravibharathi656
5472ff4ac3 fix(pick list): update warehouse property on refresh 2025-08-19 08:29:48 +05:30
Khushi Rawat
f377c94b64 Merge pull request #49141 from khushi8112/consider-asset-value-adjustments-in-report
refactor: consider asset value adjustments in report
2025-08-19 02:57:23 +05:30
MochaMind
6b7ceb92fa fix: Persian translations 2025-08-19 00:24:00 +05:30
MochaMind
9a15f4fc8d fix: Italian translations 2025-08-19 00:23:28 +05:30
Diptanil Saha
fc9fa2a7f8 Merge pull request #49211 from diptanilsaha/paid_amount_gt_mop
fix: prevent auto-setting payment amount if set_grand_total_to_default_mop is disabled
2025-08-18 17:32:59 +05:30
diptanilsaha
b617b5aa20 fix: prevent auto-setting payment amounts if set_grand_total_to_default_mop is disabled 2025-08-18 17:17:35 +05:30
ruthra kumar
15006c27cc Merge pull request #49206 from akhilnarang/update-codeowners
chore(codeowners): set ruthra for pyproject.toml
2025-08-18 16:31:46 +05:30
Sagar Vora
bd3892982f fix: update dunning status based on credit notes (#49066)
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
2025-08-18 10:47:15 +00:00
Karm Soni
53520af2fd test: update test data for internal customer and supplier 2025-08-18 15:48:43 +05:30
Diptanil Saha
5ff508de2c Merge pull request #49205 from diptanilsaha/gt_default_mop
fix: apply grand total to default payment mode in Sales and POS invoices
2025-08-18 15:12:18 +05:30
Karm Soni
059c541875 fix: update payment schedule then make gl entries 2025-08-18 14:57:41 +05:30
Sagar Vora
d959ca1694 fix: handle dunning status change on all changes to outstanding amount 2025-08-18 14:57:41 +05:30
Sagar Vora
fe2d0ea43b refactor: commonify and improve perf 2025-08-18 14:57:41 +05:30
Karm Soni
6c644dd5d2 refactor: combine the return conditions 2025-08-18 14:57:41 +05:30
Karm Soni
b304c1d079 feat: add dunning resolution for credit notes and update hooks 2025-08-18 14:57:40 +05:30
Diptanil Saha
8cf672d878 Merge pull request #49169 from aerele/asset-make-journal-entry
fix(asset): prevent translation function shadowing in make_journal_entry
2025-08-18 14:55:39 +05:30
diptanilsaha
9aa7f87a27 fix: apply grand total to default payment mode in Sales and POS invoices 2025-08-18 14:47:43 +05:30
Akhil Narang
692c848154 chore(codeowners): set ruthra for pyproject.toml
Not sure why I was here tbh

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2025-08-18 13:54:43 +05:30
rohitwaghchaure
4378be45e4 Merge pull request #49182 from aerele/item-searchfield-report
fix: handle all searchfields in items
2025-08-18 09:29:23 +05:30
rohitwaghchaure
dbb8c34486 Merge pull request #49186 from mihir-kandoi/reserve-extra-items-during-sre-transfer
fix: reserve extra items during SRE transfer
2025-08-18 09:26:20 +05:30
MochaMind
0933701f55 fix: sync translations from crowdin (#49202) 2025-08-17 20:43:53 +02:00
Raffael Meyer
5bd45b5a42 fix: ignore links in Dunning patch (#49201) 2025-08-17 20:36:16 +02:00
Raffael Meyer
48ff8175eb ci: disable coderabbit status comment (#49173) 2025-08-17 12:55:26 +02:00
MochaMind
8d4562d071 chore: update POT file (#49198) 2025-08-17 12:54:29 +02:00
rohitwaghchaure
334c17f8ab Merge pull request #49193 from rohitwaghchaure/fixed-support-45657
fix: additional cost not consider in valuation rate for Stock Entry transfer
2025-08-17 10:51:42 +05:30
Rohit Waghchaure
bbc772abe7 fix: additional cost not consider in valuation rate for Stock Entry transfer 2025-08-17 10:34:33 +05:30
diptanilsaha
1231ca17c9 fix: handle empty loyalty point details 2025-08-16 23:48:10 +05:30
diptanilsaha
e563ed0c75 fix: use query builder instead of raw SQL in get_timesheet_detail_rate 2025-08-16 23:08:29 +05:30
diptanilsaha
7f2a52ff71 fix: use query builder instead of raw SQL in get_rfq_containing_supplier 2025-08-16 23:08:12 +05:30
diptanilsaha
7fa4ed6139 fix: use query builder instead of raw SQL in unset_existing_data 2025-08-16 23:07:26 +05:30
diptanilsaha
eb22794f14 fix: sanitize column name for inventory_dimensions in get_stock_balance 2025-08-16 23:07:26 +05:30
diptanilsaha
1db135262d fix: use query builder instead of raw SQL in get_blanket_orders 2025-08-16 23:07:12 +05:30
diptanilsaha
6320f7290f fix: formatted string for disabled filter in get_income_account 2025-08-16 23:07:11 +05:30
diptanilsaha
de919568b4 fix: use query builder instead of raw SQL in get_material_requests_based_on_supplier 2025-08-16 23:06:57 +05:30
diptanilsaha
8696ba2f5d fix: use query builder instead of raw SQL in get_loyalty_details 2025-08-16 23:06:11 +05:30
KerollesFathy
c140596ab3 fix: add non-negative constraint to Repair Cost field 2025-08-16 13:42:45 +00:00
Mihir Kandoi
bba72e9b2f fix: reserve extra items during SRE transfer 2025-08-16 13:09:33 +05:30
ravibharathi656
ad559c3491 fix: handle all searchfields in items 2025-08-15 10:02:54 +05:30
divyalekha99
078b8439d9 fix: wrap inter-company order button labels in __() for translation (#49178)
* Updated purchase_order.js

* Update sales_order.js
2025-08-14 20:28:51 +05:30
Diptanil Saha
0b475aa13e Merge pull request #49108 from LewisMojica/develop
fix(pos): include Product Bundle components in reserved qty to preven…
2025-08-14 18:47:26 +05:30
Diptanil Saha
734880f314 Merge pull request #49163 from diptanilsaha/fix-product-bundle-qty
fix: product bundle child item quantity should be a positive number
2025-08-14 18:46:23 +05:30
barredterra
cff2629131 ci: skip patch and server tests for unrelated config changes 2025-08-14 14:52:15 +02:00
MochaMind
667213e52b fix: sync translations from crowdin (#49152) 2025-08-14 14:32:57 +02:00
barredterra
f0c9b3852f ci: disable coderabbit status comment
Disables this kind of comment: https://github.com/frappe/erpnext/pull/49152#issuecomment-3184835491
2025-08-14 14:30:36 +02:00
l0gesh29
5e82de1b71 fix(asset): prevent translation function shadowing in make_journal_entry 2025-08-14 16:25:53 +05:30
Sagar Vora
29ca1a1f40 chore: remove stale type hint 2025-08-14 13:06:31 +05:30
Sagar Vora
eb5946fa99 Merge pull request #49165 from karm1000/remove-last-scanned-warehouse-from-python 2025-08-14 07:00:45 +00:00
Sagar Vora
2fc39859ad Merge pull request #49164 from karm1000/reorder-last-scanned-warehouse-in-si 2025-08-14 06:39:45 +00:00
Karm Soni
58322c271b refactor: remove last_scanned_warehouse field from python 2025-08-14 12:01:45 +05:30
Karm Soni
319414486a fix: reorder last_scanned_warehouse in sales invoice 2025-08-14 11:51:33 +05:30
diptanilsaha
711076d02d fix: product bundle child item quantity should be a positive number 2025-08-14 11:49:09 +05:30
Soni Karm
227fadc541 feat: enhance barcode scanner to support warehouse scanning (#48865)
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
2025-08-14 11:32:02 +05:30
rohitwaghchaure
4cd0db764f Merge pull request #49155 from rohitwaghchaure/fixed-ignore-message-bom-creator
chore: convert message to toast notification
2025-08-14 10:34:37 +05:30
Rohit Waghchaure
fc71001110 chore: convert message to toast notification 2025-08-14 08:50:21 +05:30
Lewis
54d3e5675f 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
2025-08-13 16:25:58 -04:00
rohitwaghchaure
b9fc3db613 Merge pull request #49154 from rohitwaghchaure/fixed-incorrect-stock-reco-current-qty
fix: current qty for batch in stock reco
2025-08-13 23:56:51 +05:30
Rohit Waghchaure
817e719cc2 fix: current qty for batch in stock reco 2025-08-13 23:39:16 +05:30
Khushi Rawat
7ba61be796 Merge pull request #49075 from rehanrehman389/asset-docstatus-check
fix: add validation for draft PR/PI in Asset
2025-08-13 17:17:37 +05:30
Khushi Rawat
4a48b13715 refactor: validate linked purchase docs before field usage 2025-08-13 16:38:30 +05:30
khushi8112
cd2bab7c5f fix: add value adjustment amount in report for group by category filter 2025-08-13 16:19:51 +05:30
khushi8112
f8050f4278 fix: add value adjustment amount in asset value 2025-08-13 16:17:24 +05:30
Mihir Kandoi
3bcf1cbdce Merge pull request #49134 from karm1000/default-val-now-in-subcontracting-receipt
chore: add default value for posting_time field in subcontracting receipt
2025-08-13 14:04:18 +05:30
Mihir Kandoi
0f68dc4505 Merge pull request #49133 from mihir-kandoi/auto-reserve-serial-batch
fix: do not auto reserve serial/batch if SRE already has serial/batch set
2025-08-13 13:45:04 +05:30
Karm Soni
b7470617e0 chore: add default value for posting_time field in subcontracting receipt 2025-08-13 12:55:14 +05:30
Mihir Kandoi
ac9b0409f5 fix: do not auto reserve serial/batch if SRE already has serial/batch set 2025-08-13 12:24:44 +05:30
Lewis
d77d79e011 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.
2025-08-12 20:10:39 -04:00
Lewis
f5e5f7b588 fix: remove unclear message related to availability of product bundle 2025-08-12 18:53:09 -04:00
Lewis
a65b200eb7 fix(pos): populate packed_items table in POS Invoice 2025-08-12 18:33:02 -04:00
MochaMind
8290731253 fix: sync translations from crowdin (#49126) 2025-08-13 00:07:51 +02:00
Raffael Meyer
9429c05693 ci: disable Coderabbit on translation PRs (#49128) 2025-08-13 00:06:10 +02:00
Lewis
0fc187adc3 chore: apply pre-commit formatting 2025-08-12 16:36:00 -04:00
Mihir Kandoi
99956649e3 Merge pull request #49120 from mihir-kandoi/fix-auto-reserve-serial-batch
fix: check for auto reserve serial/batch before auto reserving
2025-08-12 22:03:59 +05:30
rohitwaghchaure
e91d886e76 Merge pull request #49123 from rohitwaghchaure/fixed-sub-assembl-in-pp
fix: do not fetch sub-assembly in PP
2025-08-12 22:01:34 +05:30
Mihir Kandoi
514cfe2c29 Merge pull request #49122 from mihir-kandoi/gh49113
feat: select child item when creating one document from another
2025-08-12 21:36:31 +05:30
Mihir Kandoi
a9936ae133 feat: select child item when creating one document from another 2025-08-12 21:05:51 +05:30
Rohit Waghchaure
1e87600119 fix: do not fetch sub-assembly in PP 2025-08-12 20:36:03 +05:30
rehansari26
a9aeb8ac54 fix: prevent duplicate reverse Journal Entry 2025-08-12 17:23:02 +05:30
Mihir Kandoi
2c64b76392 fix: check for auto reserve serial/batch before auto reserving 2025-08-12 16:51:06 +05:30
Sagar Vora
655a241958 Merge pull request #49118 from sagarvora/rm-query-exists 2025-08-12 11:19:39 +00:00
Sagar Vora
6bf63f66ec fix: guard against default not set in stock settings 2025-08-12 16:31:15 +05:30
Sagar Vora
8b75993d3a perf: remove unecessary calls to deepcopy 2025-08-12 16:17:02 +05:30
Sagar Vora
e11cadca58 perf: remove unnecessary branching and use cache in get_item_warehouse 2025-08-12 16:16:24 +05:30
l0gesh29
77021fff74 fix: handle default dimension for all company 2025-08-12 14:28:56 +05:30
l0gesh29
16e440f9a7 fix: handle default accounting dimension 2025-08-12 14:28:56 +05:30
l0gesh29
3cf765d985 fix: add patch 2025-08-12 14:28:18 +05:30
l0gesh29
42f9d27d79 fix: fetch fieldname in accounting dimension filter 2025-08-12 14:27:32 +05:30
l0gesh29
ac2acc535d fix: add fieldname in accounting dimension filter 2025-08-12 14:27:32 +05:30
Diptanil Saha
81c8972a66 Merge pull request #49112 from diptanilsaha/patch_set_invoice_doctype
fix: patch to set invoice_type on POS Settings
2025-08-12 12:49:55 +05:30
diptanilsaha
0941b908dd fix: patch to set invoice type on POS Settings 2025-08-12 12:23:45 +05:30
ruthra kumar
f9f4e4b84c Merge pull request #49104 from frappe/l10n_develop
fix: sync translations from crowdin
2025-08-12 10:53:56 +05:30
ruthra kumar
b8ea6fc708 Merge pull request #48419 from ljain112/experiment-ple
fix: do not create delinked payment ledger entries on cancel
2025-08-12 10:51:20 +05:30
ruthra kumar
0c7dcec5c2 Merge pull request #49086 from aerele/process-statement-of-accounts-auto-email
fix(process statement of accounts): use date instead of formatted date
2025-08-12 10:47:15 +05:30
ruthra kumar
92327729d6 Merge pull request #49096 from aerele/po-dialog
fix: table render issue on pop-up edit
2025-08-12 10:39:51 +05:30
Lewis Mojica
5a5804ca87 chore: remove unused variable 2025-08-11 16:06:08 -04:00
Lewis
984d744ac2 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
2025-08-11 15:27:18 -04:00
MochaMind
1e992bb263 fix: Esperanto translations 2025-08-11 22:37:03 +05:30
MochaMind
21e7675a44 fix: Dutch translations 2025-08-11 22:36:58 +05:30
MochaMind
26586a42a4 fix: Serbian (Latin) translations 2025-08-11 22:36:55 +05:30
MochaMind
823413a9c4 fix: Bosnian translations 2025-08-11 22:36:51 +05:30
MochaMind
25240967ba fix: Croatian translations 2025-08-11 22:36:48 +05:30
MochaMind
4ce058fc47 fix: Thai translations 2025-08-11 22:36:44 +05:30
MochaMind
b9a08e7920 fix: Persian translations 2025-08-11 22:36:41 +05:30
MochaMind
68f23c7a70 fix: Indonesian translations 2025-08-11 22:36:37 +05:30
MochaMind
43dbc1efbb fix: Portuguese, Brazilian translations 2025-08-11 22:36:32 +05:30
MochaMind
472c0c2b27 fix: Vietnamese translations 2025-08-11 22:36:29 +05:30
MochaMind
d0e59b580e fix: Chinese Simplified translations 2025-08-11 22:36:25 +05:30
MochaMind
a8b69efa84 fix: Turkish translations 2025-08-11 22:36:22 +05:30
MochaMind
8b27c2b8ee fix: Swedish translations 2025-08-11 22:36:18 +05:30
MochaMind
e346e988ca fix: Serbian (Cyrillic) translations 2025-08-11 22:36:14 +05:30
MochaMind
a271fd2590 fix: Russian translations 2025-08-11 22:36:09 +05:30
MochaMind
7be3eb36d9 fix: Portuguese translations 2025-08-11 22:36:06 +05:30
MochaMind
62269b595a fix: Polish translations 2025-08-11 22:36:02 +05:30
MochaMind
7d03e609a6 fix: Italian translations 2025-08-11 22:35:59 +05:30
MochaMind
91652921a3 fix: Hungarian translations 2025-08-11 22:35:55 +05:30
MochaMind
cde9d3a9ce fix: German translations 2025-08-11 22:35:51 +05:30
MochaMind
c655d1db3a fix: Czech translations 2025-08-11 22:35:48 +05:30
MochaMind
4fa74d29a9 fix: Arabic translations 2025-08-11 22:35:44 +05:30
MochaMind
752253704c fix: Spanish translations 2025-08-11 22:35:41 +05:30
MochaMind
8d35676e5a fix: French translations 2025-08-11 22:35:37 +05:30
rohitwaghchaure
4cc6596d44 Merge pull request #49087 from rohitwaghchaure/sabb-traceability-expiry-date-report
fix: batch expiry date, serial no warranty and AMC expiry date in traceability report
2025-08-11 21:40:38 +05:30
Rohit Waghchaure
16d5caa719 fix: batch expiry date, serial no warranty and amc expiry date in traceability report 2025-08-11 19:42:12 +05:30
ravibharathi656
430a06d056 fix(quotation): update currency on duplicate 2025-08-11 17:59:59 +05:30
ruthra kumar
0c62e1a9ae Merge pull request #48862 from khushi8112/show-party-name-in-reports
feat: show party name in reports
2025-08-11 17:47:09 +05:30
Lakshit Jain
d45cd5af2b Merge pull request #49093 from ljain112/fix-account-coa
fix: allow creation of root accounts in account tree view
2025-08-11 17:07:03 +05:30
ruthra kumar
2713055447 Merge pull request #49092 from ruthra-kumar/opp_type
refactor: use translated value of set default in Opportunity
2025-08-11 16:53:00 +05:30
l0gesh29
3431c6c90e fix: table render issue on pop-up edit 2025-08-11 16:52:29 +05:30
Asmita Hase
f0e7eb44f1 Merge pull request #49088 from AssemBahnasy/fix-party-type-employee-filter-develop 2025-08-11 16:44:28 +05:30
ruthra kumar
2b777caa83 refactor: use translated value of set default in Opportunity 2025-08-11 16:27:10 +05:30
Assem Bahnasy
8a9bf166c6 refactor: Move Employee inclusion to SQL level to preserve search semantics 2025-08-11 12:41:34 +03:00
Assem Bahnasy
a08c7f37d3 refactor: Use parameterized SQL queries to prevent injection and handle None values 2025-08-11 11:55:56 +03:00
ruthra kumar
3302795e50 Merge pull request #48952 from frappe/l10n_develop
fix: sync translations from crowdin
2025-08-11 13:46:41 +05:30
ruthra kumar
e867a42181 Merge pull request #49077 from frappe/pot_develop_2025-08-10
chore: update POT file
2025-08-11 13:38:57 +05:30
ravibharathi656
aa3f50ab77 fix(process statement of accounts): use date instead of formatted date 2025-08-11 12:18:17 +05:30
ruthra kumar
fc5946c139 Merge pull request #48730 from rtdany10/vat_201_export
fix(regional-uae): mark export items as zero rated
2025-08-11 11:35:08 +05:30
Mihir Kandoi
2fd4db0891 Merge pull request #49082 from mihir-kandoi/fix-sre-closed-status-query
fix: modify all remaining SRE queries to consider new Closed status
2025-08-11 10:37:47 +05:30
Vishist16
3ee23d9ee8 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
2025-08-11 10:29:27 +05:30
Mihir Kandoi
dbaa44688e fix: modify all remaining SRE queries to consider new Closed status 2025-08-11 10:21:16 +05:30
Mihir Kandoi
fe4f7b9c2f Merge pull request #49068 from KerollesFathy/query-filter-disabled-scraped-items-on-job-card
fix(job-card): Add filter to item_code query for scrap_items to exclude disabled
2025-08-11 10:12:58 +05:30
Mihir Kandoi
7adab6f5ec Merge pull request #49071 from navinrc/add-item-name-to-material-request-dialog
feat: add item_name column to Material Request dialog in Purchase Order
2025-08-11 10:02:27 +05:30
MochaMind
5b4e28fac6 fix: Swedish translations 2025-08-10 22:40:23 +05:30
MochaMind
12c91af5bc fix: Italian translations 2025-08-10 22:40:20 +05:30
frappe-pr-bot
d1f24ca4a5 chore: update POT file 2025-08-10 09:37:20 +00:00
Rehan Ansari
4cf481cca8 fix: add validation for draft PR/PI in Asset 2025-08-10 00:40:52 +05:30
MochaMind
dd910d7c1a fix: Serbian (Latin) translations 2025-08-09 22:23:46 +05:30
MochaMind
1770fe6590 fix: Swedish translations 2025-08-09 22:23:43 +05:30
MochaMind
a72a1ca517 fix: Serbian (Cyrillic) translations 2025-08-09 22:23:39 +05:30
MochaMind
9d2e5391cc fix: Italian translations 2025-08-09 22:23:33 +05:30
navinrc
4312719010 feat: add item_name column to Material Request dialog in Purchase Order 2025-08-09 01:06:51 +05:30
MochaMind
9540ffeec0 fix: Italian translations 2025-08-08 22:14:35 +05:30
KerollesFathy
89c2bbed7c fix: Add filter to item_code query for scrap_items to exclude disabled items 2025-08-08 14:45:25 +00:00
rohitwaghchaure
a7e70b1094 Merge pull request #49067 from rohitwaghchaure/fixed-github-49064
fix: restrict fixed asset items in the BOM
2025-08-08 19:29:45 +05:30
Rohit Waghchaure
760c373eb2 fix: restrict fixed asset items in the BOM 2025-08-08 19:00:32 +05:30
rohitwaghchaure
89aab0af18 Merge pull request #49060 from mihir-kandoi/modify-all-queries-for-closed-status-sre
fix: modify all SRE queries to consider new Closed status
2025-08-08 16:12:22 +05:30
Mihir Kandoi
345ca405b0 fix: modify all SRE queries to consider new Closed status 2025-08-08 15:10:43 +05:30
Asmita Hase
7d06622881 Merge pull request #49053 from asmitahase/employee-party 2025-08-08 13:57:49 +05:30
Asmita Hase
fa5419dede Merge pull request #49051 from asmitahase/patch-again 2025-08-08 12:58:29 +05:30
Asmita Hase
e7a2ff1884 fix: dont validate account type in for employee party type 2025-08-08 12:58:06 +05:30
Asmita Hase
6d908f44a5 chore: trigger create_advance_payment_ledger_records patch 2025-08-08 12:18:36 +05:30
Mihir Kandoi
d61977d002 fix: ensure variant conversion factor is returned before the template's 2025-08-08 11:57:15 +05:30
Dany Robert
29c3ef8280 fix: handle case where taxes is added invoice changed to non-export later 2025-08-08 11:01:59 +05:30
Mihir Kandoi
f9c797a402 Merge pull request #48813 from aerele/filter-expense-head-account
fix(purchase invoice): filter only enabled account
2025-08-08 10:54:10 +05:30
Dany Robert
c8940a39b3 chore: code styling 2025-08-08 10:02:35 +05:30
Dany Robert
38471995e7 fix: show message only if no tax is applied 2025-08-08 09:58:16 +05:30
MochaMind
00b3576134 fix: Italian translations 2025-08-07 21:52:10 +05:30
Asmita Hase
94c45d1db3 Merge pull request #49042 from asmitahase/ignore-validation-flag 2025-08-07 17:58:43 +05:30
rohitwaghchaure
00518069ac Merge pull request #49040 from rohitwaghchaure/fixed-calculation-sabb-traceability
fix: qty calculation in SABB traceability
2025-08-07 17:32:23 +05:30
Asmita Hase
0665d13fd3 fix: added a flag on journal entry to ignore party account type validation if required 2025-08-07 17:31:36 +05:30
Rohit Waghchaure
505814c07a fix: qty calculation in SABB traceability 2025-08-07 16:22:52 +05:30
rohitwaghchaure
c15d7fe86e Merge pull request #49022 from rohitwaghchaure/fixed-valuation-rate-batch-ma
fix: zero valuation rate for the batch
2025-08-07 13:54:13 +05:30
mithili
23308f6d10 chore: add back filter 2025-08-07 11:10:43 +05:30
mithili
7c8dd86a35 fix: add condition to fetch active accounts 2025-08-07 11:10:43 +05:30
mithili
c3111db6e2 fix(purchase invoice): filter only enabled account 2025-08-07 11:10:42 +05:30
Diptanil Saha
09f65713ca Merge pull request #49023 from diptanilsaha/fix_account_reports_presentation_currency
fix: NoneType error on applying presentation_currency filter on financial statements and trial balance report
2025-08-07 02:10:10 +05:30
Rohit Waghchaure
c8410cb5ca fix: zero valuation rate for the batch 2025-08-07 01:47:54 +05:30
diptanilsaha
d7e22de44c fix: nonetype error on applying presentation_currency filter on financial statements and trial balance report 2025-08-07 01:37:33 +05:30
rohitwaghchaure
5918199845 Merge pull request #49020 from rohitwaghchaure/fixed-source-document-batch
fix: source document in batch
2025-08-06 23:18:11 +05:30
Rohit Waghchaure
8b0b938595 fix: source document in batch 2025-08-06 22:22:36 +05:30
rohitwaghchaure
2c35299cbb Merge pull request #49010 from rohitwaghchaure/fixed-support-45862-1
fix: timeout while submitting purchase receipt
2025-08-06 20:04:55 +05:30
Khushi Rawat
07d1663f2c Merge pull request #49011 from khushi8112/fixed-asset-register
fix: fetch revaluated asset value for fixed asset register
2025-08-06 17:13:48 +05:30
khushi8112
a33bcb47b3 chore: format code 2025-08-06 16:48:09 +05:30
khushi8112
67ec4fa477 fix: fetch revaluated asset value for all the assets 2025-08-06 16:47:01 +05:30
Rohit Waghchaure
c433943c46 fix: timeout while submitting purchase receipt 2025-08-06 16:43:26 +05:30
rohitwaghchaure
865956e537 Merge pull request #48950 from rohitwaghchaure/feat-batch-traceability-report
feat: batch traceability report
2025-08-06 15:55:43 +05:30
Rohit Waghchaure
7b05a2a097 feat: serial no and batch traceability report 2025-08-06 15:17:35 +05:30
Dany Robert
eb6c8d8938 chore: linters 2025-08-06 11:40:33 +05:30
Asmita Hase
28cbd18300 Merge pull request #49003 from asmitahase/fix-references-for-advance
refactor: get advance payment doctypes from hooks
2025-08-06 11:22:09 +05:30
Asmita Hase
b4f831a931 chore: removed uncessary comment 2025-08-06 10:42:47 +05:30
Asmita Hase
a273147b6e chore: add account type to employee advance account in standard chart of accounts 2025-08-06 10:36:18 +05:30
Asmita Hase
2cb2e05b19 refactor: get advance payment doctypes from hooks 2025-08-06 10:34:48 +05:30
MochaMind
f2d31e3b77 fix: Persian translations 2025-08-05 21:36:28 +05:30
Logesh Periyasamy
a8d17b7590 Merge pull request #48761 from aerele/exchange-gain-or-loss-on-repost
fix: prevent gain or loss entry cancellation upon reposting
2025-08-05 20:55:44 +05:30
ruthra kumar
c46b3d4b83 Merge pull request #48901 from aerele/cc-allocation-round-off
fix: do not split round off when there is a cost center allocation
2025-08-05 20:16:38 +05:30
ravibharathi656
dd24cce509 test: add test for cost center allocation commercial rounding 2025-08-05 17:58:33 +05:30
ruthra kumar
b0d9c4f563 Merge pull request #48947 from aerele/process-statement-of-accounts
fix(process statement of accounts): make date fields mandatory
2025-08-05 16:35:46 +05:30
Mihir Kandoi
ccc48f909a Merge pull request #48949 from KerollesFathy/add-work-order-on-project-dashboard
feat: add Manufacture section to project dashboard to show linked Work Orders
2025-08-05 16:29:18 +05:30
Mihir Kandoi
60b7e22e93 Merge pull request #48948 from KerollesFathy/prevent-negative-operation-time-and-batch-size
feat: add non-negative constraint to batch size and sub operation time fields
2025-08-05 16:28:45 +05:30
venkat102
f0df41d521 fix: do not split round off when there is a cost center allocation 2025-08-05 16:18:53 +05:30
Mihir Kandoi
9ad7dad86d Merge pull request #48946 from KerollesFathy/prevent-negative-completed-qty-on-job-card
feat: Add non-negative constraint to completed qty fields in job card and time log
2025-08-05 16:16:44 +05:30
KerollesFathy
ece7165022 Merge branch 'develop' into add-work-order-on-project-dashboard 2025-08-05 10:42:06 +00:00
KerollesFathy
e4db7f8d0a Merge branch 'develop' into prevent-negative-operation-time-and-batch-size 2025-08-05 10:41:29 +00:00
Diptanil Saha
9a61d2d531 Merge pull request #48988 from diptanilsaha/pos_set_grand_total_to_default_mop
refactor(pos): set/reset grand total to default mode of payment
2025-08-05 16:02:22 +05:30
diptanilsaha
265f7ce092 refactor(pos): set/reset grand total to default mode of payment 2025-08-05 15:59:46 +05:30
KerollesFathy
db8d368717 Merge branch 'develop' into prevent-negative-completed-qty-on-job-card 2025-08-05 10:17:23 +00:00
ruthra kumar
30c59bddf9 Merge pull request #48798 from aerele/gl-report-show-amount-in-company-currency
feat: add show_amount_in_company_currency in gl report
2025-08-05 15:21:52 +05:30
ruthra kumar
bc26c87a63 Merge pull request #48909 from aerele/tax-withholding-details-report
fix(tax withholding details): avoid voucher duplication
2025-08-05 15:15:04 +05:30
Khushi Rawat
338ee746ec Merge pull request #48968 from khushi8112/validate-asset-before-submitting-depreciation-schedule
fix: validate asset before submitting depreciation schedule
2025-08-05 15:01:41 +05:30
Khushi Rawat
3bda9c54ae Merge pull request #48974 from khushi8112/invalid-field-query-error
fix: use maintenance_status filter for indicators
2025-08-05 15:00:30 +05:30
Mihir Kandoi
8b6f328665 Merge pull request #48969 from frappe/mergify/bp/develop/pr-48767
Fix: Procurement Tracker - No permission to read Employee #48765 (backport #48767)
2025-08-05 14:43:16 +05:30
khushi8112
1b674a1051 fix: use maintenance_status filter for indicators 2025-08-05 14:39:26 +05:30
ruthra kumar
8a10e327ff Merge pull request #48848 from ernestoruiz89/patch-2
chore: add translation function to Update budget.py
2025-08-05 14:38:07 +05:30
ruthra kumar
2c80b2baa7 Merge pull request #48774 from aerele/batch-wise-bank-reconciliation
perf: process auto bank reconciliation in batches
2025-08-05 14:37:46 +05:30
khushi8112
d6fb99916e chore: fetch docstatus to validate 2025-08-05 14:34:39 +05:30
ruthra kumar
9502b163e1 Merge pull request #48853 from flaviacastro/fix/pricing-rule-help-content
fix: pricing rule help content
2025-08-05 14:32:38 +05:30
ruthra kumar
269020984b Merge pull request #48718 from aerele/subscription-settings-timeout
refactor: process subscriptions in batch wise
2025-08-05 14:26:56 +05:30
Liuyang
e058998689 Fix: Procurement Tracker - No permission to read Employee #48765
(cherry picked from commit 284e45011e)
2025-08-05 08:51:52 +00:00
ruthra kumar
349ad94ff3 Merge pull request #48861 from ljain112/chore-tds-label
chore: correct description for `consider_party_ledger_amount` in Tax Withholding Category
2025-08-05 14:21:16 +05:30
khushi8112
f5a71c6b88 chore: add mistakenly removed test records 2025-08-05 14:19:53 +05:30
khushi8112
d5edca2022 fix: validate if journal entry linked to schedule is in draft 2025-08-05 14:16:05 +05:30
ravibharathi656
283d69c0bd refactor: process subscriptions in batch wise 2025-08-05 14:09:06 +05:30
Mihir Kandoi
cc2a27315a Merge pull request #48693 from cogk/fix-correctly-get-attachments-folder
fix: Use correct Attachments folder in code list import
2025-08-05 14:03:29 +05:30
khushi8112
a4628c2024 fix: submit depreciation schedule only for submitted asset 2025-08-05 14:00:27 +05:30
Khushi Rawat
708ba3b229 Merge pull request #48929 from ernestoruiz89/patch-3
chore: add translation function on remarks in asset depreciation entry
2025-08-05 13:37:54 +05:30
Diptanil Saha
14e17f584a Merge pull request #48964 from diptanilsaha/remove_api_calls_to_set_default_payments
fix: remove api call to set default payments
2025-08-05 13:15:41 +05:30
diptanilsaha
871b8473fa fix: remove api call to set default payments 2025-08-05 12:58:53 +05:30
Khushi Rawat
a60db40fd2 fix: add missing parentheses 2025-08-05 12:50:33 +05:30
Dany Robert
86db6a5b06 Merge branch 'develop' into vat_201_export 2025-08-05 12:22:26 +05:30
ruthra kumar
e556616ad1 Merge pull request #48860 from aerele/build_qb_match_conditions
fix: add doctype fieldname in condition
2025-08-05 12:01:25 +05:30
Mihir Kandoi
88c2be7e68 Merge pull request #48940 from mihir-kandoi/fix-missing-account-gl-entry-subcontracting
fix: failing subcontracting patch
2025-08-05 11:37:36 +05:30
Diptanil Saha
3274285729 fix(bank statement import): return blank template instead of template with 5 records on download template (#48960) 2025-08-05 11:26:25 +05:30
Mihir Kandoi
14b47e81ce fix: failing subcontracting patch 2025-08-05 11:21:36 +05:30
diptanilsaha
7dc2abb516 fix(bank statement import): return blank template instead of template with 5 records on download template 2025-08-05 11:19:48 +05:30
ravibharathi656
23bc180d98 fix(process statement of accounts): make date fields mandatory 2025-08-05 10:54:02 +05:30
Flavia de Castro
aa7727d50a Merge branch 'frappe:develop' into fix/pricing-rule-help-content 2025-08-04 15:43:44 -03:00
Diptanil Saha
0212be2e58 Merge pull request #48945 from diptanilsaha/child_company_coa_currency
fix: set default_currency in accounts during child company creation
2025-08-05 00:05:42 +05:30
Diptanil Saha
cc26d5da14 chore: remove wrongly configured 'pos*' assignment from CODEOWNERS (#48954) 2025-08-04 23:53:34 +05:30
diptanilsaha
de153aeb1d fix: set default_currency in accounts during child company creation 2025-08-04 23:49:01 +05:30
rohitwaghchaure
7f6038208d Merge pull request #48951 from rohitwaghchaure/fixed-test-cases-posting_time
chore: added now as default value for the posting time
2025-08-04 22:51:00 +05:30
Rohit Waghchaure
b3cebd87c8 chore: added now as default value for the posting time 2025-08-04 22:22:55 +05:30
MochaMind
7bd24308d3 fix: Serbian (Latin) translations 2025-08-04 21:19:45 +05:30
MochaMind
cd9651afc1 fix: Persian translations 2025-08-04 21:19:32 +05:30
MochaMind
3aa950c32e fix: Serbian (Cyrillic) translations 2025-08-04 21:19:12 +05:30
KerollesFathy
2729d7521d feat: add 'Manufacture' section to project dashboard and show linked Work Orders 2025-08-04 13:43:42 +00:00
KerollesFathy
f4722d3b24 feat: add non-negative constraint to batch size and sub operation time fields 2025-08-04 13:20:30 +00:00
KerollesFathy
c30665fda7 feat: Add non-negative constraint to completed qty fields in job card and time log 2025-08-04 12:58:49 +00:00
Dany Robert
0c15b65756 fix: avoid property setter for custom field 2025-08-04 15:52:22 +05:30
Dany Robert
d25846f383 fix: simplify export determination logic 2025-08-04 15:45:43 +05:30
Ravibharathi
02380c3eab Merge pull request #48575 from aerele/company-payment-gateway
feat(payment gateway account): add company
2025-08-04 14:23:56 +05:30
ruthra kumar
655aff7c92 Merge pull request #48926 from pps190/fix-report-currency
fix: provide missing `company` in report records that require reference to `Company:company:default_currency`
2025-08-04 10:29:20 +05:30
rohitwaghchaure
1d8f1d66e4 Merge pull request #48933 from frappe/mergify/bp/develop/pr-48914
perf: process_gl_map causing performance issues in the reposting (backport #48914)
2025-08-04 09:56:22 +05:30
ruthra kumar
3395fc1fde Merge pull request #48136 from aerele/enable_dim_submit
fix(accounts):enable allow_on_submit for accounting dimensions in repost settings allowed doctypes
2025-08-04 09:04:27 +05:30
MochaMind
415b751bab fix: sync translations from crowdin (#48911) 2025-08-03 20:46:02 +02:00
rohitwaghchaure
67b95c4abf chore: fix conflicts 2025-08-03 16:21:45 +05:30
MochaMind
5c3c11cda3 chore: update POT file (#48931) 2025-08-03 12:30:10 +02:00
Rohit Waghchaure
af7dc363e1 perf: process_gl_map causing performance issues in the reposting
(cherry picked from commit a96fa55704)

# Conflicts:
#	erpnext/stock/doctype/stock_entry/stock_entry.py
2025-08-03 09:46:15 +00:00
Ernesto Ruiz
803180d5de chore: add translation function on remark in setup_journal_entry_metadata in depreciation.py 2025-08-02 13:43:18 -06:00
Ernesto Ruiz
119904e44f chore: add translation function on remarks in make_journal_entry in asset.py 2025-08-02 13:29:33 -06:00
Diptanil Saha
2c44e4ec2c Merge pull request #48523 from ibrahim317/fix-lead-quick-entry
fix: add undefined check for cur_frm in lead doctype (#48522)
2025-08-03 00:01:57 +05:30
Mihir Kandoi
7358f44cc2 Merge pull request #48748 from devdusija/fix/account-currency-validation
fix: account currency validation to exclude cancelled entries
2025-08-02 22:17:14 +05:30
Devin Slauenwhite
c03f1c25cf fix: payment ledger voucher seperator row currencies 2025-08-02 12:29:40 -04:00
Devin Slauenwhite
97959dbe75 fix: provide company for outstanding record. 2025-08-02 12:23:12 -04:00
Devin Slauenwhite
7f3905185c fix: provide missing company in report records that require reference to Company:company:default_currency 2025-08-02 11:38:47 -04:00
Devin Slauenwhite
316470eee4 Revert "fix: set proper currency format"
This reverts PR https://github.com/frappe/erpnext/pull/42458
This reverts commit 2533808f1e.
2025-08-02 11:15:25 -04:00
Mihir Kandoi
fc56b1e8aa Merge pull request #48915 from aerele/fix/set_use_serial_batch_fields
fix: set use_serial_batch_fields when creating PR from PO
2025-08-02 20:41:39 +05:30
ibrahim
f4e5e0812b refactor: run pre-commit for formatting on lead client script (#48523) 2025-08-02 17:01:41 +03:00
Kavin
a384c96617 fix: set use_serial_batch_fields when creating PR from PO 2025-08-02 14:48:06 +05:30
Mihir Kandoi
9c5ba2b0b3 Merge pull request #48908 from mihir-kandoi/st45545
fix: include Sales Invoice in SABB validation for packed items
2025-08-01 17:18:57 +05:30
ravibharathi656
8837016243 fix(tax withholding details): avoid voucher duplication 2025-08-01 17:02:43 +05:30
Mihir Kandoi
2ce297aff8 fix: include Sales Invoice in SABB validation for packed items 2025-08-01 17:00:38 +05:30
ruthra kumar
4785f0b31d Merge pull request #48905 from ljain112/fix-advance-patch
fix: do not execute patch if no advance doctypes
2025-08-01 15:31:05 +05:30
ljain112
e38dfbfa91 fix: do not execute patch if no advance doctypes 2025-08-01 14:51:25 +05:30
Mihir Kandoi
f916f29e47 Merge pull request #48904 from mihir-kandoi/fix-stock-reco-reservation-error
fix: consider Closed SREs during Stock Reco
2025-08-01 13:26:19 +05:30
Mihir Kandoi
3a9b65ebef fix: consider Closed SREs during Stock Reco 2025-08-01 13:08:23 +05:30
MochaMind
34b0aef5ce fix: sync translations from crowdin (#48867) 2025-07-31 18:05:15 +02:00
Mihir Kandoi
1481bc80e3 Merge pull request #48898 from mihir-kandoi/st45012
fix: remove incorrect references from stock entry dashboard/connections tab
2025-07-31 21:18:53 +05:30
Mihir Kandoi
6d82e3cc28 fix: remove incorrect references from stock entry dashboard/connections tab 2025-07-31 21:01:55 +05:30
Vishist16
3a80e116e8 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
2025-07-31 20:50:41 +05:30
rohitwaghchaure
6e8589a69a Merge pull request #48893 from rohitwaghchaure/feat-landed-cost-report
feat: landed cost report
2025-07-31 20:35:26 +05:30
Lakshit Jain
e70caedddc fix: multiple fixes for advance payment accounting 2025-07-31 20:17:14 +05:30
Rohit Waghchaure
a0bb8411ef feat: landed cost report 2025-07-31 16:22:02 +05:30
Mihir Kandoi
5a718d681a Merge pull request #48890 from mihir-kandoi/add-date-to-patch
chore: add date so patch can rerun
2025-07-31 16:16:07 +05:30
Mihir Kandoi
ba45f7610d chore: add date so patch can rerun 2025-07-31 15:58:25 +05:30
Mihir Kandoi
892dc1862a Merge pull request #48887 from mihir-kandoi/st45406
fix: failing subcontracting patch
2025-07-31 15:39:54 +05:30
Mihir Kandoi
bb43419944 fix: failing subcontracting patch 2025-07-31 15:23:14 +05:30
rohitwaghchaure
0707c9d732 Merge pull request #48869 from rohitwaghchaure/feat-link-vendor-invoices
feat: link vendor invoices in the LCV
2025-07-31 13:18:31 +05:30
Diptanil Saha
edd41fd693 Merge pull request #48619 from nikkothari22/bank-account-default
fix(accounts): allow default bank account per company
2025-07-31 12:02:51 +05:30
Mihir Kandoi
e2a25ae3c5 Merge pull request #48873 from mihir-kandoi/47305
fix: return conversion factor of variant and not template
2025-07-31 12:02:39 +05:30
Mihir Kandoi
732a9b86c6 fix: return conversion factor of variant and not template 2025-07-31 11:45:20 +05:30
ruthra kumar
d4ad4a2f6e Merge pull request #48684 from cogk/fix-add-title-to-payment-schedule-error-message
fix: Add title to payment schedule error message
2025-07-31 10:28:28 +05:30
Rohit Waghchaure
ee47c5eba9 feat: link vendor invoices in the LCV 2025-07-30 23:18:55 +05:30
khushi8112
70411ec086 fix: show name of the employee in general ledger report 2025-07-30 17:59:06 +05:30
khushi8112
b0c0a86fcf chore: code format 2025-07-30 17:01:44 +05:30
khushi8112
9dee411eb5 feat: add customer name column in gross profit report 2025-07-30 17:00:33 +05:30
khushi8112
3d94a7cf2c feat: add party name in GL entries 2025-07-30 16:58:38 +05:30
khushi8112
5f24061dd4 feat: add party name column in general ledger report 2025-07-30 16:56:12 +05:30
ljain112
f619bca2d6 chore: correct description for consider_party_ledger_amount in Tax Withholding Category 2025-07-30 16:50:49 +05:30
l0gesh29
e2d63e4c32 fix: add doctype fieldname in condition 2025-07-30 16:38:33 +05:30
Diptanil Saha
848d4d3767 Merge pull request #48858 from diptanilsaha/st_45201
fix: server error on opportunity summary by sales stage report
2025-07-30 15:49:08 +05:30
diptanilsaha
830b3ba1e5 fix: server error on opportunity summary by sales stage report 2025-07-30 15:22:56 +05:30
flaviacastro
8c736b5bbd fix: pricing rule help content 2025-07-29 19:25:26 +00:00
Mihir Kandoi
30b3570987 Merge pull request #48851 from mihir-kandoi/develop
Update CODEOWNERS
2025-07-29 22:17:38 +05:30
Mihir Kandoi
b9b3302b69 Update CODEOWNERS 2025-07-29 21:58:14 +05:30
Diptanil Saha
9c14aa08f8 Merge pull request #48839 from frappe/mihirs_fault
fix: change modified timestamp so migrations work
2025-07-29 20:59:24 +05:30
Diptanil Saha
89564bd10b Merge pull request #48844 from aerele/pos-search-fields
fix: set mandatory field for pos search fields
2025-07-29 20:55:04 +05:30
Diptanil Saha
c41adc4b9c Merge pull request #48845 from diptanilsaha/feat_item_selector_list_view
feat: list view on item selector in pos
2025-07-29 20:49:59 +05:30
Ernesto Ruiz
0b08fe2bac fix: add translation function to update budget.py 2025-07-29 09:07:04 -06:00
Ernesto Ruiz
0a34facb81 chore: add translation function to Update budget.py 2025-07-29 09:05:23 -06:00
Ravibharathi
99f7eb38d3 fix: update advance paid amount on unreconcile 2025-07-29 20:35:12 +05:30
ruthra kumar
bb129b7883 Merge pull request #48835 from aerele/user-permission-report
fix: include empty values in user permission
2025-07-29 19:55:14 +05:30
diptanilsaha
140698d676 feat: list view on item selector in pos 2025-07-29 19:23:23 +05:30
rohitwaghchaure
7970819904 Merge pull request #48743 from aerele/pick-list-location-warehouse
fix(pick list): make warehouse editable
2025-07-29 18:24:09 +05:30
mithili
f6212f7b51 fix: set mandatory field for pos search fields 2025-07-29 18:20:50 +05:30
rohitwaghchaure
a7a6ca197c Merge pull request #48841 from rohitwaghchaure/fixed-support-45167
fix: serial no warehouse for backdated stock reco
2025-07-29 18:15:38 +05:30
Rohit Waghchaure
1deedc766c fix: serial no warehouse for backdated stock reco 2025-07-29 17:49:46 +05:30
Ayush Chaudhari
c18d565d3e fix: change modified timestamp so migrations work 2025-07-29 17:13:26 +05:30
ruthra kumar
b8015d1032 Merge pull request #48837 from ruthra-kumar/fix_link_error_on_po_cancellation
fix: unable to cancel PO if unreconciliation is done
2025-07-29 17:03:42 +05:30
ruthra kumar
cf70147c0d fix: ignore is overridden by transaction.js upon clicking cancel
which overrides with 'Serial and Batch Bundle'
2025-07-29 17:00:57 +05:30
ruthra kumar
4c08165b69 Merge pull request #48782 from ljain112/fix-silly
fix: attribute error in payment entry
2025-07-29 16:41:53 +05:30
ljain112
f7ee9ee967 chore: added test case for reconciliation_effect_date 2025-07-29 16:11:46 +05:30
l0gesh29
f13d98fc7c fix: include empty values in user permission 2025-07-29 16:03:10 +05:30
Khushi Rawat
ac47b42c66 Merge pull request #48759 from aerele/revert-39776
revert: do not save when set email campaign status
2025-07-29 14:37:48 +05:30
Diptanil Saha
394b5b5b94 Merge pull request #48769 from aerele/letter-head-company
fix: set letter head from company if exists
2025-07-29 13:51:58 +05:30
ruthra kumar
8ae48f9baa Merge pull request #48593 from aerele/fix/so-disable-address-update
fix(sales-order): disallow address edits after sales order is submitted
2025-07-29 13:38:57 +05:30
Mihir Kandoi
1a1eb00689 Merge pull request #48700 from Vishist16/fix-negative-scrap-qty-jobcard-48545
fix: prevent negative scrap quantity in Job Card (#48545)
2025-07-29 13:26:55 +05:30
Bhavan23
daac7c589b fix(sales-order): disallow address edits after sales order is submitted 2025-07-29 13:23:37 +05:30
Logesh Periyasamy
88b9f8d68c feat: show opening/closing balance in cash flow report (#47877)
* feat: add checkbox to carryforward opening balance

* fix: ignore period closing voucher

* chore: rename filter check box

* feat: add total for opening and closing balance

* fix: update section name

* fix: remove section rename

---------

Co-authored-by: venkat102 <venkatesharunachalam659@gmail.com>
2025-07-29 13:05:29 +05:30
Mihir Kandoi
c86e75c091 Merge pull request #48557 from KerollesFathy/ft/cost-non-negative-on-ws
feat: Add non-negative constraint to workstation cost fields
2025-07-29 13:03:33 +05:30
ruthra kumar
444225f0ec Merge pull request #48757 from aerele/update-subscription-details
fix: add patch for update subscription details
2025-07-29 12:06:43 +05:30
Mihir Kandoi
3d5b46bdfc Merge pull request #48820 from mihir-kandoi/st44923
fix: over billed purchase receipt status
2025-07-29 11:31:21 +05:30
Mihir Kandoi
15e354f76e fix: over billed purchase receipt status 2025-07-29 11:15:14 +05:30
MochaMind
b1037eaade fix: sync translations from crowdin (#48817) 2025-07-28 16:56:08 +02:00
Diptanil Saha
a20d0d8f60 Merge pull request #48778 from aerele/payment-term-template-sales-invoice
fix: fetch payment term template from order
2025-07-28 20:24:35 +05:30
ruthra kumar
bf99f8095d Merge pull request #48797 from aerele/auto-repeat-field-no-copy
fix: avoid auto_repeat on duplicate
2025-07-28 17:58:12 +05:30
Diptanil Saha
7464fdb8e8 Merge pull request #48794 from diptanilsaha/internal_trans_valuation_rate
fix: fetch item valuation rate for internal transactions when server side reactivity is disabled
2025-07-28 17:45:29 +05:30
ruthra kumar
ea5761ee9c Merge pull request #48800 from frappe/mergify/bp/develop/pr-48041
fix: Misclassification of Journal Voucher Entries in Customer Ledger Summary (backport #48041)
2025-07-28 17:39:26 +05:30
ruthra kumar
c29fb45e10 Merge pull request #48796 from aerele/item-wise-sales-purchase-register-user-permission
fix: remove alias for order by field
2025-07-28 17:39:02 +05:30
diptanilsaha
9c4aac03df fix: fetch item valuation rate for internal transactions 2025-07-28 17:33:28 +05:30
ruthra kumar
f12b1bbf5d Merge pull request #48480 from aerele/currency-sales-partner-commision-report
Currency sales partner commision report
2025-07-28 17:11:24 +05:30
Mihir Kandoi
da498b0558 Merge pull request #48804 from mihir-kandoi/st44619
fix: sql error in quality inspection
2025-07-28 16:53:21 +05:30
Mihir Kandoi
062b245e3f fix: sql error in quality inspection 2025-07-28 16:37:29 +05:30
rohitwaghchaure
2b2c7bdf09 Merge pull request #48787 from rohitwaghchaure/fixed-pervent-concurrent-issue
fix: concurrency issues
2025-07-28 16:27:56 +05:30
rohitwaghchaure
d0504546ec Merge pull request #48801 from rohitwaghchaure/fixed-support-44546
fix: incorrect GL entries
2025-07-28 16:27:32 +05:30
Mihir Kandoi
da68fa0980 Merge pull request #48676 from mihir-kandoi/fix-no-account-in-gl-entry
fix: missing account in GL entries (subcontracting)
2025-07-28 16:20:45 +05:30
ruthra kumar
8d96acfc98 Merge pull request #48413 from ljain112/fix-ple
perf: multiple fixes related to ple and gle
2025-07-28 16:11:31 +05:30
ruthra kumar
96c59e0435 refactor(test): fix test data; no double counting 2025-07-28 15:49:18 +05:30
Mihir Kandoi
2ec69545ea Merge pull request #48793 from mihir-kandoi/st44120
fix: status in MR (material transfer) when using transit stock entries
2025-07-28 15:32:26 +05:30
Mihir Kandoi
baa612bc72 fix: status in MR (material transfer) when using transit stock entries 2025-07-28 15:16:50 +05:30
ruthra kumar
56085fe6a9 chore: resolve conflict 2025-07-28 15:00:09 +05:30
Rohit Waghchaure
4c273fcc99 fix: incorrect GL entries 2025-07-28 14:56:17 +05:30
l0gesh29
8fdda31e45 chore: rename variable 2025-07-28 14:52:03 +05:30
Mihir Kandoi
73e34ff9a9 Merge branch 'develop' into fix-no-account-in-gl-entry 2025-07-28 14:50:26 +05:30
Assem Bahnasy
d915c2b404 fix: Misclassification of Journal Voucher Entries in Customer Ledger Summary (#48041)
* fix: miscalculation of Invoiced Amount, Paid Amount, and Credit Amount in Customer Ledger Summary

* style: Apply ruff-format to customer_ledger_summary.py and ignore .venv/

* fix: Ensure .venv/ is ignored in .gitignore

* chore: removing backportrc line

* test: adding test_journal_voucher_against_return_invoice()

* fix: fixed test_journal_voucher_against_return_invoice function

* Revert .gitignore changes

---------

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
(cherry picked from commit 01fcd98c84)

# Conflicts:
#	erpnext/accounts/report/customer_ledger_summary/test_customer_ledger_summary.py
2025-07-28 09:07:05 +00:00
l0gesh29
468e5e9b2e feat: add show_amount_in_company_currency in gl report 2025-07-28 13:54:02 +05:30
l0gesh29
048b87328b fix: remove alias for order by field 2025-07-28 12:57:06 +05:30
mithili
2c54f49cbc fix: avoid auto_repeat on duplicate 2025-07-28 12:30:14 +05:30
Diptanil Saha
fccfcd6b0e Merge pull request #48675 from aerele/item-price-internal-transaction
feat(internal-transaction): fetch valuation rate for internal transaction
2025-07-28 11:48:30 +05:30
Dany Robert
1170e4fb2c fix(regional-uae): restrict zero rated export to invoice 2025-07-28 05:32:04 +00:00
ruthra kumar
20c2af9cd4 Merge pull request #48788 from frappe/l10n_develop
fix: sync translations from crowdin
2025-07-28 10:36:46 +05:30
MochaMind
1d991af821 fix: Persian translations 2025-07-27 18:54:32 +05:30
Rohit Waghchaure
a186b1266d fix: prevent concurrency issues 2025-07-27 18:46:43 +05:30
ljain112
dc841fe661 fix: attribute error in payment entry 2025-07-26 12:56:10 +05:30
ruthra kumar
ac448988ca Merge pull request #48780 from frappe/l10n_develop
fix: sync translations from crowdin
2025-07-25 19:41:13 +05:30
MochaMind
cc48cfaa5d fix: Indonesian translations 2025-07-25 18:49:01 +05:30
ravibharathi656
5ed34d6ff9 fix: fetch payment term template from order 2025-07-25 13:30:05 +05:30
rohitwaghchaure
46e6e48495 Merge pull request #48773 from ShreyasTheNewbie/create_job_card
fix: create job card for selected operations only
2025-07-25 10:05:36 +05:30
mithili
9638151f9d refactor: remove join in sql 2025-07-24 18:41:44 +05:30
mithili
998617879c chore: update query to fetch company currency 2025-07-24 18:41:44 +05:30
mithili
984947f333 fix: get default company currency 2025-07-24 18:41:44 +05:30
mithili
2de2ea9f58 fix: set company as mandatory 2025-07-24 18:41:43 +05:30
ravibharathi656
657de2cc7e perf: process auto bank reconciliation in batches 2025-07-24 17:04:03 +05:30
Shreyas Sojitra
27e5344188 fix: create job card for selected operations only 2025-07-24 10:05:03 +00:00
ravibharathi656
d163da171f fix: set letter head from company if exists 2025-07-24 14:55:21 +05:30
ravibharathi656
d3253d7d06 revert: do not save when set email campaign status 2025-07-23 16:16:46 +05:30
l0gesh29
c7b1379a7f fix: update subscription details patch 2025-07-23 15:46:08 +05:30
Kitti U. @ Ecosoft
ed79adebc4 refactor: call hooks after gle & sle rename (#48706) 2025-07-23 11:18:06 +05:30
ravibharathi656
f5beda48dc fix(pick list): make warehouse editable 2025-07-23 08:34:52 +05:30
ruthra kumar
d45d20e4db Merge pull request #48650 from aerele/payment-entry-outstanding-amount
fix: update outstanding amount on payment reconcillation
2025-07-23 06:52:29 +05:30
ruthra kumar
f41c6c037b Merge pull request #48732 from aerele/dimension-wise-acc-balance-report
fix: resolve sql syntax on accounting dimension
2025-07-23 06:43:33 +05:30
MochaMind
313913b329 fix: sync translations from crowdin (#48724) 2025-07-22 23:22:26 +02:00
Dev Dusija
c9c45fe89f fix: account currency validation to exclude cancelled entries 2025-07-22 23:56:48 +05:30
ruthra kumar
56ddb16186 Merge pull request #48733 from aerele/item-wise-sales-purchase-register
fix: add alias for order by field
2025-07-22 17:53:41 +05:30
ruthra kumar
4f1acc9349 Merge pull request #48665 from aerele/exchange-gain-or-loss-account
fix: show amount for exchange gain or loss account
2025-07-22 12:13:02 +05:30
rohitwaghchaure
ecff9dfdd8 Merge pull request #48723 from aerele/company-filter-job-card
fix(job card): company filter
2025-07-22 09:48:10 +05:30
rohitwaghchaure
73d2878e08 Merge pull request #48720 from rohitwaghchaure/fixed-support-44556
fix: valuation for rejected materials
2025-07-22 09:47:26 +05:30
l0gesh29
feaf39a812 fix: add alias for order by field 2025-07-22 01:23:19 +05:30
l0gesh29
1662b7c311 fix: resolve sql syntax on accounting dimension 2025-07-21 23:58:19 +05:30
Dany Robert
dc72e6cf36 fix(regional-uae): split export determination 2025-07-21 14:47:14 +00:00
pugazhendhivelu
4edbe77f67 chore: rename function set company filters 2025-07-21 20:10:08 +05:30
rohitwaghchaure
fa228da29c Merge pull request #48382 from karm1000/feat/stock-balance-multiselect-items-warehouses
feat: stock balance and stock ledger report with multi-select items and warehouses
2025-07-21 20:02:25 +05:30
rohitwaghchaure
9aea4ba51a Merge pull request #48704 from aerele/production-plan-sub-assembly-warehouse
fix(production plan): add company filter to sub assembly warehouse
2025-07-21 19:56:35 +05:30
Rohit Waghchaure
b7039cc506 fix: valuation for rejected materials 2025-07-21 19:53:04 +05:30
Dany Robert
b8224693c4 fix(regional-uae): mark export items as zero rated 2025-07-21 14:22:05 +00:00
ruthra kumar
1e44e3c1f6 Merge pull request #48690 from aerele/sales-order-item-schedule-date
fix: set delivery date if missing
2025-07-21 19:43:04 +05:30
ruthra kumar
a8e2386daa Merge pull request #48671 from aerele/journal-entry-print-settings
revert: do not set pay_to_recd_from to None
2025-07-21 19:39:23 +05:30
ravibharathi656
7e12332ea5 test: add test for pay_to_recd_from 2025-07-21 18:45:31 +05:30
ravibharathi656
03d6550db3 revert: do not set pay_to_recd_from to None 2025-07-21 18:45:30 +05:30
pugazhendhivelu
b1311ceb30 fix(job card): company filter 2025-07-21 17:34:49 +05:30
MochaMind
5089cf2155 fix: sync translations from crowdin (#48685) 2025-07-21 12:57:24 +02:00
Khushi Rawat
204de4934a Merge pull request #48649 from khushi8112/post-gl-entry-on-completion-date-of-asset-repair
fix: post gl entry on completion date instead of current date
2025-07-21 15:14:14 +05:30
MochaMind
8f3ed909c3 chore: update POT file (#48712) 2025-07-20 11:59:11 +02:00
ravibharathi656
1728a95111 fix(production plan): add company filter to sub assembly warehouse 2025-07-19 08:18:22 +05:30
Vishist Singh Solanki
94ec76545c fix: prevent negative scrap quantity in Job Card (#48545) 2025-07-18 16:07:14 +00:00
Mihir Kandoi
4174269091 fix: job card linter error (#47561) 2025-07-18 14:51:41 +00:00
Corentin Forler
bc2cb1737a fix: Use correct Attachments folder in code list import 2025-07-18 16:17:42 +02:00
ravibharathi656
cf6913891a fix: set delivery date if missing 2025-07-18 18:37:29 +05:30
Corentin Forler
205037fd6b fix: Add title to payment schedule error message 2025-07-18 14:07:11 +02:00
Diptanil Saha
7591656491 feat: tabs in pos invoice doctype (#48683) 2025-07-18 17:12:13 +05:30
khushi8112
766c5bbe2b fix: make completion mandatory and fix test case 2025-07-18 17:10:58 +05:30
Mihir Kandoi
446264e496 fix: patch to set default buying price list in material request (#48680)
* fix: patch to set default buying price list in material request
2025-07-18 11:13:27 +00:00
Mihir Kandoi
1ff47f0780 Merge branch 'develop' into fix-no-account-in-gl-entry 2025-07-18 16:28:16 +05:30
Mihir Kandoi
cb02391f37 fix: recreate GL entry instead of repost 2025-07-18 16:26:57 +05:30
Mihir Kandoi
e01ff50833 Merge pull request #48653 from mihir-kandoi/st43557-2
feat: button to recalculate costing and billing fields in project
2025-07-18 16:25:04 +05:30
Karm Soni
8a97b39028 fix: update get_data function to use item_query 2025-07-18 16:10:32 +05:30
Mihir Kandoi
f6e16c1180 chore: rename recalculating to updating 2025-07-18 16:08:04 +05:30
Mihir Kandoi
dd23d4c81b feat: option to recalculate costing and billing fields in project 2025-07-18 16:08:04 +05:30
Mihir Kandoi
dfd115cee5 Merge pull request #48631 from mihir-kandoi/st43869-2
feat: consider process less when calculating pending qty in work order
2025-07-18 15:53:00 +05:30
Diptanil Saha
37a964c300 Merge pull request #48677 from diptanilsaha/fix_coa_company_view_ledger_btn
fix: view ledger button of company on chart of accounts
2025-07-18 15:41:53 +05:30
Mihir Kandoi
b53723acad fix: include cost center in patch 2025-07-18 15:33:31 +05:30
diptanilsaha
98eb115746 fix: view ledger button of company on chart of accounts 2025-07-18 15:28:57 +05:30
Mihir Kandoi
c022b80e05 fix: missing account in GL entries (subcontracting) 2025-07-18 15:13:59 +05:30
l0gesh29
a88c62a307 feat: fetch valuation rate for internal transaction 2025-07-18 14:08:36 +05:30
l0gesh29
98724dff32 feat: add fetch_valuation_rate_for_internal_transaction in accounts settings 2025-07-18 14:07:25 +05:30
Diptanil Saha
9dc583ffcb fix: remove incorrect report conditions and unset sales partner on consolidated sales invoice (#48669)
* fix: undo query changes for sales partner related reports

* fix: patch to remove sales partner from consolidated sales invoice
2025-07-18 00:30:04 +05:30
Diptanil Saha
971024ab99 Merge pull request #48667 from diptanilsaha/fix_pos_sales_partner
fix: sales partner on pos invoice
2025-07-17 20:33:01 +05:30
l0gesh29
b6da350c20 fix: add validation for account key 2025-07-17 18:52:41 +05:30
l0gesh29
4f90f50eb2 fix: show amount for exchange gain or loss account 2025-07-17 18:15:06 +05:30
diptanilsaha
84b9a2aefb fix: unset commission and sales partner on consolidated sales invoice 2025-07-17 18:09:11 +05:30
diptanilsaha
e70416c78c fix: fixed the query for sales invoice in sale partner related reports 2025-07-17 17:53:54 +05:30
diptanilsaha
4fb1202c30 fix: added POS Invoice option on sales partner related reports 2025-07-17 17:53:54 +05:30
diptanilsaha
2245731fc8 fix: prepare sales partner commission report from pos invoice and sales invoice 2025-07-17 17:53:54 +05:30
diptanilsaha
2b87de1000 fix: pos invoice fetch commission_rate from sales_partner doctype on empty 2025-07-17 17:53:14 +05:30
Karm Soni
063c4e9720 refactor: revert indentation 2025-07-17 15:39:12 +05:30
rohitwaghchaure
cc2ca58721 Merge pull request #48655 from rohitwaghchaure/fixed-support-44001
fix: precision issue for Sales Incoming Rate
2025-07-17 15:34:31 +05:30
Rohit Waghchaure
7b99275ceb fix: precision issue for Sales Incoming Rate 2025-07-17 15:10:06 +05:30
ravibharathi656
478766c600 fix: update outstanding amount on payment reconcillation 2025-07-17 14:48:56 +05:30
rohitwaghchaure
0ae080723c Merge pull request #48616 from rohitwaghchaure/fixed-support-44081
fix: stand-alone credit note gl entries
2025-07-17 13:57:52 +05:30
Rohit Waghchaure
f3d6a64156 fix: stand-alone credit note gl entries 2025-07-17 13:33:10 +05:30
khushi8112
da8f7b29c1 fix: post gl entry on completion date instead of current date 2025-07-17 13:10:50 +05:30
Mihir Kandoi
8900744fc4 Merge pull request #48645 from mihir-kandoi/st43688
fix: do not consider cancelled SLEs in report
2025-07-17 11:38:33 +05:30
Mihir Kandoi
71578cb2ef fix: do not consider cancelled SLEs in report 2025-07-17 11:20:05 +05:30
ruthra kumar
8d091f6821 Merge pull request #48637 from frappe/l10n_develop
fix: sync translations from crowdin
2025-07-16 20:28:46 +05:30
ruthra kumar
9c7c22ed20 Merge pull request #48612 from aerele/pcv-forex-accounts
fix(period closing voucher): closing account head debit and debit in account currency should be equal
2025-07-16 20:13:06 +05:30
MochaMind
f9a78e9b45 fix: Persian translations 2025-07-16 17:02:01 +05:30
MochaMind
13afd3301f fix: Portuguese translations 2025-07-16 17:01:57 +05:30
rohitwaghchaure
a27f3f737f Merge pull request #48633 from rohitwaghchaure/fixed-support-42610
fix: performance issue while submitting the purchase invoice
2025-07-16 16:45:36 +05:30
Karm Soni
bc46045cc7 refactor: remove unused imports in stock_balance.py 2025-07-16 16:12:43 +05:30
Rohit Waghchaure
47979871de fix: performance issue while submitting the purchase invoice 2025-07-16 15:55:21 +05:30
Diptanil Saha
c9675b3f7d feat: account name and number columns on financial statements report on export (#48630)
* feat: account name and number columns on trial balance report on export

* feat: account name and number columns on financial statement reports on export

* test: fixed test_profit_and_loss_output_and_summary for new columns
2025-07-16 15:24:43 +05:30
diptanilsaha
79f73ccca1 test: fixed test_profit_and_loss_output_and_summary for new columns 2025-07-16 15:06:28 +05:30
Mihir Kandoi
74c4ca68e5 feat: consider process less when calculating pending qty in work order 2025-07-16 14:46:37 +05:30
Mihir Kandoi
2a186ab8dd Merge pull request #48628 from mihir-kandoi/fix-get-reserved-serial-nos
fix: serial no reserved error when reservation is transferred
2025-07-16 13:22:42 +05:30
diptanilsaha
6b98323806 feat: account name and number columns on financial statement reports on export 2025-07-16 13:22:31 +05:30
Mihir Kandoi
52ac389661 fix: serial no reserved error when reservation is transferred 2025-07-16 12:57:58 +05:30
diptanilsaha
393c1d4bee feat: account name and number columns on trial balance report on export 2025-07-16 12:46:56 +05:30
Diptanil Saha
9b8e0eb5c5 revert: "feat: trial balance report account name and number in separate column" (#48624)
Revert "feat: trial balance report account name and number in separate column"
2025-07-16 11:43:36 +05:30
Diptanil Saha
33f2a23bd8 fix: pos customer selection on new order (#48622) 2025-07-16 11:04:56 +05:30
Mihir Kandoi
d40538968f Merge pull request #48621 from mihir-kandoi/fix-get-batch-against-sales-order-2
fix: possible issue in getting reserved batch against sales order
2025-07-16 10:21:25 +05:30
Mihir Kandoi
28ee5fbf2e fix: possible issue in getting reserved batch against sales order 2025-07-16 10:05:36 +05:30
Nikhil Kothari
982550b92c fix(accounts): allow default bank account per company 2025-07-15 21:32:07 -05:00
MochaMind
26f234fdbd fix: sync translations from crowdin (#48605)
* fix: French translations

* fix: Portuguese translations

* fix: Persian translations

* fix: Arabic translations

* fix: Turkish translations

* fix: Polish translations

* fix: Swedish translations

* fix: Vietnamese translations

* fix: Chinese Simplified translations

* fix: Spanish translations

* fix: Czech translations

* fix: German translations

* fix: Hungarian translations

* fix: Italian translations

* fix: Dutch translations

* fix: Russian translations

* fix: Serbian (Cyrillic) translations

* fix: Portuguese, Brazilian translations

* fix: Thai translations

* fix: Croatian translations

* fix: Bosnian translations

* fix: Serbian (Latin) translations

* fix: Esperanto translations
2025-07-15 17:44:34 +02:00
venkat102
d6fd613272 fix(period closing voucher): closing account head debit and debit in account currency should be equal 2025-07-15 18:16:23 +05:30
rohitwaghchaure
480e76d98e Merge pull request #48611 from rohitwaghchaure/fixed-job-card-stock-entry
fix: confirmation dialog for submitting the stock entry
2025-07-15 18:12:10 +05:30
rohitwaghchaure
8b06468490 Merge pull request #48610 from rohitwaghchaure/fixed-support-43674-1
fix: added serial no condition
2025-07-15 18:04:04 +05:30
Rohit Waghchaure
ea3d4ced5e fix: Confirmation dialog for submitting the stock entry 2025-07-15 17:52:08 +05:30
Rohit Waghchaure
bb7ddd11f1 fix: added serial no condition 2025-07-15 17:27:00 +05:30
Diptanil Saha
05e7db2362 Merge pull request #48565 from aerele/fix/qty-change
fix(transaction): recalculate tax and total when quantity changes
2025-07-15 17:01:12 +05:30
Sagar Vora
34e0a939e6 Merge pull request #48607 from ljain112/silly-fix 2025-07-15 11:23:48 +00:00
ljain112
0da8ed2daa fix: fix party account field access 2025-07-15 16:45:58 +05:30
Khushi Rawat
0caa0371dc Merge pull request #48360 from aerele/item-wise-sales-register-mode-of-payment
fix: fetch sales invoice based on mode_of_payment in item-wise sales register
2025-07-15 15:49:46 +05:30
Karm Soni
7a266113ed fix: warehouse filter query by chaining conditions 2025-07-15 15:15:31 +05:30
ruthra kumar
e725780c6d Merge pull request #48535 from ljain112/fix-dda
fix: handle cases where distributed discount amount is not set
2025-07-15 15:07:06 +05:30
rohitwaghchaure
0fb6b4eaf6 Merge pull request #48408 from aerele/make_purchase_order_for_default_supplier
fix: resolve bundle item into line item if againt default supplier ch…
2025-07-15 15:05:48 +05:30
rohitwaghchaure
403220c69a Merge pull request #48595 from rohitwaghchaure/fixed-support-43674
fix: system was allowing credit notes with serial numbers for any customer
2025-07-15 14:56:58 +05:30
rohitwaghchaure
6150106dee Merge pull request #48588 from mihir-kandoi/st43481
perf: optimize code for subcontracting
2025-07-15 14:14:24 +05:30
Rohit Waghchaure
e073075834 fix: system was allowing credit notes with serial numbers for any customer 2025-07-15 14:00:04 +05:30
Karm Soni
fca9843fc2 fix: handle empty warehouse condition in get_warehouse_condition function; typo; 2025-07-15 13:39:39 +05:30
Karm Soni
169caaf66f fix: use the item_query for get_data 2025-07-15 13:23:09 +05:30
ruthra kumar
dea3e326ba Merge pull request #48536 from frappe/l10n_develop
fix: sync translations from crowdin
2025-07-15 12:42:06 +05:30
MochaMind
26ecd7fd1b fix: Persian translations 2025-07-15 12:26:11 +05:30
MochaMind
f877f87b01 fix: Swedish translations 2025-07-15 12:26:11 +05:30
MochaMind
d33851367b fix: Persian translations 2025-07-15 12:26:11 +05:30
MochaMind
4c5d753ade fix: Turkish translations 2025-07-15 12:26:11 +05:30
Mihir Kandoi
bc6f69ad54 perf: optimize code for subcontracting 2025-07-15 11:55:03 +05:30
rohitwaghchaure
ee2ea11458 Merge pull request #48582 from barredterra/sabb-translatability
fix: make labels in serial_batch_prompt translatable
2025-07-15 11:53:59 +05:30
MochaMind
e1b2956cdb chore: update POT file (#48583) 2025-07-14 22:25:42 +02:00
barredterra
8757800888 fix: make labels in serial_batch_prompt translatable 2025-07-14 21:47:00 +02:00
Raffael Meyer
d99f258d61 fix(Employee): add context to status in List View (#48576) 2025-07-14 15:37:00 +02:00
Diptanil Saha
b8bf4319ac Merge pull request #48411 from thomasantony12/employee_query
fix: employee search based on the fields mentioned in the employee doctype search fields
2025-07-14 18:58:09 +05:30
mergify[bot]
7ae642e6fa Merge branch 'develop' into employee_query 2025-07-14 13:10:07 +00:00
Mihir Kandoi
70204b4464 Merge pull request #48526 from mihir-kandoi/st43470
fix: gross margin not set in project on submission of stock entry
2025-07-14 17:11:40 +05:30
rohitwaghchaure
e0895be7e9 Merge pull request #48568 from mihir-kandoi/st43465
fix: recalculate qty issue for stock reco
2025-07-14 17:07:15 +05:30
Mihir Kandoi
815220a3c6 Merge pull request #48542 from mihir-kandoi/st43593
fix: field name of price_list in material request
2025-07-14 16:43:31 +05:30
Mihir Kandoi
668574e4f0 fix: incorrect if condition 2025-07-14 16:36:29 +05:30
Mihir Kandoi
adb9a6bc15 fix: field name of price_list in material request 2025-07-14 16:27:14 +05:30
Mihir Kandoi
597d5aff02 fix: incorrect stock reco sle 2025-07-14 16:25:29 +05:30
ruthra kumar
896b21e78b Merge pull request #48321 from ljain112/fix-client-item-tax-template
fix: fetch item tax template after setting `base_net_rate`
2025-07-14 15:01:59 +05:30
ljain112
816b84be02 fix: handle cases where distributed discount amount is not set 2025-07-14 14:56:12 +05:30
ruthra kumar
290a9b7804 Merge pull request #48435 from ljain112/fix-ui-account
fix: prevent creation of root accounts in account tree view
2025-07-14 14:44:50 +05:30
Bhavan23
ac7b6c6a3d fix(transaction): recalculate tax and total when quantity changes 2025-07-14 13:23:56 +05:30
ruthra kumar
3ccb209bfd Merge pull request #48540 from aerele/payable/receivable-summary
feat: add calculate_ageing_with option in summary reports
2025-07-14 11:38:02 +05:30
Diptanil Saha
f2ce84c161 Merge pull request #48539 from diptanilsaha/feat_gh_37933
feat: trial balance report account name and number in separate column
2025-07-14 11:21:53 +05:30
diptanilsaha
52a6856f6c feat: trial balance report account name and number in separate column 2025-07-14 11:05:04 +05:30
KerollesFathy
92a12d7fea fix: Add non-negative constraint to job capacity field in workstation 2025-07-13 13:03:01 +00:00
KerollesFathy
a2bb557570 feat: Add non-negative constraint to workstation cost fields 2025-07-13 12:44:09 +00:00
rohitwaghchaure
a73c555574 Merge pull request #48550 from ljain112/fix-test-batch
chore: fix flacky test and remove redundant code
2025-07-13 17:20:39 +05:30
rohitwaghchaure
25838ba9b0 Merge pull request #48509 from mihir-kandoi/fix-reservation-on-manufacture-entry
fix: stock reservation on manufacture stock entry
2025-07-13 14:29:25 +05:30
ljain112
e6b9e82b2f chore: return doc if item already exists for test 2025-07-12 13:07:52 +05:30
ljain112
de8c3ba968 chore: fix flacky test and remove redundant code 2025-07-12 12:48:01 +05:30
Thomas antony
de56faf862 chore: add missing key value 2025-07-12 10:18:34 +05:30
Thomas antony
89233d2b87 Merge branch 'frappe:develop' into employee_query 2025-07-12 10:04:35 +05:30
Thomas antony
75a00928b5 chore: included value in "key" for search condition 2025-07-12 09:48:08 +05:30
l0gesh29
a3834eef46 feat: add calculate_ageing_with option in summary reports 2025-07-11 17:54:09 +05:30
Diptanil Saha
b38d472d7c Merge pull request #48495 from ljain112/refactor--acc-settings
perf: use `cached_doc` for Account Settings
2025-07-11 14:41:30 +05:30
Asmita Hase
96bfe7ccb7 Merge pull request #48395 from mahsem/eetr 2025-07-11 11:59:24 +05:30
ruthra kumar
146f98d026 Merge pull request #48508 from frappe/l10n_develop
fix: sync translations from crowdin
2025-07-11 11:49:49 +05:30
Mihir Kandoi
ec578ba231 fix: gross margin not set in project on submission of stock entry 2025-07-11 11:04:29 +05:30
rohitwaghchaure
29d94f71f3 Merge pull request #48512 from rohitwaghchaure/fixed-support-43409
fix: incorrect last sle for no batch wise valuation
2025-07-11 11:01:16 +05:30
Mihir Kandoi
a878dd3837 fix: stock reservation on manufacture stock entry 2025-07-11 10:31:17 +05:30
Rohit Waghchaure
93d3eb662f fix: incorrect last sle for no batch wise valuation 2025-07-11 09:03:04 +05:30
Ibrahim
d8371c41cf fix: add undefined check for cur_frm in lead doctype (#48522) 2025-07-10 23:24:08 +03:00
Diptanil Saha
73c08c1ecd Merge pull request #48517 from diptanilsaha/fix_pos_payment_keypress
fix: pos payment method amount using numpad and keyboard
2025-07-10 23:11:07 +05:30
Mihir Kandoi
ea05f81024 Merge pull request #48514 from mihir-kandoi/st43398
fix: no attribute error in old subcontracting flow
2025-07-10 23:02:18 +05:30
Mihir Kandoi
e16014e448 Merge pull request #48513 from mihir-kandoi/st42779
fix: error in available serial no report is no serial no present in company
2025-07-10 22:51:02 +05:30
diptanilsaha
15b1609d88 fix: pos payment method amount using numpad and keyboard 2025-07-10 22:47:10 +05:30
Mihir Kandoi
51751a7a05 fix: no attribute error in old subcontracting flow 2025-07-10 22:46:56 +05:30
Mihir Kandoi
0ae60b8b61 fix: error in available serial no report is no serial no present in company 2025-07-10 22:34:35 +05:30
Mihir Kandoi
7af9fa36d7 Merge pull request #48510 from mihir-kandoi/st42929
fix: missing parameter in precision function
2025-07-10 19:08:16 +05:30
Mihir Kandoi
3886641887 fix: missing parameter in precision function 2025-07-10 18:52:13 +05:30
MochaMind
b651d3f622 fix: Persian translations 2025-07-10 14:26:30 +05:30
MochaMind
d72825e279 fix: Portuguese translations 2025-07-10 14:26:24 +05:30
Diptanil Saha
6e73fbedb0 Merge pull request #48506 from diptanilsaha/fix_st_43111
fix: pos adding item multiple times on applying item group filter
2025-07-10 12:36:06 +05:30
diptanilsaha
e9f99e5a3f fix: pos adding item multiple times on item group filter 2025-07-10 12:31:15 +05:30
Mihir Kandoi
9f44de50eb Merge pull request #48503 from mihir-kandoi/convert-string-to-date
fix: invalid comparison error in sabb.py
2025-07-10 11:04:59 +05:30
Mihir Kandoi
ec1faf02ed fix: invalid comparison error in sabb.py 2025-07-10 10:48:33 +05:30
Mihir Kandoi
2397abaee5 Merge pull request #48499 from mihir-kandoi/st43376
fix: use planned_qty instead of pending_qty to check if WO should be created against PP
2025-07-09 21:03:30 +05:30
Mihir Kandoi
b11bf8eb79 fix: use planned_qty instead of pending_qty to check if WO should be created against PP 2025-07-09 20:59:11 +05:30
l0gesh29
f3460ec840 fix: carry forward the delivered_by_supplier check to PO 2025-07-09 19:26:41 +05:30
rohitwaghchaure
fbe14b79cc Merge pull request #48490 from rohitwaghchaure/fixed-support-39446
feat: update the modified date of the SLE after reposting
2025-07-09 19:20:45 +05:30
Patrick Eißler
ebd45878c3 feat(BOM): improve tree display with item_name and qty (#48176)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-07-09 13:52:12 +02:00
rohitwaghchaure
91881fad6b Merge pull request #48488 from rohitwaghchaure/fixe-support-42043
feat: parent item group support in Stock Projected Qty report
2025-07-09 16:48:17 +05:30
Rohit Waghchaure
c2cd4934e7 feat: update the modified date of the SLE after reposting 2025-07-09 16:45:13 +05:30
rohitwaghchaure
48485c27ec Merge pull request #48487 from rohitwaghchaure/feat-batch-rate-report
feat: batch rate (valuation) in Batch-Wise Balance History report
2025-07-09 16:28:19 +05:30
Rohit Waghchaure
6e80d89d13 feat: parent item group support in Stock Projected Qty report 2025-07-09 16:18:21 +05:30
Rohit Waghchaure
8a2a845a16 feat: batch rate (valuation) in Batch-Wise Balance History report 2025-07-09 16:07:20 +05:30
Diptanil Saha
376dcf50ec feat: filter to display trial balance report without group account (#48486) 2025-07-09 15:44:46 +05:30
ljain112
751f3abd95 perf: use cached_doc for Account Settings 2025-07-09 13:28:37 +05:30
rohitwaghchaure
6e98adecdd Merge pull request #48481 from rohitwaghchaure/fixed-support-43199
fix: stock settings save issue
2025-07-09 12:02:46 +05:30
Rohit Waghchaure
64ae1ec367 fix: stock settings save issue 2025-07-09 11:43:09 +05:30
ruthra kumar
b937b18e3d Merge pull request #47892 from ruthra-kumar/ar_report_procedures_and_sql
refactor: use sql for building voucher balance in Receivable report
2025-07-09 11:02:41 +05:30
ruthra kumar
fc8ca7d82c chore: rename method 2025-07-09 10:45:58 +05:30
ruthra kumar
7efeed54de refactor: build and pass match conditions as qb criterion 2025-07-09 10:43:41 +05:30
ruthra kumar
52c0df24e3 chore: drop unused utility method 2025-07-09 10:42:46 +05:30
ruthra kumar
9d0ebe3427 refactor: dynamic DB field types 2025-07-09 10:42:46 +05:30
ruthra kumar
1a90c0d031 refactor: better variable name 2025-07-09 10:42:46 +05:30
ruthra kumar
c5e35cc330 refactor: prefix-ed names for easy distinction 2025-07-09 10:42:46 +05:30
ruthra kumar
da32bb5f51 refactor: utility to drop existing procedures and include cost center 2025-07-09 10:42:46 +05:30
ruthra kumar
7b7440d44a refactor: order by posting date 2025-07-09 10:42:46 +05:30
ruthra kumar
e90c6a33bd refactor: call procedures based on config 2025-07-09 10:42:46 +05:30
ruthra kumar
8cf8f6abad refactor: introduce sql option for data fetch 2025-07-09 10:42:46 +05:30
ruthra kumar
097e74979f refactor: better readability 2025-07-09 10:42:45 +05:30
ruthra kumar
e5920c57aa refactor: using sql procedures for AR report
- dynamic filters are passed
2025-07-09 10:42:45 +05:30
Diptanil Saha
c714b724da fix: resolve sql error on dimension-wise accounts balance report (#48477) 2025-07-08 23:41:39 +05:30
Soham Kulkarni
f0697d8f27 Merge pull request #48349 from sokumon/remove-leaderboard
fix: remove Leaderboard shortcut
2025-07-08 22:57:20 +05:30
sokumon
27309d6714 fix: remove Leaderboard shortcut 2025-07-08 22:40:19 +05:30
Mihir Kandoi
c0631468db Merge pull request #48475 from mihir-kandoi/st42934 2025-07-08 22:14:52 +05:30
Mihir Kandoi
d10647a592 fix: indicator in material_request_list.js 2025-07-08 21:58:31 +05:30
Mihir Kandoi
269ac78a98 Merge pull request #48471 from mihir-kandoi/st43209
fix: sort available batches based on expiry when merging SLEs with SABB and those without
2025-07-08 19:47:44 +05:30
Mihir Kandoi
5c665c562a fix: test case 2025-07-08 19:31:03 +05:30
Mihir Kandoi
4d784b8fc7 fix: sort available batches based on expiry 2025-07-08 17:52:19 +05:30
ruthra kumar
dd027f09ac Merge pull request #48469 from ruthra-kumar/better_label_for_ignore_err
chore: better label for checkbox
2025-07-08 17:08:34 +05:30
ruthra kumar
2a16353cf6 Merge pull request #47142 from prateekkaramchandani/feat/ledger-preview-stock-entry
feat: Ledger Preview for Stock Entry
2025-07-08 17:03:19 +05:30
ruthra kumar
8c2e40e291 chore: better label for checkbox 2025-07-08 16:52:24 +05:30
Prateek Karamchandani
5f1ca4113d feat: Ledger Preview for Stock Entry 2025-07-08 16:46:44 +05:30
ruthra kumar
846f0350d8 Merge pull request #48427 from ljain112/fix-psoa-validations
fix: Add company validation to company related fields in Process Statement Of Accounts
2025-07-08 16:05:51 +05:30
Khushi Rawat
95a235e239 Merge pull request #48259 from aerele/item-wise-sales-register
fix: add not specified key for None respresented customer_group and t…
2025-07-08 16:01:57 +05:30
rohitwaghchaure
b7bf2fad84 Merge pull request #48378 from aerele/refactor-quality-inspection
fix: update item reference in quality inspection
2025-07-08 16:01:38 +05:30
ruthra kumar
d0537f2ee4 Merge pull request #48359 from aerele/get_fiscal_year_data
fix: get fiscal year based on date
2025-07-08 15:55:50 +05:30
Khushi Rawat
495afae178 Merge pull request #48402 from aerele/journal-entry-title-rename
fix: rename journal entry title on update
2025-07-08 15:54:33 +05:30
ruthra kumar
83f279410c Merge pull request #48450 from frappe/l10n_develop
fix: sync translations from crowdin
2025-07-08 15:46:06 +05:30
Mihir Kandoi
34f51ae0b2 Merge pull request #48456 from mihir-kandoi/st43167
fix: duplicate items being created when fetching items from warehouse in stock reco
2025-07-08 14:30:22 +05:30
ruthra kumar
5b619c7832 Merge pull request #48328 from ljain112/fix-pricing-rule
fix: update condition for blank tree fields in pricing rule
2025-07-08 14:22:15 +05:30
ruthra kumar
376191b31f Merge pull request #48361 from aerele/revert-48162
revert: do not convert exchange gain/loss amount to foreign currency
2025-07-08 14:22:04 +05:30
ruthra kumar
2c507c891c Merge pull request #48418 from ljain112/jv-paid-loan
chore: remove redundant field "paid_loan" from Journal Entry Doctype
2025-07-08 14:09:11 +05:30
Mihir Kandoi
73f6c29559 fix: duplicate items being created when fetching items from warehouse in stock reco 2025-07-08 13:27:10 +05:30
ruthra kumar
6cac0347ae Merge pull request #48416 from ljain112/refactor-payment-entry
refactor: remove duplicate reconciliation date logic
2025-07-08 13:03:25 +05:30
Diptanil Saha
f5de1ea5c8 Merge pull request #48343 from aerele/validate_with_previous_doc
fix: consider empty string in previous doc validation
2025-07-08 12:39:49 +05:30
rohitwaghchaure
161e336d97 Merge pull request #48444 from mihir-kandoi/st42689
refactor: remove do_reposting_for_each_stock_transaction feature
2025-07-08 12:31:06 +05:30
MochaMind
d2a4cebe54 fix: Persian translations 2025-07-08 12:17:56 +05:30
Diptanil Saha
88255d3d3d Merge pull request #48403 from aerele/validate_selling_price
fix: add selling price validation on update item
2025-07-08 12:14:06 +05:30
ruthra kumar
1cd2266da1 Merge pull request #48326 from ljain112/cost-center-advance-pe
fix: cost center for payment entry against advance payment doctypes in accounts payable/rece
2025-07-08 12:05:25 +05:30
Mihir Kandoi
288c3ee9c2 Merge pull request #48332 from mihir-kandoi/st42096
fix: valuation rate of raw materials in subcontracting receipt
2025-07-08 11:57:45 +05:30
Mihir Kandoi
cae34096c7 Merge pull request #48445 from mihir-kandoi/fix-mr-default-price-list
fix: use default buying price list when price list is falsy
2025-07-08 11:55:00 +05:30
Mihir Kandoi
27c73cf9e9 fix: use default buying price list when price list is falsy 2025-07-08 11:50:43 +05:30
Mihir Kandoi
84ea6afd01 fix: valuation rate of raw materials in subcontracting receipt 2025-07-08 11:42:07 +05:30
Mihir Kandoi
e342b1f7bd refactor: remove do_reposting_for_each_stock_transaction feature 2025-07-08 11:35:45 +05:30
rohitwaghchaure
9f32021d07 Merge pull request #48441 from frappe/revert-47918-fixed-support-40162
Revert "fix: stock reco qty with inventory dimension"
2025-07-08 10:36:18 +05:30
rohitwaghchaure
8ba66c9833 Revert "fix: stock reco qty with inventory dimension (#47918)"
This reverts commit 342cebc778.
2025-07-08 09:56:56 +05:30
ruthra kumar
2012045798 Merge pull request #48324 from ljain112/fix-pr-unreconcile
fix: update payment request outstanding on unreconciliation
2025-07-08 09:45:52 +05:30
MochaMind
7ec4d16403 fix: sync translations from crowdin (#48406) 2025-07-07 17:46:49 +02:00
Raffael Meyer
8cc6853c34 fix: make labels in error message translatable (#48327) 2025-07-07 17:44:56 +02:00
ljain112
3600f2f91b fix: prevent creation of root accounts in account tree view 2025-07-07 19:00:42 +05:30
rohitwaghchaure
7ed05e7d2d Merge pull request #48432 from rohitwaghchaure/fixed-support-42759
fix: fetch from parent optional in inventory dimension
2025-07-07 18:51:01 +07:00
Rohit Waghchaure
8aac6a6b18 fix: fetch from parent optional in inventory dimension 2025-07-07 17:01:01 +05:30
Mihir Kandoi
5fc07842eb Merge pull request #48428 from mihir-kandoi/st42480
fix: address not found when creating internal PR from DN
2025-07-07 15:20:14 +05:30
Mihir Kandoi
aa2c56e117 Merge pull request #48425 from mihir-kandoi/st42648-2
feat: add price list field to material request
2025-07-07 15:03:47 +05:30
Mihir Kandoi
97c48ed6d2 fix: address not found when creating internal PR from DN 2025-07-07 15:01:31 +05:30
ljain112
4e45e69247 fix: Add company validation to company related fields in Process Statement Of Accounts 2025-07-07 14:43:04 +05:30
Mihir Kandoi
0e881f2999 Merge pull request #48424 from mihir-kandoi/st42959
fix: item list and project not being set in work order when created from material request
2025-07-07 14:17:39 +05:30
Mihir Kandoi
f4c6bdf204 feat: add price list field to material request 2025-07-07 14:14:16 +05:30
Mihir Kandoi
099a5fbad9 fix: item list and project not being set in work order when created from material request 2025-07-07 13:01:41 +05:30
Karm Soni
e60c711fdc fix: correct query filter assignment in stock ledger and balance reports 2025-07-07 11:06:46 +05:30
MochaMind
0a41fe2541 chore: update POT file (#48417) 2025-07-06 14:57:09 +02:00
ljain112
901a89ebcd fix: do not create delinked payment ledger entries on cancel 2025-07-06 17:15:12 +05:30
ljain112
2ee463fa33 chore: remove redundant field "paid_loan" from Journal Entry Doctype 2025-07-06 15:24:45 +05:30
ljain112
398406082a refactor: remove duplicate reconciliation date logic 2025-07-06 15:03:06 +05:30
Lakshit Jain
277c1101fc fix: multiple fixes related Deferred Accounting 2025-07-06 14:55:45 +05:30
Diptanil Saha
ee0dd462b8 Merge pull request #48357 from aerele/fix-pos-merge-log
fix: add company field on POS Invoice Merge Log
2025-07-06 14:26:50 +05:30
ljain112
df0994c0d3 fix: query voucher outstanding only when all the conditions are true. 2025-07-06 14:09:05 +05:30
ljain112
fc622631c0 fix: do not query outstanding for Journal Entry 2025-07-06 13:59:07 +05:30
ljain112
46a6290ce9 perf: use cached value for account validations in gl and ple 2025-07-06 13:14:40 +05:30
thomasantony12
09541c52e1 fix: employee search based on the fields mentioned in the doctype searchfields 2025-07-06 11:22:24 +05:30
Kavin
9548f341bf test: test company fetching from POS Closing Entry 2025-07-05 21:59:53 +05:30
Kavin
b4b473185f fix: pass company on create_merge_logs 2025-07-05 21:58:07 +05:30
Kavin
d46b68230c fix: patch for updating company name on existing pos merge log records 2025-07-05 13:34:52 +05:30
Kavin
109658731b fix: add company field on POS Invoice Merge Log 2025-07-05 13:34:11 +05:30
l0gesh29
ec07549d5e fix: resolve bundle item into line item if againt default supplier checked 2025-07-05 12:48:50 +05:30
Diptanil Saha
90be3cddf7 fix: pos payment numpad error on currency precision not set (#48407) 2025-07-05 06:53:29 +00:00
Karm Soni
0a71ca6739 fix(test): update tests 2025-07-05 10:04:34 +05:30
Raffael Meyer
2928d39d58 fix(Quotation): hide buttons if user cannot use them (#48115) 2025-07-04 18:03:39 +00:00
Mihir Kandoi
407fdab487 feat: add subject field to project (#48368)
* feat: add subject field to project
2025-07-04 16:09:34 +00:00
ravibharathi656
9e633bddef chore: add none value 2025-07-04 20:03:25 +05:30
l0gesh29
327d067305 fix: add selling price validation on update item 2025-07-04 19:57:22 +05:30
ravibharathi656
acb9829159 fix: rename journal entry title on update 2025-07-04 19:26:55 +05:30
Mihir Kandoi
b0535bff34 Merge pull request #48372 from mihir-kandoi/st42648
fix: rate not being fetched for product bundles in material request
2025-07-04 12:45:34 +05:30
Mihir Kandoi
0da90f8092 Merge pull request #48374 from mihir-kandoi/st42781-d
fix: LCV from PR order mismatch
2025-07-04 12:45:02 +05:30
l0gesh29
efb8e7c0e4 fix: get fiscal year based on date 2025-07-04 12:23:06 +05:30
mahsem
80d6779210 fix: employee_exit_translatability 2025-07-04 08:26:52 +02:00
Mihir Kandoi
32a45cf635 fix: LCV from PR order mismatch 2025-07-04 11:37:15 +05:30
Mihir Kandoi
45c7bac2d0 fix: rate not being fetched for product bundles in material request 2025-07-04 11:36:51 +05:30
MochaMind
59ae667cce fix: sync translations from crowdin (#48316)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-07-04 05:50:27 +00:00
Diptanil Saha
50bf4017d6 fix: pos minor issues (#48384)
* fix: remove tax rate on pos

* fix: use toggle components to load invoices

* refactor: remove resize selector
2025-07-03 22:50:23 +05:30
Diptanil Saha
5f721f01d3 fix: pos recent order display customer code and name (#48379) 2025-07-03 22:49:09 +05:30
Karm Soni
f2afd98725 feat: update stock ledger report to support multi-select for warehouses and items 2025-07-03 18:04:05 +05:30
Karm Soni
2882576479 refactor: use existing functionality 2025-07-03 16:26:58 +05:30
Karm Soni
2ff1dcc391 feat: enhance apply_warehouse_filter to support multiple warehouses in filters 2025-07-03 16:24:27 +05:30
l0gesh29
dd43594ad6 fix: consider empty string in previous doc validation 2025-07-03 16:04:19 +05:30
venkat102
c17ae703c7 revert: do not convert exchange gain/loss amount to foreign currency 2025-07-03 16:03:21 +05:30
pugazhendhivelu
9da5010265 fix: update item reference in quality inspection 2025-07-03 15:44:00 +05:30
ravibharathi656
39cd7a29df fix: fetch sales invoice based on mode_of_payment in item-wise sales register 2025-07-03 15:38:05 +05:30
Diptanil Saha
86b37782fe fix: pos payment section (#48366) 2025-07-03 15:16:07 +05:30
ruthra kumar
1ee8a9f257 Merge pull request #48375 from ljain112/fix-flaky-test-tds
chore: fix flaky test in Tax Withholding Details
2025-07-03 14:21:06 +05:30
ruthra kumar
704223e5d0 fix(test): flaky budget test case 2025-07-03 14:06:09 +05:30
ljain112
7ee2418f60 fix: sort tax withhodling details report by section code and transaction date 2025-07-03 13:34:33 +05:30
ljain112
14a2f98521 chore: fix flaky test in Tax Withholding Details 2025-07-03 13:11:37 +05:30
Mihir Kandoi
7dbc821731 Merge pull request #48333 from mihir-kandoi/fix-job-card-buttons
fix: multiple buttons in job card showing in a single row
2025-07-03 13:07:58 +05:30
Karm Soni
0d2a88bafc feat: update stock balance report to support multi-select for items and warehouses 2025-07-03 12:59:00 +05:30
Akhil Narang
072518ed96 build: bump dependencies (#48122)
* build(deps): drop `pycountry`

Framework includes this

Signed-off-by: Akhil Narang <me@akhilnarang.dev>

* build(deps): bump unidecode

Signed-off-by: Akhil Narang <me@akhilnarang.dev>

* build(deps): bump holidays

Signed-off-by: Akhil Narang <me@akhilnarang.dev>

* build(deps): pin googlemaps

Signed-off-by: Akhil Narang <me@akhilnarang.dev>

* build(deps): bump python-youtube

Signed-off-by: Akhil Narang <me@akhilnarang.dev>

---------

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2025-07-02 11:44:49 +05:30
rohitwaghchaure
863507ea28 Merge pull request #48173 from mihir-kandoi/st41207
fix: incorrect pending qty when creating PI from PO and PI rates differ from PO
2025-07-01 17:48:12 +05:30
ruthra kumar
0b7f73fa8b Merge pull request #48325 from ljain112/refactor-po-validate
perf: use get_all instead of get_value for validating po dates
2025-07-01 16:23:44 +05:30
ruthra kumar
37727448f6 Merge pull request #48244 from aerele/reconcile-drcr-posting-date
fix: use gain_loss_posting_date instead of today
2025-07-01 15:41:43 +05:30
Mihir Kandoi
74df63a28a fix: multiple button in job card showing in a single row 2025-07-01 11:44:03 +05:30
Jeba Jebas
bb62a01c0d 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>
2025-07-01 10:11:37 +05:30
ljain112
7e0e9db4d2 fix: update condition for blank tree fields in pricing rule 2025-06-30 19:12:49 +05:30
ljain112
48e8e85617 refactor: function to fetch advance payment doctypes 2025-06-30 17:49:56 +05:30
ljain112
8f19f14004 fix: cost center for payment entry against advance payment doctypes in accounts Payable/Receivable report 2025-06-30 17:35:08 +05:30
ljain112
aac4ac0fae perf: use get_all instead of get_value for validating po dates 2025-06-30 15:58:04 +05:30
ljain112
31d12517f0 chore: fix test case for payment request 2025-06-30 15:04:27 +05:30
ljain112
8098229b55 fix: update payment request outstanding on unreconciliation 2025-06-30 14:18:40 +05:30
Diptanil Saha
8ea9cb1d34 Merge pull request #48279 from aerele/pos-search-by-customer-name
fix(pos invoice): search using customer name
2025-06-30 14:13:25 +05:30
ravibharathi656
6a401bcfbb refactor: use or_filters for customer and customer_name 2025-06-30 12:51:14 +05:30
ravibharathi656
20fd071c4e fix(pos invoice): search using customer name 2025-06-30 12:51:14 +05:30
ljain112
db654d5e59 fix: fetch item tax template after setting base_net_rate 2025-06-30 12:31:39 +05:30
rohitwaghchaure
abfff79095 Merge pull request #48298 from FHenry/dev_fix_support_42326
fix: default UOMs by new Stock Entry created by Stock Level section button (when Item is batch or serial)
2025-06-30 11:02:05 +05:30
rohitwaghchaure
8aafd893ed Merge pull request #48240 from mihir-kandoi/st41963
refactor: bom stock report
2025-06-30 11:01:14 +05:30
rohitwaghchaure
21118d5373 Merge pull request #48184 from iamkhanraheel/update-disassembly-items
fix: Disassembly order items calculation in stock entry & track it in work order
2025-06-30 11:00:58 +05:30
ruthra kumar
2c7262b033 Merge pull request #48291 from ljain112/fix-bank-clearance
perf: use lazy doc for updating bank clearance_date
2025-06-30 10:34:09 +05:30
ruthra kumar
dc1be35dbb Merge pull request #48271 from aerele/company-default-currency-for-commission
fix: use company default currency in amount_eligible_for_commission
2025-06-30 10:08:51 +05:30
ruthra kumar
ee3f4c21be Merge pull request #48304 from zaqoutabed/translation-patch-1
chore: fix translation message
2025-06-30 10:02:58 +05:30
Abdallah A. Zaqout
bc002937ad chore: fix translation message 2025-06-30 09:47:30 +05:30
rohitwaghchaure
2af95d2339 Merge pull request #48310 from rohitwaghchaure/fixed-support-40224
fix: accounting entries for standalone credit notes
2025-06-30 09:38:37 +05:30
Khushi Rawat
d69d5b498d Merge pull request #48311 from khushi8112/validate-asset-status-for-repair
fix: validate asset status for repair
2025-06-30 00:55:29 +05:30
khushi8112
cfe04a2aaf test: asset status validation 2025-06-30 00:29:23 +05:30
khushi8112
c6baa34812 fix: validate asset before repair 2025-06-29 22:46:39 +05:30
Rohit Waghchaure
52177cffcd fix: accounting entries for standalone credit notes 2025-06-29 21:45:57 +05:30
MochaMind
344bcf1448 fix: sync translations from crowdin (#48302) 2025-06-29 16:01:36 +02:00
MochaMind
45292700d4 chore: update POT file (#48307) 2025-06-29 13:12:24 +02:00
Diptanil Saha
c742a1dbe9 feat: partly paid pos invoices (#48246)
* fix: partial payment in pos

* fix: show alerts for update failure

* fix: partial payment validation

* fix: remove setting clearance date

* fix: partly paid invoices in pos

* fix: throw error if user tries to make payment for consolidated invoice

* fix: include unpaid invoices in partly paid invoice filter

* refactor: function rename

* feat: button to open form view for partly paid invoices in pos order summary

* fix: payment menu item visible for unpaid invoices

* refactor: update_payments function

* fix: set outstanding amount for pos invoice

* test: partly paid pos invoices

* test: removed frappe.db.commit

* refactor: using before_submit to set outstanding amount
2025-06-28 00:48:23 +05:30
rohitwaghchaure
1cb7d5126c Merge pull request #48296 from rohitwaghchaure/fixed-support-42161
fix: not able to save material request
2025-06-27 16:24:31 +05:30
Florian HENRY
e7da4992f3 fix: default UOMs by new stock Entry created by Stock Level section button 2025-06-27 12:54:28 +02:00
Rohit Waghchaure
c5e36eb323 fix: not able to save material request 2025-06-27 16:07:08 +05:30
rohitwaghchaure
4dbf4a214d Merge pull request #48293 from rohitwaghchaure/fixed-support-42204
fix: option to pick serial / batch for asset repair
2025-06-27 15:28:01 +05:30
Rohit Waghchaure
ae77c609ff fix: option to pick serial / batch for asset repair 2025-06-27 14:53:11 +05:30
MochaMind
195911ce4e fix: sync translations from crowdin (#48268) 2025-06-27 10:45:05 +02:00
ljain112
d2983b977c perf: use lazy doc for updating clearance_date 2025-06-27 13:54:27 +05:30
ljain112
824a86c503 chore: validate all payment entries before updating the clearance_date 2025-06-27 13:53:16 +05:30
rohitwaghchaure
a0a8428483 Merge pull request #48243 from rohitwaghchaure/fixed-status-stock-reservation
fix: multiple fixes related to stock reservation
2025-06-27 13:51:07 +05:30
Rohit Waghchaure
87a472c2d7 fix: multiple fixes related to stock reservation 2025-06-27 12:46:02 +05:30
Soham Kulkarni
a926c7eafd Merge pull request #48288 from sokumon/remove-newsletter
fix: remove newsletter related code
2025-06-27 11:59:40 +05:30
sokumon
b630ccc8e6 fix: remove newsletter related code 2025-06-27 01:21:33 +05:30
Raffael Meyer
0426b37f32 fix: use label "State/Province" for translatability (#48273) 2025-06-26 20:20:17 +02:00
Diptanil Saha
e1d9f863c6 fix: customer section on pos item cart (#48284)
* fix: customer recent transactions

* fix: pos customer section display customer_name instead of customer name
2025-06-26 22:49:18 +05:30
l0gesh29
24cc711a70 fix: add not specified key for None respresented customer_group and territory 2025-06-26 18:32:54 +05:30
ravibharathi656
7c7b392789 fix: use company default currency in amount_eligible_for_commission 2025-06-26 18:09:23 +05:30
Priyansh Shah
fab0f4f337 fix: Multiple Issues in Pick List to Delivery Note Flow (#48206)
* fix: get items from Pick List to DN even if not linked to Sales Order

* refactor: consistently return dn; better place to convert json to doc

* fix: update DN if already created instead of creating new DN when SO is not present in pick list location

* fix: set correct warehouse,batch no and serial no in packed items and allow multiple customer in a pick list

* fix: return 0 for minimum possible bundles if none exist

* fix: test cases

* test: add tests for product bundle items in pick list and handling pick lists with and without sales orders

* fix: minor change to test case

* refactor: simplify pick list creation by using create_pick_list function

* fix: update delivery note creation logic and remove unused function

* test: update pick list test for packed items

* fix: add conditional check for sales_order before setting customer in delivery note

* test: add test case for packed item multiple times in so

---------

Co-authored-by: Smit Vora <smitvora203@gmail.com>
2025-06-26 17:55:48 +05:30
iamkhanraheel
aee26c3550 test: added test case for disassembly order 2025-06-26 17:21:34 +05:30
Diptanil Saha
1e929e2c6c fix: pos opening and closing validation (#48059)
* fix: pos opening and closing validation

* test: pos opening entry tests

* test: added test for pos opening entry

* fix: patch to set status cancelled on cancelled POS Opening Entry and POS Closing Entry

* fix: error messages
2025-06-26 16:26:53 +05:30
ravibharathi656
0585bc5aef fix: use gain_loss_posting_date instead of today 2025-06-24 18:48:22 +05:30
Mihir Kandoi
ee4e0c646d refactor: bom stock report 2025-06-24 18:13:38 +05:30
Mihir Kandoi
ea6ff2defe fix: test case 2025-06-24 12:24:58 +05:30
Mihir Kandoi
ab77ee7f5a fix: incorrect pending qty when creating PI from PO and PI rates differ from PO 2025-06-24 12:15:03 +05:30
iamkhanraheel
ce6ace4b8a fix: func parameters 2025-06-22 21:33:02 +05:30
iamkhanraheel
3e4d160626 fix: disassemble qty calculation & max calculation to be allowed to create it 2025-06-21 01:14:26 +05:30
ravibharathi656
1e37fd8991 fix: include child doctypes in allow_on_submit patch for accounting dimensions 2025-06-19 18:47:13 +05:30
ravibharathi656
55e79c4dfd fix: enable allow_on_submit for accounting dimensions in allowed doctypes 2025-06-19 18:46:34 +05:30
ravibharathi656
fbd8fd7d22 fix: include child doctypes in repostable accounting types 2025-06-19 18:45:34 +05:30
466 changed files with 299914 additions and 165304 deletions

12
.coderabbit.yml Normal file
View File

@@ -0,0 +1,12 @@
reviews:
auto_review:
ignore_title_keywords:
- "sync translations"
- "update POT file"
- "style: "
review_status: false
poem: false
collapse_walkthrough: true
sequence_diagrams: false
changed_files_summary: false
high_level_summary: false

View File

@@ -8,6 +8,9 @@ on:
- '**.md'
- '**.html'
- '**.csv'
- 'crowdin.yml'
- '.coderabbit.yml'
- '.mergify.yml'
workflow_dispatch:
permissions:

View File

@@ -10,6 +10,9 @@ on:
- "**.md"
- "**.html"
- "**.csv"
- 'crowdin.yml'
- '.coderabbit.yml'
- '.mergify.yml'
permissions:
contents: read

View File

@@ -9,6 +9,9 @@ on:
- "**.css"
- "**.md"
- "**.html"
- 'crowdin.yml'
- '.coderabbit.yml'
- '.mergify.yml'
permissions:
contents: read

View File

@@ -9,6 +9,9 @@ on:
- '**.css'
- '**.md'
- '**.html'
- 'crowdin.yml'
- '.coderabbit.yml'
- '.mergify.yml'
schedule:
# Run everday at midnight UTC / 5:30 IST
- cron: "0 0 * * *"

View File

@@ -6,6 +6,9 @@ on:
- '**.js'
- '**.md'
- '**.html'
- 'crowdin.yml'
- '.coderabbit.yml'
- '.mergify.yml'
types: [opened, labelled, synchronize, reopened]
concurrency:

View File

@@ -32,8 +32,6 @@ repos:
cypress/.*|
.*node_modules.*|
.*boilerplate.*|
erpnext/public/js/controllers/.*|
erpnext/templates/pages/order.js|
erpnext/templates/includes/.*
)$

View File

@@ -8,17 +8,16 @@ erpnext/assets/ @khushi8112
erpnext/regional @ruthra-kumar
erpnext/selling @ruthra-kumar
erpnext/support/ @ruthra-kumar
pos*
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/ @ruthra-kumar @rohitwaghchaure
erpnext/controllers/ @ruthra-kumar @rohitwaghchaure @mihir-kandoi
erpnext/patches/ @ruthra-kumar
.github/ @ruthra-kumar
pyproject.toml @akhilnarang
pyproject.toml @ruthra-kumar

View File

@@ -10,8 +10,10 @@ from frappe.contacts.doctype.address.address import (
class ERPNextAddress(Address):
def validate(self):
self.validate_reference()
self.update_compnay_address()
super().validate()
self.update_company_address()
if hasattr(super(), "validate"):
super().validate()
def link_address(self):
"""Link address based on owner"""
@@ -20,7 +22,7 @@ class ERPNextAddress(Address):
return super().link_address()
def update_compnay_address(self):
def update_company_address(self):
for link in self.get("links"):
if link.link_doctype == "Company":
self.is_your_company_address = 1
@@ -38,6 +40,10 @@ class ERPNextAddress(Address):
"""
After Address is updated, update the related 'Primary Address' on Customer.
"""
if hasattr(super(), "on_update"):
super().on_update()
address_display = get_address_display(self.as_dict())
filters = {"customer_primary_address": self.name}
customers = frappe.db.get_all("Customer", filters=filters, as_list=True)

View File

@@ -167,7 +167,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:
@@ -210,7 +210,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):
@@ -259,7 +259,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():
@@ -302,7 +302,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

@@ -270,12 +270,14 @@ frappe.treeview_settings["Account"] = {
label: __("View Ledger"),
click: function (node, btn) {
frappe.route_options = {
account: node.label,
from_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
to_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
company:
frappe.treeview_settings["Account"].treeview.page.fields_dict.company.get_value(),
};
if (node.parent_label) {
frappe.route_options["account"] = node.label;
}
frappe.set_route("query-report", "General Ledger");
},
btnClass: "hidden-xs",

View File

@@ -18,6 +18,7 @@ def create_charts(
accounts = []
def _import_accounts(children, parent, root_type, root_account=False):
nonlocal custom_chart
for account_name, child in children.items():
if root_account:
root_type = child.get("root_type")
@@ -55,7 +56,8 @@ def create_charts(
"account_number": account_number,
"account_type": child.get("account_type"),
"account_currency": child.get("account_currency")
or frappe.get_cached_value("Company", company, "default_currency"),
if custom_chart
else frappe.get_cached_value("Company", company, "default_currency"),
"tax_rate": child.get("tax_rate"),
}
)

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

@@ -11,6 +11,9 @@
"cost_center",
"debit",
"credit",
"reporting_currency_exchange_rate",
"debit_in_reporting_currency",
"credit_in_reporting_currency",
"account_currency",
"debit_in_account_currency",
"credit_in_account_currency",
@@ -124,12 +127,30 @@
"fieldname": "is_period_closing_voucher_entry",
"fieldtype": "Check",
"label": "Is Period Closing Voucher Entry"
},
{
"fieldname": "debit_in_reporting_currency",
"fieldtype": "Currency",
"label": "Debit Amount in Reporting Currency",
"options": "Company:company:reporting_currency"
},
{
"fieldname": "credit_in_reporting_currency",
"fieldtype": "Currency",
"label": "Credit Amount in Reporting Currency",
"options": "Company:company:reporting_currency"
},
{
"fieldname": "reporting_currency_exchange_rate",
"fieldtype": "Float",
"label": "Reporting Currency Exchange Rate",
"precision": "9"
}
],
"icon": "fa fa-list",
"in_create": 1,
"links": [],
"modified": "2024-03-27 13:05:56.710541",
"modified": "2025-08-22 19:13:50.400404",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account Closing Balance",
@@ -158,7 +179,8 @@
"role": "Auditor"
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -2,12 +2,15 @@
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import cint, cstr
from frappe.utils import cint, cstr, flt
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
)
from erpnext.exceptions import ReportingCurrencyExchangeNotFoundError
from erpnext.setup.utils import get_exchange_rate
class AccountClosingBalance(Document):
@@ -26,12 +29,15 @@ class AccountClosingBalance(Document):
cost_center: DF.Link | None
credit: DF.Currency
credit_in_account_currency: DF.Currency
credit_in_reporting_currency: DF.Currency
debit: DF.Currency
debit_in_account_currency: DF.Currency
debit_in_reporting_currency: DF.Currency
finance_book: DF.Link | None
is_period_closing_voucher_entry: DF.Check
period_closing_voucher: DF.Link | None
project: DF.Link | None
reporting_currency_exchange_rate: DF.Float
# end: auto-generated types
pass
@@ -55,6 +61,7 @@ def make_closing_entries(closing_entries, voucher_name, company, closing_date):
"closing_date": closing_date,
}
)
set_amount_in_reporting_currency(cle, company, closing_date)
cle.flags.ignore_permissions = True
cle.flags.ignore_links = True
cle.submit()
@@ -144,3 +151,29 @@ def get_previous_closing_entries(company, closing_date, accounting_dimensions):
entries = query.run(as_dict=1)
return entries
def set_amount_in_reporting_currency(cle, company, closing_date):
default_currency, reporting_currency = frappe.get_cached_value(
"Company", company, ["default_currency", "reporting_currency"]
)
reporting_currency_exchange_rate = get_exchange_rate(default_currency, reporting_currency, closing_date)
if not reporting_currency_exchange_rate:
frappe.throw(
title=_("Reporting Currency Exchange Not Found"),
msg=_(
"Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually."
).format(default_currency, reporting_currency, closing_date),
exc=ReportingCurrencyExchangeNotFoundError,
)
debit_in_reporting_currency = flt(cle.get("debit", 0) * reporting_currency_exchange_rate)
credit_in_reporting_currency = flt(cle.get("credit", 0) * reporting_currency_exchange_rate)
cle.update(
{
"reporting_currency_exchange_rate": reporting_currency_exchange_rate,
"debit_in_reporting_currency": debit_in_reporting_currency,
"credit_in_reporting_currency": credit_in_reporting_currency,
}
)

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": "2024-03-27 13:05:57.199186",
"modified": "2025-08-08 14:13:22.203011",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension Filter",
@@ -139,8 +146,9 @@
}
],
"quick_entry": 1,
"row_format": "Dynamic",
"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):
@@ -71,7 +74,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
@@ -86,8 +89,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

@@ -26,9 +26,20 @@ frappe.ui.form.on("Accounts Settings", {
add_taxes_from_taxes_and_charges_template(frm) {
toggle_tax_settings(frm, "add_taxes_from_taxes_and_charges_template");
},
add_taxes_from_item_tax_template(frm) {
toggle_tax_settings(frm, "add_taxes_from_item_tax_template");
},
drop_ar_procedures: function (frm) {
frm.call({
doc: frm.doc,
method: "drop_ar_sql_procedures",
callback: function (r) {
frappe.show_alert(__("Procedures dropped"), 5);
},
});
},
});
function toggle_tax_settings(frm, field_name) {

View File

@@ -42,6 +42,7 @@
"show_payment_schedule_in_print",
"item_price_settings_section",
"maintain_same_internal_transaction_rate",
"fetch_valuation_rate_for_internal_transaction",
"column_break_feyo",
"maintain_same_rate_action",
"role_to_override_stop_action",
@@ -90,6 +91,8 @@
"receivable_payable_remarks_length",
"accounts_receivable_payable_tuning_section",
"receivable_payable_fetch_method",
"column_break_ntmi",
"drop_ar_procedures",
"legacy_section",
"ignore_is_opening_check_for_reporting",
"payment_request_settings",
@@ -556,7 +559,7 @@
"fieldname": "receivable_payable_fetch_method",
"fieldtype": "Select",
"label": "Data Fetch Method",
"options": "Buffered Cursor\nUnBuffered Cursor"
"options": "Buffered Cursor\nUnBuffered Cursor\nRaw SQL"
},
{
"fieldname": "accounts_receivable_payable_tuning_section",
@@ -631,6 +634,23 @@
"fieldname": "add_taxes_from_taxes_and_charges_template",
"fieldtype": "Check",
"label": "Automatically Add Taxes from Taxes and Charges Template"
},
{
"fieldname": "column_break_ntmi",
"fieldtype": "Column Break"
},
{
"depends_on": "eval:doc.receivable_payable_fetch_method == \"Raw SQL\"",
"description": "Drops existing SQL Procedures and Function setup by Accounts Receivable report",
"fieldname": "drop_ar_procedures",
"fieldtype": "Button",
"label": "Drop Procedures"
},
{
"default": "0",
"fieldname": "fetch_valuation_rate_for_internal_transaction",
"fieldtype": "Check",
"label": "Fetch Valuation Rate for Internal Transaction"
}
],
"grid_page_length": 50,
@@ -639,7 +659,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-06-23 15:55:33.346398",
"modified": "2025-07-18 13:56:47.192437",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -49,6 +49,7 @@ class AccountsSettings(Document):
enable_immutable_ledger: DF.Check
enable_party_matching: DF.Check
exchange_gain_loss_posting_date: DF.Literal["Invoice", "Payment", "Reconciliation Date"]
fetch_valuation_rate_for_internal_transaction: DF.Check
frozen_accounts_modifier: DF.Link | None
general_ledger_remarks_length: DF.Int
ignore_account_closing_balance: DF.Check
@@ -59,7 +60,7 @@ class AccountsSettings(Document):
merge_similar_account_heads: DF.Check
over_billing_allowance: DF.Currency
post_change_gl_entries: DF.Check
receivable_payable_fetch_method: DF.Literal["Buffered Cursor", "UnBuffered Cursor"]
receivable_payable_fetch_method: DF.Literal["Buffered Cursor", "UnBuffered Cursor", "Raw SQL"]
receivable_payable_remarks_length: DF.Int
reconciliation_queue_size: DF.Int
role_allowed_to_over_bill: DF.Link | None
@@ -149,8 +150,16 @@ class AccountsSettings(Document):
if self.add_taxes_from_item_tax_template and self.add_taxes_from_taxes_and_charges_template:
frappe.throw(
_("You cannot enable both the settings '{0}' and '{1}'.").format(
frappe.bold(self.meta.get_label("add_taxes_from_item_tax_template")),
frappe.bold(self.meta.get_label("add_taxes_from_taxes_and_charges_template")),
frappe.bold(_(self.meta.get_label("add_taxes_from_item_tax_template"))),
frappe.bold(_(self.meta.get_label("add_taxes_from_taxes_and_charges_template"))),
),
title=_("Auto Tax Settings Error"),
)
@frappe.whitelist()
def drop_ar_sql_procedures(self):
from erpnext.accounts.report.accounts_receivable.accounts_receivable import InitSQLProceduresForAR
frappe.db.sql(f"drop function if exists {InitSQLProceduresForAR.genkey_function_name}")
frappe.db.sql(f"drop procedure if exists {InitSQLProceduresForAR.init_procedure_name}")
frappe.db.sql(f"drop procedure if exists {InitSQLProceduresForAR.allocate_procedure_name}")

View File

@@ -12,7 +12,8 @@
"against_voucher_no",
"amount",
"currency",
"event"
"event",
"delinked"
],
"fields": [
{
@@ -68,12 +69,20 @@
"label": "Company",
"options": "Company",
"read_only": 1
},
{
"default": "0",
"fieldname": "delinked",
"fieldtype": "Check",
"label": "DeLinked",
"read_only": 1
}
],
"grid_page_length": 50,
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-11-05 10:31:28.736671",
"modified": "2025-07-29 11:37:42.678556",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Advance Payment Ledger Entry",
@@ -107,7 +116,8 @@
"share": 1
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -1,9 +1,11 @@
# Copyright (c) 2024, 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.utils import get_advance_payment_doctypes, update_voucher_outstanding
class AdvancePaymentLedgerEntry(Document):
# begin: auto-generated types
@@ -19,9 +21,16 @@ class AdvancePaymentLedgerEntry(Document):
amount: DF.Currency
company: DF.Link | None
currency: DF.Link | None
delinked: DF.Check
event: DF.Data | None
voucher_no: DF.DynamicLink | None
voucher_type: DF.Link | None
# end: auto-generated types
pass
def on_update(self):
if (
self.against_voucher_type in get_advance_payment_doctypes()
and self.flags.update_outstanding == "Yes"
and not frappe.flags.is_reverse_depr_entry
):
update_voucher_outstanding(self.against_voucher_type, self.against_voucher_no, None, None, None)

View File

@@ -17,6 +17,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"section_break_8",
"rate",
"section_break_9",
@@ -95,6 +96,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

@@ -132,7 +132,8 @@
"fieldtype": "Data",
"in_list_view": 1,
"label": "IBAN",
"length": 30
"length": 34,
"options": "IBAN"
},
{
"fieldname": "column_break_12",
@@ -208,6 +209,7 @@
"label": "Disabled"
}
],
"grid_page_length": 50,
"links": [
{
"group": "Transactions",
@@ -250,7 +252,7 @@
"link_fieldname": "default_bank_account"
}
],
"modified": "2024-10-30 09:41:14.113414",
"modified": "2025-08-29 12:32:01.081687",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Account",
@@ -282,9 +284,10 @@
"write": 1
}
],
"row_format": "Dynamic",
"search_fields": "bank,account",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -52,7 +52,6 @@ class BankAccount(Document):
def validate(self):
self.validate_company()
self.validate_iban()
self.validate_account()
self.update_default_bank_account()
@@ -72,35 +71,6 @@ class BankAccount(Document):
if self.is_company_account and not self.company:
frappe.throw(_("Company is mandatory for company account"))
def validate_iban(self):
"""
Algorithm: https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN
"""
# IBAN field is optional
if not self.iban:
return
def encode_char(c):
# Position in the alphabet (A=1, B=2, ...) plus nine
return str(9 + ord(c) - 64)
# remove whitespaces, upper case to get the right number from ord()
iban = "".join(self.iban.split(" ")).upper()
# Move country code and checksum from the start to the end
flipped = iban[4:] + iban[:4]
# Encode characters as numbers
encoded = [encode_char(c) if ord(c) >= 65 and ord(c) <= 90 else c for c in flipped]
try:
to_check = int("".join(encoded))
except ValueError:
frappe.throw(_("IBAN is not valid"))
if to_check % 97 != 1:
frappe.throw(_("IBAN is not valid"))
def update_default_bank_account(self):
if self.is_default and not self.disabled:
frappe.db.set_value(
@@ -109,6 +79,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,
},
@@ -117,15 +88,6 @@ class BankAccount(Document):
)
@frappe.whitelist()
def make_bank_account(doctype, docname):
doc = frappe.new_doc("Bank Account")
doc.party_type = doctype
doc.party = docname
return doc
def get_party_bank_account(party_type, party):
return frappe.db.get_value(
"Bank Account",

View File

@@ -8,38 +8,4 @@ from frappe.tests import IntegrationTestCase
class TestBankAccount(IntegrationTestCase):
def test_validate_iban(self):
valid_ibans = [
"GB82 WEST 1234 5698 7654 32",
"DE91 1000 0000 0123 4567 89",
"FR76 3000 6000 0112 3456 7890 189",
]
invalid_ibans = [
# wrong checksum (3rd place)
"GB72 WEST 1234 5698 7654 32",
"DE81 1000 0000 0123 4567 89",
"FR66 3000 6000 0112 3456 7890 189",
]
bank_account = frappe.get_doc({"doctype": "Bank Account"})
try:
bank_account.validate_iban()
except AttributeError:
msg = "BankAccount.validate_iban() failed for empty IBAN"
self.fail(msg=msg)
for iban in valid_ibans:
bank_account.iban = iban
try:
bank_account.validate_iban()
except ValidationError:
msg = f"BankAccount.validate_iban() failed for valid IBAN {iban}"
self.fail(msg=msg)
for not_iban in invalid_ibans:
bank_account.iban = not_iban
msg = f"BankAccount.validate_iban() accepted invalid IBAN {not_iban}"
with self.assertRaises(ValidationError, msg=msg):
bank_account.validate_iban()
pass

View File

@@ -89,46 +89,64 @@ class BankClearance(Document):
@frappe.whitelist()
def update_clearance_date(self):
clearance_date_updated = False
invalid_document = []
invalid_cheque_date = []
entries_to_update = []
def validate_entry(d):
is_valid = True
if not d.payment_document:
invalid_document.append(str(d.idx))
is_valid = False
if d.clearance_date and d.cheque_date and getdate(d.clearance_date) < getdate(d.cheque_date):
invalid_cheque_date.append(str(d.idx))
is_valid = False
return is_valid
for d in self.get("payment_entries"):
if d.clearance_date:
if not d.payment_document:
frappe.throw(_("Row #{0}: Payment document is required to complete the transaction"))
if d.cheque_date and getdate(d.clearance_date) < getdate(d.cheque_date):
frappe.throw(
_("Row #{0}: For {1} Clearance date {2} cannot be before Cheque Date {3}").format(
d.idx,
get_link_to_form(d.payment_document, d.payment_entry),
d.clearance_date,
d.cheque_date,
)
)
if d.clearance_date or self.include_reconciled_entries:
if validate_entry(d) and (d.clearance_date or self.include_reconciled_entries):
if not d.clearance_date:
d.clearance_date = None
if d.payment_document == "Sales Invoice":
frappe.db.set_value(
"Sales Invoice Payment",
{"parent": d.payment_entry, "account": self.get("account"), "amount": [">", 0]},
"clearance_date",
d.clearance_date,
)
entries_to_update.append(d)
else:
# using db_set to trigger notification
payment_entry = frappe.get_doc(d.payment_document, d.payment_entry)
payment_entry.db_set("clearance_date", d.clearance_date)
if invalid_document or invalid_cheque_date:
msg = _("<p>Please correct the following row(s):</p><ul>")
if invalid_document:
msg += _("<li>Payment document required for row(s): {0}</li>").format(
", ".join(invalid_document)
)
clearance_date_updated = True
if invalid_cheque_date:
msg += _("<li>Clearance date must be after cheque date for row(s): {0}</li>").format(
", ".join(invalid_cheque_date)
)
if clearance_date_updated:
self.get_payment_entries()
msgprint(_("Clearance Date updated"))
else:
msg += "</ul>"
frappe.throw(_(msg))
return
if not entries_to_update:
msgprint(_("Clearance Date not mentioned"))
return
for d in entries_to_update:
if d.payment_document == "Sales Invoice":
frappe.db.set_value(
"Sales Invoice Payment",
{"parent": d.payment_entry, "account": self.get("account"), "amount": [">", 0]},
"clearance_date",
d.clearance_date,
)
else:
# using db_set to trigger notification
payment_entry = frappe.get_lazy_doc(d.payment_document, d.payment_entry)
payment_entry.db_set("clearance_date", d.clearance_date)
self.get_payment_entries()
msgprint(_("Clearance Date updated"))
def get_payment_entries_for_bank_clearance(
@@ -137,8 +155,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 +183,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

@@ -146,6 +146,7 @@
"fieldname": "iban",
"fieldtype": "Data",
"label": "IBAN",
"options": "IBAN",
"read_only": 1
},
{
@@ -214,9 +215,10 @@
"read_only": 1
}
],
"grid_page_length": 50,
"is_submittable": 1,
"links": [],
"modified": "2024-03-27 13:06:37.731207",
"modified": "2025-08-29 11:52:33.550847",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Guarantee",
@@ -250,9 +252,10 @@
}
],
"quick_entry": 1,
"row_format": "Dynamic",
"search_fields": "customer",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "customer"
}
}

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

@@ -252,7 +252,7 @@ frappe.ui.form.on("Bank Statement Import", {
open_url_post(method, {
doctype: "Bank Transaction",
export_records: "5_records",
export_records: "blank_template",
export_fields: {
"Bank Transaction": [
"date",

View File

@@ -76,6 +76,18 @@ class BankStatementImport(DataImport):
self.validate_google_sheets_url()
def start_import(self):
"""
Start a background import job for this Bank Statement Import.
Validates that the preview contains a "Bank Account" column and that the scheduler is active (unless running in test or developer mode). If validation passes and there is not already an enqueued job for this document, enqueue a background worker to perform the import.
Returns:
str | None: The enqueued job_id when a new job was queued, otherwise None.
Raises:
frappe.ValidationError: If the preview is missing a "Bank Account" column.
frappe.ValidationError: If the scheduler is inactive and import is not allowed to run immediately.
"""
preview = frappe.get_doc("Bank Statement Import", self.name).get_preview_from_template(
self.import_file, self.google_sheets_url
)
@@ -111,20 +123,94 @@ class BankStatementImport(DataImport):
return None
def preprocess_mt940_content(content: str) -> str:
"""
Truncate overly long MT940 statement numbers found in `:28C:` tags to the last 5 digits.
This function fixes MT940 files where banks supply statement numbers longer than the MT940-expected maximum (5 digits),
which can break parsers. It only processes lines that start with the `:28C:` tag and:
- leaves content unchanged if no `:28C:` tag is present,
- truncates numeric statement numbers longer than 5 digits to their last 5 digits,
- preserves any `/sequence` suffix and trailing whitespace on the same line.
Parameters:
content (str): Raw MT940 file content.
Returns:
str: The processed content with corrected `:28C:` statement numbers.
"""
# Fast-path: bail if no :28C: tag exists
if ":28C:" not in content:
return content
# Match :28C: at start of line, capture digits and optional /seq, preserve whitespace
pattern = re.compile(r'(?m)^(:28C:)(\d{6,})(/\d+)?(\s*)$')
def replace_statement_number(match):
"""
Replace a matched MT940 :28C: statement number by truncating it to the last five digits if it is longer.
Parameters:
match (re.Match): A regex match with groups:
1: prefix (e.g., ':28C:')
2: numeric statement number
3: optional sequence part (e.g., '/1')
4: optional trailing whitespace
Returns:
str: Reconstructed replacement string preserving prefix, (possibly truncated) statement number, sequence part, and trailing whitespace.
"""
prefix = match.group(1) # ':28C:'
statement_num = match.group(2) # The statement number
sequence_part = match.group(3) or '' # The sequence part like '/1'
trailing_space = match.group(4) or '' # Preserve trailing whitespace
# If statement number is longer than 5 digits, truncate to last 5 digits
if len(statement_num) > 5:
statement_num = statement_num[-5:]
return prefix + statement_num + sequence_part + trailing_space
# Apply the replacement
processed_content = pattern.sub(replace_statement_number, content)
return processed_content
@frappe.whitelist()
def convert_mt940_to_csv(data_import, mt940_file_path):
"""
Convert an MT940 file to a CSV and save it to the Frappe File Manager, returning the saved file URL.
This function:
- Loads the specified MT940 file, verifies it is MT940 format, preprocesses content to fix statement number formatting, and parses transactions.
- Writes parsed transactions to an in-memory CSV with headers: Date, Deposit, Withdrawal, Description, Reference Number, Bank Account, Currency.
- Saves the CSV as a private attachment on the Bank Statement Import document and returns the file URL.
Parameters:
data_import (str): Name (docname) of the Bank Statement Import document to attach the converted CSV to.
mt940_file_path (str): File path or file identifier pointing to the uploaded MT940 file to convert.
Returns:
str: URL of the saved CSV file in the File Manager.
Raises:
frappe.ValidationError: If the file is not MT940, MT940 import is not enabled on the document, parsing fails, or no transactions are found.
"""
doc = frappe.get_doc("Bank Statement Import", data_import)
file_doc, content = get_file(mt940_file_path)
if not is_mt940_format(content):
is_mt940 = is_mt940_format(content)
if not is_mt940:
frappe.throw(_("The uploaded file does not appear to be in valid MT940 format."))
if is_mt940_format(content) and not doc.import_mt940_fromat:
if is_mt940 and not doc.import_mt940_fromat:
frappe.throw(_("MT940 file detected. Please enable 'Import MT940 Format' to proceed."))
try:
transactions = mt940.parse(content)
# Preprocess MT940 content to fix statement number format issues
processed_content = preprocess_mt940_content(content)
transactions = mt940.parse(processed_content)
except Exception as e:
frappe.throw(_("Failed to parse MT940 format. Error: {0}").format(str(e)))
@@ -249,6 +335,20 @@ def start_import(data_import, bank_account, import_file_path, google_sheets_url,
def update_mapping_db(bank, template_options):
"""
Update a Bank document's transaction field mappings to match the provided template options.
This replaces all existing entries in the Bank.bank_transaction_mapping child table with mappings from
the JSON-encoded template_options. The expected template_options JSON contains a "column_to_field_map"
object mapping file column names (keys) to bank transaction field names (values).
Parameters:
bank (str | frappe.model.document.Document): Bank name/docname or a Bank document.
template_options (str): JSON string containing a "column_to_field_map" mapping of file column -> bank field.
Side effects:
Overwrites the Bank.bank_transaction_mapping entries and saves the Bank document.
"""
bank = frappe.get_doc("Bank", bank)
for d in bank.bank_transaction_mapping:
d.delete()
@@ -260,6 +360,17 @@ def update_mapping_db(bank, template_options):
def add_bank_account(data, bank_account):
"""
Ensure every data row contains the given bank account value.
Assumes `data` is a list of rows where data[0] is the header row. If the header row does not contain "Bank Account",
this function appends that header and appends the `bank_account` value to each subsequent row. If the header exists,
it sets the `bank_account` value into the existing "Bank Account" column for every data row. Mutates `data` in place.
Parameters:
data (list[list]): Table-like data with the first row as headers.
bank_account (str): Bank account value to set for each data row.
"""
bank_account_loc = None
if "Bank Account" not in data[0]:
data[0].append("Bank Account")
@@ -276,6 +387,21 @@ def add_bank_account(data, bank_account):
def write_files(import_file, data):
"""
Write processed tabular data back to the original import file path (CSV or Excel).
This function overwrites the file referenced by import_file.file_doc.get_full_path().
- If the file extension is "csv", writes rows using the csv writer (expects `data` as an iterable of row iterables).
- If the extension is "xlsx" or "xls", writes to an Excel workbook using write_xlsx with sheet name "trans".
Parameters:
import_file: object
File wrapper whose `.file_doc.get_full_path()` and `.file_doc.get_extension()` are used to determine the target path and extension.
data: Iterable[Iterable]
Sequence of rows (each row is an iterable of cell values) to be written.
No return value.
"""
full_file_path = import_file.file_doc.get_full_path()
parts = import_file.file_doc.get_extension()
extension = parts[1]
@@ -285,11 +411,26 @@ def write_files(import_file, data):
with open(full_file_path, "w", newline="") as file:
writer = csv.writer(file)
writer.writerows(data)
elif extension == "xlsx" or "xls":
elif extension in ("xlsx", "xls"):
write_xlsx(data, "trans", file_path=full_file_path)
def write_xlsx(data, sheet_name, wb=None, column_widths=None, file_path=None):
"""
Write rows of data to an Excel worksheet and save the workbook.
Creates a sheet named `sheet_name` in the provided openpyxl workbook (or a new write-only workbook if `wb` is None), applies optional column widths, converts HTML in string cells (except for sheets named "Data Import Template" or "Data Export"), strips characters illegal in Excel, and saves the workbook to `file_path`.
Parameters:
data (Iterable[Sequence]): Iterable of rows, where each row is a sequence of cell values.
sheet_name (str): Name of the worksheet to create.
wb (openpyxl.Workbook, optional): Workbook to append the sheet to. If not provided, a new write-only Workbook is created.
column_widths (Sequence[Number], optional): Sequence of column widths; indexes correspond to columns starting at 1.
file_path (str): File path where the workbook will be saved.
Returns:
bool: True on successful save.
"""
# from xlsx utils with changes
column_widths = column_widths or []
if wb is None:

View File

@@ -1,10 +1,220 @@
# Copyright (c) 2020, Frappe Technologies and Contributors
# See license.txt
# import frappe
import unittest
from frappe.tests import IntegrationTestCase
from erpnext.accounts.doctype.bank_statement_import.bank_statement_import import (
preprocess_mt940_content,
is_mt940_format,
)
class TestBankStatementImport(IntegrationTestCase):
pass
class TestBankStatementImport(unittest.TestCase):
"""Unit tests for Bank Statement Import functions"""
def test_preprocess_mt940_content_with_long_statement_number(self):
"""Test that statement numbers longer than 5 digits are truncated to last 5 digits"""
# Test case with 6-digit statement number (167619 -> 67619)
mt940_content = ":28C:167619/1"
expected_content = ":28C:67619/1"
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, expected_content)
def test_preprocess_mt940_content_with_normal_statement_number(self):
"""Test that statement numbers with 5 or fewer digits are unchanged"""
# Test case with 5-digit statement number (should remain unchanged)
mt940_content = ":28C:12345/1"
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, mt940_content) # Should be unchanged
# Test case with 4-digit statement number (should remain unchanged)
mt940_content = ":28C:1234/1"
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, mt940_content) # Should be unchanged
def test_preprocess_mt940_content_without_sequence_number(self):
"""Test statement number truncation without sequence number"""
# Test case with long statement number but no sequence (no /1)
mt940_content = ":28C:987654321"
expected_content = ":28C:54321"
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, expected_content)
def test_preprocess_mt940_content_multiple_occurrences(self):
"""Test multiple statement numbers in the same content"""
mt940_content = """:28C:167619/1
:28C:987654/2"""
expected_content = """:28C:67619/1
:28C:87654/2"""
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, expected_content)
def test_preprocess_mt940_content_edge_cases(self):
"""Test edge cases like empty content and content without :28C: tags"""
# Test empty content
self.assertEqual(preprocess_mt940_content(""), "")
# Test content without :28C: tags
content_without_28c = """:20:STARTUMSE
:25:12345678901234567890
:60F:C031002EUR0,00"""
result = preprocess_mt940_content(content_without_28c)
self.assertEqual(result, content_without_28c) # Should be unchanged
def test_preprocess_mt940_content_with_full_mt940_document(self):
"""Test preprocessing with complete MT940 document"""
mt940_content = """:20:STARTUMSE
:25:12345678901234567890
:28C:167619/1
:60F:C031002EUR0,00
:61:0310021002DR123,45NMSCNONREF//8327000090031789
:86:806?20EREF+NONREF?21MREF+M180031?22CRED+DE98ZZZ09999999999
:62F:C031002EUR-123,45
-"""
expected_content = """:20:STARTUMSE
:25:12345678901234567890
:28C:67619/1
:60F:C031002EUR0,00
:61:0310021002DR123,45NMSCNONREF//8327000090031789
:86:806?20EREF+NONREF?21MREF+M180031?22CRED+DE98ZZZ09999999999
:62F:C031002EUR-123,45
-"""
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, expected_content)
def test_is_mt940_format_detection(self):
"""Test MT940 format detection function"""
# Valid MT940 content with all required tags
valid_mt940 = """:20:STARTUMSE
:25:12345678901234567890
:28C:167619/1
:60F:C031002EUR0,00
:61:0310021002DR123,45NMSCNONREF//8327000090031789"""
self.assertTrue(is_mt940_format(valid_mt940))
# Invalid MT940 content (CSV format)
invalid_mt940 = """Date,Description,Amount
2023-01-01,Test Transaction,100.00
2023-01-02,Another Transaction,-50.00"""
self.assertFalse(is_mt940_format(invalid_mt940))
# Partially valid MT940 (missing some required tags)
partial_mt940 = """:20:STARTUMSE
:25:12345678901234567890
:60F:C031002EUR0,00"""
self.assertFalse(is_mt940_format(partial_mt940))
# Empty content
self.assertFalse(is_mt940_format(""))
def test_preprocess_mt940_content_boundary_conditions(self):
"""
Verify preprocessing handles statement-number length boundaries in `:28C:` tags.
Checks that:
- A 6-digit statement number is truncated to its last 5 digits.
- A 5-digit statement number remains unchanged.
- A very long statement number is reduced to its last 5 digits.
"""
# Test exactly 6 digits (should be truncated)
mt940_content = ":28C:123456/1"
expected_content = ":28C:23456/1"
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, expected_content)
# Test exactly 5 digits (should remain unchanged)
mt940_content = ":28C:12345/1"
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, mt940_content)
# Test very long statement number
mt940_content = ":28C:123456789012345/1"
expected_content = ":28C:12345/1" # Last 5 digits
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, expected_content)
def test_preprocess_mt940_content_real_world_case(self):
"""
Verify preprocessing of a real-world MT940 document: truncate 6-digit `:28C:` statement numbers to their last 5 digits and preserve all other content.
Uses a sanitized, production-failing MT940 sample where `:28C:167619/1` must become `:28C:67619/1`. Asserts the entire document matches the expected transformed output, that the truncated tag is present and the original is absent, and that unrelated fields (e.g., `:20:` reference and UPI details) remain unchanged.
"""
# This is based on actual MT940 content that was causing parsing errors (sanitized)
mt940_content = """{1:F0112345678901X0000000000}{2:I94012345678901XN}{4:
:20:STMTREF167619
:25:1234567890
:28C:167619/1
:60F:C250622USD0,00
:61:2507170717C100000,00NMSCNOREF
:86:BY EXAMPLE INST 123456/03-07-25/TESTBANK/CITY
:61:2507240724C1,00NMSCNEFTINW-1234567890
:86:NEFT TEST123456789 EXAMPLE MERCHANT SERVICES
:61:2507310731D305,62NMSCTBMS-1234567890
:86:Chrg: Debit Card Annual Fee 1234 for 2025
:61:2508030803D1066,00NMSC123456789
:86:PCD/1234/EXAMPLE DOMAIN/01234567890123/23:27
:61:2508060806D2000,00NMSCUPI-123456789
:86:UPI/TEST USER/123456789/PaidViaTestApp
:61:2508140814D5000,00NMSCUPI-123456789
:86:UPI/TEST USER/123456789/PaidViaTestApp
:61:2509190919D900,00NMSCUPI-123456789
:86:UPI/EXAMPLE MERCHANT/123456789/Pay
:61:2509190919D2606,00NMSCUPI-123456789
:86:UPI/JOHN DOE/123456789/PaidViaTestApp
:62F:C250922USD88123,38
-}"""
# Expected result with statement number 167619 truncated to 67619
expected_content = """{1:F0112345678901X0000000000}{2:I94012345678901XN}{4:
:20:STMTREF167619
:25:1234567890
:28C:67619/1
:60F:C250622USD0,00
:61:2507170717C100000,00NMSCNOREF
:86:BY EXAMPLE INST 123456/03-07-25/TESTBANK/CITY
:61:2507240724C1,00NMSCNEFTINW-1234567890
:86:NEFT TEST123456789 EXAMPLE MERCHANT SERVICES
:61:2507310731D305,62NMSCTBMS-1234567890
:86:Chrg: Debit Card Annual Fee 1234 for 2025
:61:2508030803D1066,00NMSC123456789
:86:PCD/1234/EXAMPLE DOMAIN/01234567890123/23:27
:61:2508060806D2000,00NMSCUPI-123456789
:86:UPI/TEST USER/123456789/PaidViaTestApp
:61:2508140814D5000,00NMSCUPI-123456789
:86:UPI/TEST USER/123456789/PaidViaTestApp
:61:2509190919D900,00NMSCUPI-123456789
:86:UPI/EXAMPLE MERCHANT/123456789/Pay
:61:2509190919D2606,00NMSCUPI-123456789
:86:UPI/JOHN DOE/123456789/PaidViaTestApp
:62F:C250922USD88123,38
-}"""
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, expected_content)
# Verify that the problematic statement number was actually changed
self.assertIn(":28C:67619/1", result)
self.assertNotIn(":28C:167619/1", result)
# Verify that other content remains unchanged
self.assertIn(":20:STMTREF167619", result) # Reference should remain unchanged
self.assertIn("UPI/TEST USER/123456789/PaidViaTestApp", result)
def test_preprocess_mt940_content_whitespace_variants(self):
"""Test handling of whitespace and different line endings"""
# Test with trailing spaces
mt940_content = ":28C:167619/1 \n"
expected_content = ":28C:67619/1 \n"
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, expected_content)
# Test with Windows line endings (CRLF)
mt940_content = ":28C:167619/1\r\n"
expected_content = ":28C:67619/1\r\n"
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, expected_content)
# Test with leading spaces (should not match as it's not line start)
mt940_content = " :28C:167619/1\n"
result = preprocess_mt940_content(mt940_content)
self.assertEqual(result, mt940_content) # Should remain unchanged

View File

@@ -223,7 +223,8 @@
{
"fieldname": "bank_party_iban",
"fieldtype": "Data",
"label": "Party IBAN (Bank Statement)"
"label": "Party IBAN (Bank Statement)",
"options": "IBAN"
},
{
"fieldname": "bank_party_account_number",
@@ -238,7 +239,7 @@
"grid_page_length": 50,
"is_submittable": 1,
"links": [],
"modified": "2025-06-18 17:24:57.044666",
"modified": "2025-08-29 11:53:45.908169",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction",

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(IntegrationTestCase):
@classmethod
@@ -22,24 +25,24 @@ class TestAutoMatchParty(IntegrationTestCase):
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(IntegrationTestCase):
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

@@ -145,8 +145,10 @@ def validate_expense_against_budget(args, expense_amount=0):
if not frappe.db.count("Budget", cache=True):
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"
)
@@ -302,7 +304,7 @@ def compare_expense_with_budget(args, budget_amount, action_for, action, budget_
def get_expense_breakup(args, currency, budget_against):
msg = "<hr>Total Expenses booked through - <ul>"
msg = "<hr> {{ _('Total Expenses booked through') }} - <ul>"
common_filters = frappe._dict(
{
@@ -316,7 +318,7 @@ def get_expense_breakup(args, currency, budget_against):
"<li>"
+ frappe.utils.get_link_to_report(
"General Ledger",
label="Actual Expenses",
label=_("Actual Expenses"),
filters=common_filters.copy().update(
{
"from_date": frappe.get_cached_value("Fiscal Year", args.fiscal_year, "year_start_date"),
@@ -334,7 +336,7 @@ def get_expense_breakup(args, currency, budget_against):
"<li>"
+ frappe.utils.get_link_to_report(
"Material Request",
label="Material Requests",
label=_("Material Requests"),
report_type="Report Builder",
doctype="Material Request",
filters=common_filters.copy().update(
@@ -357,7 +359,7 @@ def get_expense_breakup(args, currency, budget_against):
"<li>"
+ frappe.utils.get_link_to_report(
"Purchase Order",
label="Unbilled Orders",
label=_("Unbilled Orders"),
report_type="Report Builder",
doctype="Purchase Order",
filters=common_filters.copy().update(

View File

@@ -113,6 +113,10 @@ class TestBudget(ERPNextTestSuite):
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
frappe.db.set_value("Budget", budget.name, "fiscal_year", fiscal_year)
accumulated_limit = get_accumulated_monthly_budget(
budget.monthly_distribution, nowdate(), budget.fiscal_year, budget.accounts[0].budget_amount
)
mr = frappe.get_doc(
{
"doctype": "Material Request",
@@ -126,7 +130,7 @@ class TestBudget(ERPNextTestSuite):
"uom": "_Test UOM",
"warehouse": "_Test Warehouse - _TC",
"schedule_date": nowdate(),
"rate": 100000,
"rate": accumulated_limit + 1,
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
}

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

@@ -3,6 +3,7 @@
import unittest
import frappe
from frappe.query_builder.functions import Sum
from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, today
@@ -190,6 +191,31 @@ class TestCostCenterAllocation(IntegrationTestCase):
coa2.cancel()
jv.cancel()
@IntegrationTestCase.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
@@ -163,43 +164,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 = resolve and (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()
new_status = "Resolved" if resolve else "Unresolved"
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)
if dunning.status != new_status:
dunning.status = new_status
dunning.save()
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(IntegrationTestCase):
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

@@ -29,14 +29,17 @@
"against_voucher",
"voucher_detail_no",
"transaction_exchange_rate",
"reporting_currency_exchange_rate",
"amounts_section",
"debit_in_account_currency",
"debit",
"debit_in_transaction_currency",
"debit_in_reporting_currency",
"column_break_bm1w",
"credit_in_account_currency",
"credit",
"credit_in_transaction_currency",
"credit_in_reporting_currency",
"dimensions_section",
"cost_center",
"column_break_lmnm",
@@ -353,13 +356,31 @@
{
"fieldname": "column_break_8abq",
"fieldtype": "Column Break"
},
{
"fieldname": "debit_in_reporting_currency",
"fieldtype": "Currency",
"label": "Debit Amount in Reporting Currency",
"options": "Company:company:reporting_currency"
},
{
"fieldname": "credit_in_reporting_currency",
"fieldtype": "Currency",
"label": "Credit Amount in Reporting Currency",
"options": "Company:company:reporting_currency"
},
{
"fieldname": "reporting_currency_exchange_rate",
"fieldtype": "Float",
"label": "Reporting Currency Exchange Rate",
"precision": "9"
}
],
"icon": "fa fa-list",
"idx": 1,
"in_create": 1,
"links": [],
"modified": "2025-03-21 15:29:11.221890",
"modified": "2025-08-22 12:57:17.750252",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",
@@ -390,8 +411,9 @@
}
],
"quick_entry": 1,
"row_format": "Dynamic",
"search_fields": "voucher_no,account,posting_date,against_voucher",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -18,8 +18,9 @@ from erpnext.accounts.party import (
validate_party_frozen_disabled,
validate_party_gle_currency,
)
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
from erpnext.exceptions import InvalidAccountCurrency
from erpnext.accounts.utils import OUTSTANDING_DOCTYPES, get_account_currency, get_fiscal_year
from erpnext.exceptions import InvalidAccountCurrency, ReportingCurrencyExchangeNotFoundError
from erpnext.setup.utils import get_exchange_rate
exclude_from_linked_with = True
@@ -42,9 +43,11 @@ class GLEntry(Document):
cost_center: DF.Link | None
credit: DF.Currency
credit_in_account_currency: DF.Currency
credit_in_reporting_currency: DF.Currency
credit_in_transaction_currency: DF.Currency
debit: DF.Currency
debit_in_account_currency: DF.Currency
debit_in_reporting_currency: DF.Currency
debit_in_transaction_currency: DF.Currency
due_date: DF.Date | None
finance_book: DF.Link | None
@@ -57,6 +60,7 @@ class GLEntry(Document):
posting_date: DF.Date | None
project: DF.Link | None
remarks: DF.Text | None
reporting_currency_exchange_rate: DF.Float
to_rename: DF.Check
transaction_currency: DF.Link | None
transaction_date: DF.Date | None
@@ -88,6 +92,8 @@ class GLEntry(Document):
self.validate_party()
self.validate_currency()
self.set_amount_in_reporting_currency()
def on_update(self):
adv_adj = self.flags.adv_adj
if not self.flags.from_repost and self.voucher_type != "Period Closing Voucher":
@@ -131,18 +137,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 (
@@ -224,26 +232,23 @@ class GLEntry(Document):
def validate_account_details(self, adv_adj):
"""Account must be ledger, active and not freezed"""
ret = frappe.db.sql(
"""select is_group, docstatus, company
from tabAccount where name=%s""",
self.account,
as_dict=1,
)[0]
account = frappe.get_cached_value(
"Account", self.account, fieldname=["is_group", "docstatus", "company"], as_dict=True
)
if ret.is_group == 1:
if account.is_group == 1:
frappe.throw(
_(
"""{0} {1}: Account {2} is a Group Account and group accounts cannot be used in transactions"""
).format(self.voucher_type, self.voucher_no, self.account)
)
if ret.docstatus == 2:
if account.docstatus == 2:
frappe.throw(
_("{0} {1}: Account {2} is inactive").format(self.voucher_type, self.voucher_no, self.account)
)
if ret.company != self.company:
if account.company != self.company:
frappe.throw(
_("{0} {1}: Account {2} does not belong to Company {3}").format(
self.voucher_type, self.voucher_no, self.account, self.company
@@ -295,6 +300,25 @@ class GLEntry(Document):
if self.party_type and self.party:
validate_party_gle_currency(self.party_type, self.party, self.company, self.account_currency)
def set_amount_in_reporting_currency(self):
default_currency, reporting_currency = frappe.get_cached_value(
"Company", self.company, ["default_currency", "reporting_currency"]
)
transaction_date = self.transaction_date or self.posting_date
self.reporting_currency_exchange_rate = get_exchange_rate(
default_currency, reporting_currency, transaction_date
)
if not self.reporting_currency_exchange_rate:
frappe.throw(
title=_("Reporting Currency Exchange Not Found"),
msg=_(
"Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually."
).format(default_currency, reporting_currency, transaction_date),
exc=ReportingCurrencyExchangeNotFoundError,
)
self.debit_in_reporting_currency = flt(self.debit * self.reporting_currency_exchange_rate)
self.credit_in_reporting_currency = flt(self.credit * self.reporting_currency_exchange_rate)
def validate_and_set_fiscal_year(self):
if not self.fiscal_year:
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
@@ -311,7 +335,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]
@@ -385,7 +409,7 @@ def update_outstanding_amt(
)
)
if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
if against_voucher_type in OUTSTANDING_DOCTYPES:
ref_doc = frappe.get_doc(against_voucher_type, against_voucher)
# Didn't use db_set for optimization purpose
@@ -462,4 +486,9 @@ def rename_temporarily_named_docs(doctype):
f"UPDATE `tab{doctype}` SET name = %s, to_rename = 0, modified = %s where name = %s",
(newname, now(), oldname),
)
for hook_type in ("on_gle_rename", "on_sle_rename"):
for hook in frappe.get_hooks(hook_type):
frappe.call(hook, newname=newname, oldname=oldname)
frappe.db.commit()

View File

@@ -196,6 +196,7 @@ frappe.ui.form.on("Journal Entry", {
});
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
erpnext.utils.set_letter_head(frm);
},
voucher_type: function (frm) {

View File

@@ -46,7 +46,6 @@
"reference",
"clearance_date",
"remark",
"paid_loan",
"inter_company_journal_entry_reference",
"column_break98",
"bill_no",
@@ -310,13 +309,6 @@
"oldfieldtype": "Small Text",
"read_only": 1
},
{
"fieldname": "paid_loan",
"fieldtype": "Data",
"hidden": 1,
"label": "Paid Loan",
"print_hide": 1
},
{
"depends_on": "eval:doc.voucher_type== \"Inter Company Journal Entry\"",
"fieldname": "inter_company_journal_entry_reference",
@@ -599,7 +591,7 @@
"table_fieldname": "payment_entries"
}
],
"modified": "2025-06-17 15:18:13.322681",
"modified": "2025-07-06 15:22:58.465131",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",

View File

@@ -24,6 +24,7 @@ from erpnext.accounts.party import get_party_account
from erpnext.accounts.utils import (
cancel_exchange_gain_loss_journal,
get_account_currency,
get_advance_payment_doctypes,
get_balance_on,
get_stock_accounts,
get_stock_and_account_balance,
@@ -71,7 +72,6 @@ class JournalEntry(AccountsController):
mode_of_payment: DF.Link | None
multi_currency: DF.Check
naming_series: DF.Literal["ACC-JV-.YYYY.-"]
paid_loan: DF.Data | None
pay_to_recd_from: DF.Data | None
payment_order: DF.Link | None
periodic_entry_difference_account: DF.Link | None
@@ -151,8 +151,8 @@ class JournalEntry(AccountsController):
if self.docstatus == 0:
self.apply_tax_withholding()
self.title = self.get_title()
if self.is_new() or not self.title:
self.title = self.get_title()
def validate_advance_accounts(self):
journal_accounts = set([x.account for x in self.accounts])
@@ -195,8 +195,6 @@ class JournalEntry(AccountsController):
self.validate_cheque_info()
self.check_credit_limit()
self.make_gl_entries()
self.make_advance_payment_ledger_entries()
self.update_advance_paid()
self.update_asset_value()
self.update_inter_company_jv()
self.update_invoice_discounting()
@@ -298,8 +296,6 @@ class JournalEntry(AccountsController):
"Advance Payment Ledger Entry",
)
self.make_gl_entries(1)
self.make_advance_payment_ledger_entries()
self.update_advance_paid()
self.unlink_advance_entry_reference()
self.unlink_asset_reference()
self.unlink_inter_company_jv()
@@ -309,20 +305,6 @@ class JournalEntry(AccountsController):
def get_title(self):
return self.pay_to_recd_from or self.accounts[0].account
def update_advance_paid(self):
advance_paid = frappe._dict()
advance_payment_doctypes = frappe.get_hooks("advance_payment_receivable_doctypes") + frappe.get_hooks(
"advance_payment_payable_doctypes"
)
for d in self.get("accounts"):
if d.is_advance:
if d.reference_type in advance_payment_doctypes:
advance_paid.setdefault(d.reference_type, []).append(d.reference_name)
for voucher_type, order_list in advance_paid.items():
for voucher_no in list(set(order_list)):
frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
def validate_inter_company_accounts(self):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
doc = frappe.db.get_value(
@@ -662,8 +644,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}"
@@ -672,6 +657,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(
@@ -1197,49 +1184,65 @@ class JournalEntry(AccountsController):
self.transaction_exchange_rate = row.exchange_rate
break
advance_doctypes = get_advance_payment_doctypes()
for d in self.get("accounts"):
if d.debit or d.credit or (self.voucher_type == "Exchange Gain Or Loss"):
r = [d.user_remark, self.remark]
r = [x for x in r if x]
remarks = "\n".join(r)
row = {
"account": d.account,
"party_type": d.party_type,
"due_date": self.due_date,
"party": d.party,
"against": d.against_account,
"debit": flt(d.debit, d.precision("debit")),
"credit": flt(d.credit, d.precision("credit")),
"account_currency": d.account_currency,
"debit_in_account_currency": flt(
d.debit_in_account_currency, d.precision("debit_in_account_currency")
),
"credit_in_account_currency": flt(
d.credit_in_account_currency, d.precision("credit_in_account_currency")
),
"transaction_currency": self.transaction_currency,
"transaction_exchange_rate": self.transaction_exchange_rate,
"debit_in_transaction_currency": flt(
d.debit_in_account_currency, d.precision("debit_in_account_currency")
)
if self.transaction_currency == d.account_currency
else flt(d.debit, d.precision("debit")) / self.transaction_exchange_rate,
"credit_in_transaction_currency": flt(
d.credit_in_account_currency, d.precision("credit_in_account_currency")
)
if self.transaction_currency == d.account_currency
else flt(d.credit, d.precision("credit")) / self.transaction_exchange_rate,
"against_voucher_type": d.reference_type,
"against_voucher": d.reference_name,
"remarks": remarks,
"voucher_detail_no": d.reference_detail_no,
"cost_center": d.cost_center,
"project": d.project,
"finance_book": self.finance_book,
"advance_voucher_type": d.advance_voucher_type,
"advance_voucher_no": d.advance_voucher_no,
}
if d.reference_type in advance_doctypes:
row.update(
{
"against_voucher_type": self.doctype,
"against_voucher": self.name,
"advance_voucher_type": d.reference_type,
"advance_voucher_no": d.reference_name,
}
)
gl_map.append(
self.get_gl_dict(
{
"account": d.account,
"party_type": d.party_type,
"due_date": self.due_date,
"party": d.party,
"against": d.against_account,
"debit": flt(d.debit, d.precision("debit")),
"credit": flt(d.credit, d.precision("credit")),
"account_currency": d.account_currency,
"debit_in_account_currency": flt(
d.debit_in_account_currency, d.precision("debit_in_account_currency")
),
"credit_in_account_currency": flt(
d.credit_in_account_currency, d.precision("credit_in_account_currency")
),
"transaction_currency": self.transaction_currency,
"transaction_exchange_rate": self.transaction_exchange_rate,
"debit_in_transaction_currency": flt(
d.debit_in_account_currency, d.precision("debit_in_account_currency")
)
if self.transaction_currency == d.account_currency
else flt(d.debit, d.precision("debit")) / self.transaction_exchange_rate,
"credit_in_transaction_currency": flt(
d.credit_in_account_currency, d.precision("credit_in_account_currency")
)
if self.transaction_currency == d.account_currency
else flt(d.credit, d.precision("credit")) / self.transaction_exchange_rate,
"against_voucher_type": d.reference_type,
"against_voucher": d.reference_name,
"remarks": remarks,
"voucher_detail_no": d.reference_detail_no,
"cost_center": d.cost_center,
"project": d.project,
"finance_book": self.finance_book,
},
row,
item=d,
)
)
@@ -1796,6 +1799,14 @@ def make_inter_company_journal_entry(name, voucher_type, company):
@frappe.whitelist()
def make_reverse_journal_entry(source_name, target_doc=None):
existing_reverse = frappe.db.exists("Journal Entry", {"reversal_of": source_name, "docstatus": 1})
if existing_reverse:
frappe.throw(
_("A Reverse Journal Entry {0} already exists for this Journal Entry.").format(
get_link_to_form("Journal Entry", existing_reverse)
)
)
from frappe.model.mapper import get_mapped_doc
def post_process(source, target):

View File

@@ -579,6 +579,18 @@ class TestJournalEntry(IntegrationTestCase):
]
self.assertEqual(expected, actual)
def test_pay_to_recd_from(self):
jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, save=False)
jv.pay_to_recd_from = "_Test Receiver"
jv.save()
self.assertEqual(jv.pay_to_recd_from, "_Test Receiver")
jv.pay_to_recd_from = "_Test Receiver 2"
jv.save()
jv.submit()
self.assertEqual(jv.pay_to_recd_from, "_Test Receiver 2")
def make_journal_entry(
account1,

View File

@@ -32,6 +32,8 @@
"reference_name",
"reference_due_date",
"reference_detail_no",
"advance_voucher_type",
"advance_voucher_no",
"col_break3",
"is_advance",
"user_remark",
@@ -262,20 +264,37 @@
"hidden": 1,
"label": "Reference Detail No",
"no_copy": 1
},
{
"fieldname": "advance_voucher_type",
"fieldtype": "Link",
"label": "Advance Voucher Type",
"no_copy": 1,
"options": "DocType",
"read_only": 1
},
{
"fieldname": "advance_voucher_no",
"fieldtype": "Dynamic Link",
"label": "Advance Voucher No",
"no_copy": 1,
"options": "advance_voucher_type",
"read_only": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:09:58.647732",
"modified": "2025-07-25 04:45:28.117715",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",
"naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -17,8 +17,9 @@ class JournalEntryAccount(Document):
account: DF.Link
account_currency: DF.Link | None
account_type: DF.Data | None
advance_voucher_no: DF.DynamicLink | None
advance_voucher_type: DF.Link | None
against_account: DF.Text | None
balance: DF.Currency
bank_account: DF.Link | None
cost_center: DF.Link | None
credit: DF.Currency
@@ -31,7 +32,6 @@ class JournalEntryAccount(Document):
parentfield: DF.Data
parenttype: DF.Data
party: DF.DynamicLink | None
party_balance: DF.Currency
party_type: DF.Link | None
project: DF.Link | None
reference_detail_no: DF.Data | None

View File

@@ -25,6 +25,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"help_section",
"loyalty_program_help"
],
@@ -144,6 +145,12 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
}
],
"links": [],

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
@@ -55,22 +56,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

@@ -14,6 +14,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"section_break_4",
"invoices"
],
@@ -63,6 +64,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

@@ -273,6 +273,7 @@ frappe.ui.form.on("Payment Entry", {
frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm);
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
erpnext.utils.set_letter_head(frm);
},
contact_person: function (frm) {

View File

@@ -46,7 +46,9 @@ from erpnext.accounts.party import (
from erpnext.accounts.utils import (
cancel_exchange_gain_loss_journal,
get_account_currency,
get_advance_payment_doctypes,
get_outstanding_invoices,
get_reconciliation_effect_date,
)
from erpnext.controllers.accounts_controller import (
AccountsController,
@@ -197,12 +199,10 @@ class PaymentEntry(AccountsController):
def on_submit(self):
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.update_payment_requests()
self.make_advance_payment_ledger_entries()
self.update_advance_paid() # advance_paid_status depends on the payment request amount
self.set_status()
def validate_for_repost(self):
@@ -302,13 +302,11 @@ class PaymentEntry(AccountsController):
"Advance Payment Ledger Entry",
)
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.update_payment_requests(cancel=True)
self.make_advance_payment_ledger_entries()
self.update_advance_paid() # advance_paid_status depends on the payment request amount
self.set_status()
def update_payment_requests(self, cancel=False):
@@ -639,7 +637,7 @@ class PaymentEntry(AccountsController):
def validate_mandatory(self):
for field in ("paid_amount", "received_amount", "source_exchange_rate", "target_exchange_rate"):
if not self.get(field):
frappe.throw(_("{0} is mandatory").format(self.meta.get_label(field)))
frappe.throw(_("{0} is mandatory").format(_(self.meta.get_label(field))))
def validate_reference_documents(self):
valid_reference_doctypes = self.get_valid_reference_doctypes()
@@ -1099,10 +1097,7 @@ class PaymentEntry(AccountsController):
def calculate_base_allocated_amount_for_reference(self, d) -> float:
base_allocated_amount = 0
advance_payment_doctypes = frappe.get_hooks("advance_payment_receivable_doctypes") + frappe.get_hooks(
"advance_payment_payable_doctypes"
)
if d.reference_doctype in advance_payment_doctypes:
if d.reference_doctype in get_advance_payment_doctypes():
# When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type.
# This is so there are no Exchange Gain/Loss generated for such doctypes
@@ -1384,10 +1379,7 @@ class PaymentEntry(AccountsController):
if not self.party_account:
return
advance_payment_doctypes = frappe.get_hooks("advance_payment_receivable_doctypes") + frappe.get_hooks(
"advance_payment_payable_doctypes"
)
advance_payment_doctypes = get_advance_payment_doctypes()
if self.payment_type == "Receive":
against_account = self.paid_to
else:
@@ -1443,23 +1435,27 @@ class PaymentEntry(AccountsController):
dr_or_cr + "_in_transaction_currency": d.allocated_amount
if self.transaction_currency == self.party_account_currency
else allocated_amount_in_company_currency / self.transaction_exchange_rate,
"advance_voucher_type": d.advance_voucher_type,
"advance_voucher_no": d.advance_voucher_no,
},
item=self,
)
)
if self.book_advance_payments_in_separate_party_account:
if d.reference_doctype in advance_payment_doctypes:
# Upon reconciliation, whole ledger will be reposted. So, reference to SO/PO is fine
gle.update(
{
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
}
)
else:
# Do not reference Invoices while Advance is in separate party account
gle.update({"against_voucher_type": self.doctype, "against_voucher": self.name})
if d.reference_doctype in advance_payment_doctypes:
# advance reference
gle.update(
{
"against_voucher_type": self.doctype,
"against_voucher": self.name,
"advance_voucher_type": d.reference_doctype,
"advance_voucher_no": d.reference_name,
}
)
elif self.book_advance_payments_in_separate_party_account:
# Do not reference Invoices while Advance is in separate party account
gle.update({"against_voucher_type": self.doctype, "against_voucher": self.name})
else:
gle.update(
{
@@ -1564,29 +1560,14 @@ class PaymentEntry(AccountsController):
"voucher_no": self.name,
"voucher_detail_no": invoice.name,
}
if invoice.reconcile_effect_on:
posting_date = invoice.reconcile_effect_on
else:
# For backwards compatibility
# Supporting reposting on payment entries reconciled before select field introduction
reconciliation_takes_effect_on = frappe.get_cached_value(
"Company", self.company, "reconciliation_takes_effect_on"
posting_date = get_reconciliation_effect_date(
invoice.reference_doctype, invoice.reference_name, self.company, self.posting_date
)
if reconciliation_takes_effect_on == "Advance Payment Date":
posting_date = self.posting_date
elif reconciliation_takes_effect_on == "Oldest Of Invoice Or Advance":
date_field = "posting_date"
if invoice.reference_doctype in ["Sales Order", "Purchase Order"]:
date_field = "transaction_date"
posting_date = frappe.db.get_value(
invoice.reference_doctype, invoice.reference_name, date_field
)
if getdate(posting_date) < getdate(self.posting_date):
posting_date = self.posting_date
elif reconciliation_takes_effect_on == "Reconciliation Date":
posting_date = nowdate()
frappe.db.set_value("Payment Entry Reference", invoice.name, "reconcile_effect_on", posting_date)
dr_or_cr, account = self.get_dr_and_account_for_advances(invoice)
@@ -1604,6 +1585,8 @@ class PaymentEntry(AccountsController):
{
"against_voucher_type": invoice.reference_doctype,
"against_voucher": invoice.reference_name,
"advance_voucher_type": invoice.advance_voucher_type,
"advance_voucher_no": invoice.advance_voucher_no,
"posting_date": posting_date,
}
)
@@ -1628,6 +1611,8 @@ class PaymentEntry(AccountsController):
{
"against_voucher_type": "Payment Entry",
"against_voucher": self.name,
"advance_voucher_type": invoice.advance_voucher_type,
"advance_voucher_no": invoice.advance_voucher_no,
}
)
gle = self.get_gl_dict(
@@ -1776,19 +1761,6 @@ class PaymentEntry(AccountsController):
return flt(gl_dict.get(field, 0) / (conversion_rate or 1))
def update_advance_paid(self):
if self.payment_type not in ("Receive", "Pay") or not self.party:
return
advance_payment_doctypes = frappe.get_hooks("advance_payment_receivable_doctypes") + frappe.get_hooks(
"advance_payment_payable_doctypes"
)
for d in self.get("references"):
if d.allocated_amount and d.reference_doctype in advance_payment_doctypes:
frappe.get_lazy_doc(
d.reference_doctype, d.reference_name, for_update=True
).set_total_advance_paid()
def on_recurring(self, reference_doc, auto_repeat_doc):
self.reference_no = reference_doc.name
self.reference_date = nowdate()

View File

@@ -52,7 +52,7 @@ class TestPaymentEntry(IntegrationTestCase):
self.assertEqual(pe.paid_to_account_type, "Cash")
expected_gle = dict(
(d[0], d) for d in [["Debtors - _TC", 0, 1000, so.name], ["_Test Cash - _TC", 1000.0, 0, None]]
(d[0], d) for d in [["Debtors - _TC", 0, 1000, pe.name], ["_Test Cash - _TC", 1000.0, 0, None]]
)
self.validate_gl_entries(pe.name, expected_gle)
@@ -84,7 +84,7 @@ class TestPaymentEntry(IntegrationTestCase):
expected_gle = dict(
(d[0], d)
for d in [["_Test Receivable USD - _TC", 0, 5500, so.name], [pe.paid_to, 5500.0, 0, None]]
for d in [["_Test Receivable USD - _TC", 0, 5500, pe.name], [pe.paid_to, 5500.0, 0, None]]
)
self.validate_gl_entries(pe.name, expected_gle)

View File

@@ -22,7 +22,9 @@
"exchange_gain_loss",
"account",
"payment_request",
"payment_request_outstanding"
"payment_request_outstanding",
"advance_voucher_type",
"advance_voucher_no"
],
"fields": [
{
@@ -151,20 +153,37 @@
"fieldtype": "Date",
"label": "Reconcile Effect On",
"read_only": 1
},
{
"columns": 2,
"fieldname": "advance_voucher_type",
"fieldtype": "Link",
"label": "Advance Voucher Type",
"options": "DocType",
"read_only": 1
},
{
"columns": 2,
"fieldname": "advance_voucher_no",
"fieldtype": "Dynamic Link",
"label": "Advance Voucher No",
"options": "advance_voucher_type",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-01-13 15:56:18.895082",
"modified": "2025-07-25 04:32:11.040025",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Reference",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -16,6 +16,8 @@ class PaymentEntryReference(Document):
account: DF.Link | None
account_type: DF.Data | None
advance_voucher_no: DF.DynamicLink | None
advance_voucher_type: DF.Link | None
allocated_amount: DF.Float
bill_no: DF.Data | None
due_date: DF.Date | None
@@ -26,7 +28,6 @@ class PaymentEntryReference(Document):
parentfield: DF.Data
parenttype: DF.Data
payment_request: DF.Link | None
payment_request_outstanding: DF.Float
payment_term: DF.Link | None
payment_term_outstanding: DF.Float
payment_type: DF.Data | None

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

@@ -7,6 +7,7 @@
"field_order": [
"payment_gateway",
"payment_channel",
"company",
"is_default",
"column_break_4",
"payment_account",
@@ -71,11 +72,21 @@
"fieldtype": "Select",
"label": "Payment Channel",
"options": "\nEmail\nPhone\nOther"
},
{
"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": "2024-03-29 18:53:09.836254",
"modified": "2025-07-14 16:49:55.210352",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Gateway Account",
@@ -94,6 +105,7 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []

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

@@ -197,4 +197,4 @@
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -16,7 +16,7 @@ from erpnext.accounts.doctype.gl_entry.gl_entry import (
validate_balance_type,
validate_frozen_account,
)
from erpnext.accounts.utils import update_voucher_outstanding
from erpnext.accounts.utils import OUTSTANDING_DOCTYPES, update_voucher_outstanding
from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
@@ -51,38 +51,36 @@ class PaymentLedgerEntry(Document):
# end: auto-generated types
def validate_account(self):
valid_account = frappe.db.get_list(
"Account",
"name",
filters={"name": self.account, "account_type": self.account_type, "company": self.company},
ignore_permissions=True,
account = frappe.get_cached_value(
"Account", self.account, fieldname=["account_type", "company"], as_dict=True
)
if not valid_account:
if account.company != self.company:
frappe.throw(_("{0} account is not of company {1}").format(self.account, self.company))
if account.account_type != self.account_type:
frappe.throw(_("{0} account is not of type {1}").format(self.account, self.account_type))
def validate_account_details(self):
"""Account must be ledger, active and not freezed"""
ret = frappe.db.sql(
"""select is_group, docstatus, company
from tabAccount where name=%s""",
self.account,
as_dict=1,
)[0]
account = frappe.get_cached_value(
"Account", self.account, fieldname=["is_group", "docstatus", "company"], as_dict=True
)
if ret.is_group == 1:
if account.is_group == 1:
frappe.throw(
_(
"""{0} {1}: Account {2} is a Group Account and group accounts cannot be used in transactions"""
).format(self.voucher_type, self.voucher_no, self.account)
)
if ret.docstatus == 2:
if account.docstatus == 2:
frappe.throw(
_("{0} {1}: Account {2} is inactive").format(self.voucher_type, self.voucher_no, self.account)
)
if ret.company != self.company:
if account.company != self.company:
frappe.throw(
_("{0} {1}: Account {2} does not belong to Company {3}").format(
self.voucher_type, self.voucher_no, self.account, self.company
@@ -170,7 +168,7 @@ class PaymentLedgerEntry(Document):
# update outstanding amount
if (
self.against_voucher_type in ["Journal Entry", "Sales Invoice", "Purchase Invoice", "Fees"]
self.against_voucher_type in OUTSTANDING_DOCTYPES
and self.flags.update_outstanding == "Yes"
and not frappe.flags.is_reverse_depr_entry
):

View File

@@ -28,6 +28,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"sec_break1",
"invoice_name",
"invoices",
@@ -194,6 +195,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"),
}
)
@@ -589,7 +603,7 @@ class PaymentReconciliation(Document):
def check_mandatory_to_fetch(self):
for fieldname in ["company", "party_type", "party", "receivable_payable_account"]:
if not self.get(fieldname):
frappe.throw(_("Please select {0} first").format(self.meta.get_label(fieldname)))
frappe.throw(_("Please select {0} first").format(_(self.meta.get_label(fieldname))))
def validate_entries(self):
if not self.get("invoices"):
@@ -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": [
@@ -826,7 +840,7 @@ def reconcile_dr_cr_note(dr_cr_notes, company, active_dimensions=None):
create_gain_loss_journal(
company,
today(),
inv.difference_posting_date,
inv.party_type,
inv.party,
inv.account,

View File

@@ -1714,6 +1714,67 @@ class TestPaymentReconciliation(IntegrationTestCase):
)
self.assertEqual(len(pl_entries), 3)
def test_advance_payment_reconciliation_date_for_older_date(self):
old_settings = frappe.db.get_value(
"Company",
self.company,
[
"reconciliation_takes_effect_on",
"default_advance_paid_account",
"book_advance_payments_in_separate_party_account",
],
as_dict=True,
)
frappe.db.set_value(
"Company",
self.company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_paid_account": self.advance_payable_account,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
},
)
self.supplier = "_Test Supplier"
pi1 = self.create_purchase_invoice(qty=10, rate=100)
po = self.create_purchase_order(qty=10, rate=100)
pay = get_payment_entry(po.doctype, po.name)
pay.paid_amount = 1000
pay.save().submit()
pr = frappe.new_doc("Payment Reconciliation")
pr.company = self.company
pr.party_type = "Supplier"
pr.party = self.supplier
pr.receivable_payable_account = get_party_account(pr.party_type, pr.party, pr.company)
pr.default_advance_account = self.advance_payable_account
pr.get_unreconciled_entries()
invoices = [x.as_dict() for x in pr.invoices]
payments = [x.as_dict() for x in pr.payments]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.allocation[0].allocated_amount = 100
pr.reconcile()
pay.reload()
self.assertEqual(getdate(pay.references[0].reconcile_effect_on), getdate(pi1.posting_date))
# test setting of date if not available
frappe.db.set_value("Payment Entry Reference", pay.references[1].name, "reconcile_effect_on", None)
pay.reload()
pay.cancel()
pay.reload()
pi1.reload()
po.reload()
self.assertEqual(getdate(pay.references[0].reconcile_effect_on), getdate(pi1.posting_date))
pi1.cancel()
po.cancel()
frappe.db.set_value("Company", self.company, old_settings)
def test_advance_payment_reconciliation_against_journal_for_customer(self):
frappe.db.set_value(
"Company",
@@ -2147,6 +2208,138 @@ class TestPaymentReconciliation(IntegrationTestCase):
self.assertEqual(len(pr.get("payments")), 0)
self.assertEqual(pr.get("invoices")[0].get("outstanding_amount"), 200)
def test_partial_advance_payment_with_closed_fiscal_year(self):
"""
Test Advance Payment partial reconciliation before period closing and partial after period closing
"""
default_settings = frappe.db.get_value(
"Company",
self.company,
[
"book_advance_payments_in_separate_party_account",
"default_advance_paid_account",
"reconciliation_takes_effect_on",
],
as_dict=True,
)
first_fy_start_date = frappe.db.get_value(
"Fiscal Year", {"disabled": 0}, [{"MIN": "year_start_date"}]
)
prev_fy_start_date = add_years(first_fy_start_date, -1)
prev_fy_end_date = add_days(first_fy_start_date, -1)
create_fiscal_year(
company=self.company, year_start_date=prev_fy_start_date, year_end_date=prev_fy_end_date
)
frappe.db.set_value(
"Company",
self.company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_paid_account": self.advance_payable_account,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
},
)
self.supplier = "_Test Supplier"
# Create advance payment of 1000 (previous FY)
pe = self.create_payment_entry(amount=1000, posting_date=prev_fy_start_date)
pe.party_type = "Supplier"
pe.party = self.supplier
pe.payment_type = "Pay"
pe.paid_from = self.cash
pe.paid_to = self.advance_payable_account
pe.save().submit()
# Create purchase invoice of 600 (previous FY)
pi1 = self.create_purchase_invoice(qty=1, rate=600, do_not_submit=True)
pi1.posting_date = prev_fy_start_date
pi1.set_posting_time = 1
pi1.supplier = self.supplier
pi1.credit_to = self.creditors
pi1.save().submit()
# Reconcile advance payment
pr = self.create_payment_reconciliation(party_is_customer=False)
pr.party = self.supplier
pr.receivable_payable_account = self.creditors
pr.default_advance_account = self.advance_payable_account
pr.from_invoice_date = pr.to_invoice_date = pi1.posting_date
pr.from_payment_date = pr.to_payment_date = pe.posting_date
pr.get_unreconciled_entries()
invoices = [x.as_dict() for x in pr.invoices if x.invoice_number == pi1.name]
payments = [x.as_dict() for x in pr.payments if x.reference_name == pe.name]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.reconcile()
# Verify partial reconciliation
pe.reload()
pi1.reload()
self.assertEqual(len(pe.references), 1)
self.assertEqual(pe.references[0].allocated_amount, 600)
self.assertEqual(flt(pe.unallocated_amount), 400)
self.assertEqual(pi1.outstanding_amount, 0)
self.assertEqual(pi1.status, "Paid")
# Close accounting period for March (previous FY)
pcv = make_period_closing_voucher(
company=self.company, cost_center=self.cost_center, posting_date=prev_fy_end_date
)
pcv.reload()
self.assertEqual(pcv.gle_processing_status, "Completed")
# Change reconciliation setting to "Reconciliation Date"
frappe.db.set_value(
"Company",
self.company,
"reconciliation_takes_effect_on",
"Reconciliation Date",
)
# Create new purchase invoice for 400 in new fiscal year
pi2 = self.create_purchase_invoice(qty=1, rate=400, do_not_submit=True)
pi2.posting_date = today()
pi2.set_posting_time = 1
pi2.supplier = self.supplier
pi2.currency = "INR"
pi2.credit_to = self.creditors
pi2.save()
pi2.submit()
# Allocate 600 from advance payment to purchase invoice
pr = self.create_payment_reconciliation(party_is_customer=False)
pr.party = self.supplier
pr.receivable_payable_account = self.creditors
pr.default_advance_account = self.advance_payable_account
pr.from_invoice_date = pr.to_invoice_date = pi2.posting_date
pr.from_payment_date = pr.to_payment_date = pe.posting_date
pr.get_unreconciled_entries()
invoices = [x.as_dict() for x in pr.invoices if x.invoice_number == pi2.name]
payments = [x.as_dict() for x in pr.payments if x.reference_name == pe.name]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.reconcile()
pe.reload()
pi2.reload()
# Assert advance payment is fully allocated
self.assertEqual(len(pe.references), 2)
self.assertEqual(flt(pe.unallocated_amount), 0)
# Assert new invoice is fully paid
self.assertEqual(pi2.outstanding_amount, 0)
self.assertEqual(pi2.status, "Paid")
# Verify reconciliation dates are correct based on company setting
self.assertEqual(getdate(pe.references[0].reconcile_effect_on), getdate(pi1.posting_date))
self.assertEqual(getdate(pe.references[1].reconcile_effect_on), getdate(pi2.posting_date))
frappe.db.set_value("Company", self.company, default_settings)
def make_customer(customer_name, currency=None):
if not frappe.db.exists("Customer", customer_name):

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,19 +169,25 @@
{
"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": "2024-03-27 13:10:10.704417",
"modified": "2025-08-20 19:12:50.406769",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation Allocation",
"owner": "Administrator",
"permissions": [],
"row_format": "Dynamic",
"sort_field": "creation",
"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

@@ -228,7 +228,8 @@
"fetch_from": "bank_account.iban",
"fieldname": "iban",
"fieldtype": "Read Only",
"label": "IBAN"
"label": "IBAN",
"options": "IBAN"
},
{
"fetch_from": "bank_account.branch_code",
@@ -458,11 +459,12 @@
"label": "Phone Number"
}
],
"grid_page_length": 50,
"in_create": 1,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2025-01-04 05:39:32.448857",
"modified": "2025-08-29 11:52:48.555415",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",
@@ -497,8 +499,9 @@
"write": 1
}
],
"row_format": "Dynamic",
"show_preview_popup": 1,
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -16,7 +16,7 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import (
)
from erpnext.accounts.doctype.subscription_plan.subscription_plan import get_plan_rate
from erpnext.accounts.party import get_party_account, get_party_bank_account
from erpnext.accounts.utils import get_account_currency, get_currency_precision
from erpnext.accounts.utils import get_account_currency, get_advance_payment_doctypes, get_currency_precision
from erpnext.utilities import payment_app_import_guard
ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST = [
@@ -464,10 +464,7 @@ class PaymentRequest(Document):
return create_stripe_subscription(gateway_controller, data)
def update_reference_advance_payment_status(self):
advance_payment_doctypes = frappe.get_hooks("advance_payment_receivable_doctypes") + frappe.get_hooks(
"advance_payment_payable_doctypes"
)
if self.reference_doctype in advance_payment_doctypes:
if self.reference_doctype in get_advance_payment_doctypes():
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
ref_doc.set_advance_payment_status()
@@ -537,7 +534,8 @@ def make_payment_request(**args):
frappe.throw(_("Payment Requests cannot be created against: {0}").format(frappe.bold(args.dt)))
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"))
@@ -784,7 +782,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})
return get_payment_gateway_account(gateway_account)
@@ -826,8 +824,7 @@ def update_payment_requests_as_per_pe_references(references=None, cancel=False):
if not references:
return
precision = references[0].precision("allocated_amount")
precision = frappe.get_precision("Payment Entry Reference", "allocated_amount")
referenced_payment_requests = frappe.get_all(
"Payment Request",
filters={"name": ["in", {row.payment_request for row in references if row.payment_request}]},

View File

@@ -34,12 +34,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",
},
{
"doctype": "Payment Gateway Account",
@@ -47,6 +49,7 @@ payment_method = [
"payment_account": "_Test Bank USD - _TC",
"payment_channel": "Other",
"currency": "USD",
"company": "_Test Company",
},
{
"doctype": "Payment Gateway Account",
@@ -54,6 +57,7 @@ payment_method = [
"payment_account": "_Test Bank USD - _TC",
"payment_channel": "Phone",
"currency": "USD",
"company": "_Test Company",
},
]
@@ -67,7 +71,11 @@ class TestPaymentRequest(IntegrationTestCase):
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)
@@ -103,7 +111,7 @@ class TestPaymentRequest(IntegrationTestCase):
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")
@@ -117,7 +125,7 @@ class TestPaymentRequest(IntegrationTestCase):
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")
@@ -130,7 +138,7 @@ class TestPaymentRequest(IntegrationTestCase):
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway Other - USD",
payment_gateway_account="_Test Gateway Other - USD - _TC",
submit_doc=True,
return_doc=True,
)
@@ -145,7 +153,7 @@ class TestPaymentRequest(IntegrationTestCase):
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway - USD", # email channel
payment_gateway_account="_Test Gateway - USD - _TC", # email channel
submit_doc=False,
return_doc=True,
)
@@ -163,7 +171,7 @@ class TestPaymentRequest(IntegrationTestCase):
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway Phone - USD",
payment_gateway_account="_Test Gateway Phone - USD - _TC",
submit_doc=True,
return_doc=True,
)
@@ -180,7 +188,7 @@ class TestPaymentRequest(IntegrationTestCase):
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway - USD", # email channel
payment_gateway_account="_Test Gateway - USD - _TC", # email channel
submit_doc=True,
return_doc=True,
)
@@ -201,7 +209,7 @@ class TestPaymentRequest(IntegrationTestCase):
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway - USD", # email channel
payment_gateway_account="_Test Gateway - USD - _TC", # email channel
make_sales_invoice=True,
mute_email=True,
submit_doc=True,
@@ -232,7 +240,7 @@ class TestPaymentRequest(IntegrationTestCase):
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,
)
@@ -257,7 +265,7 @@ class TestPaymentRequest(IntegrationTestCase):
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,
)
@@ -276,7 +284,7 @@ class TestPaymentRequest(IntegrationTestCase):
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,
)
@@ -300,7 +308,7 @@ class TestPaymentRequest(IntegrationTestCase):
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,
)
@@ -322,7 +330,7 @@ class TestPaymentRequest(IntegrationTestCase):
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,
)
@@ -366,7 +374,7 @@ class TestPaymentRequest(IntegrationTestCase):
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,
)
@@ -471,7 +479,7 @@ class TestPaymentRequest(IntegrationTestCase):
self.assertEqual(pe.paid_amount, 800) # paid amount set from pr's outstanding amount
self.assertEqual(pe.references[0].allocated_amount, 800)
self.assertEqual(pe.references[0].outstanding_amount, 800) # for Orders it is not zero
self.assertEqual(pe.references[0].outstanding_amount, 0) # Also for orders it will zero
self.assertEqual(pe.references[0].payment_request, pr.name)
so.load_from_db()
@@ -813,3 +821,33 @@ class TestPaymentRequest(IntegrationTestCase):
pi.load_from_db()
pr = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1)
self.assertEqual(pr.grand_total, pi.outstanding_amount)
def test_payment_request_on_unreconcile(self):
pi = make_purchase_invoice(currency="INR", qty=1, rate=500)
pi.submit()
pr = make_payment_request(
dt=pi.doctype,
dn=pi.name,
mute_email=1,
submit_doc=True,
return_doc=True,
)
self.assertEqual(pr.grand_total, pi.outstanding_amount)
pe = pr.create_payment_entry()
unreconcile = frappe.get_doc(
{
"doctype": "Unreconcile Payment",
"company": pe.company,
"voucher_type": pe.doctype,
"voucher_no": pe.name,
}
)
unreconcile.add_references()
unreconcile.submit()
pi.load_from_db()
pr.load_from_db()
self.assertEqual(pr.grand_total, pi.outstanding_amount)

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()
@@ -210,8 +212,10 @@ class PeriodClosingVoucher(AccountsController):
return gl_entry
def get_gle_for_closing_account(self, dimension_balance, dimensions):
balance_in_account_currency = flt(dimension_balance.balance_in_account_currency)
balance_in_company_currency = flt(dimension_balance.balance_in_company_currency)
debit = balance_in_company_currency if balance_in_company_currency > 0 else 0
credit = abs(balance_in_company_currency) if balance_in_company_currency < 0 else 0
gl_entry = frappe._dict(
{
"company": self.company,
@@ -220,14 +224,10 @@ class PeriodClosingVoucher(AccountsController):
"account_currency": frappe.db.get_value(
"Account", self.closing_account_head, "account_currency"
),
"debit_in_account_currency": balance_in_account_currency
if balance_in_account_currency > 0
else 0,
"debit": balance_in_company_currency if balance_in_company_currency > 0 else 0,
"credit_in_account_currency": abs(balance_in_account_currency)
if balance_in_account_currency < 0
else 0,
"credit": abs(balance_in_company_currency) if balance_in_company_currency < 0 else 0,
"debit_in_account_currency": debit,
"debit": debit,
"credit_in_account_currency": credit,
"credit": credit,
"is_period_closing_voucher_entry": 1,
"voucher_type": "Period Closing Voucher",
"voucher_no": self.name,

View File

@@ -74,6 +74,7 @@
"label": "User Details"
},
{
"fetch_from": "pos_opening_entry.company",
"fetch_if_empty": 1,
"fieldname": "company",
"fieldtype": "Link",
@@ -103,6 +104,7 @@
"fieldtype": "Link",
"label": "Cashier",
"options": "User",
"read_only": 1,
"reqd": 1
},
{
@@ -259,7 +261,7 @@
"link_fieldname": "pos_closing_entry"
}
],
"modified": "2025-06-06 12:00:31.955176",
"modified": "2025-06-14 02:38:14.962291",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Closing Entry",

View File

@@ -209,13 +209,16 @@ class POSClosingEntry(StatusUpdater):
def on_submit(self):
consolidate_pos_invoices(closing_entry=self)
frappe.publish_realtime(
f"poe_{self.pos_opening_entry}_closed",
self,
f"poe_{self.pos_opening_entry}",
message={"operation": "Closed", "doc": self},
docname=f"POS Opening Entry/{self.pos_opening_entry}",
)
self.update_sales_invoices_closing_entry()
def before_cancel(self):
self.check_pce_is_cancellable()
def on_cancel(self):
unconsolidate_pos_invoices(closing_entry=self)
@@ -237,6 +240,15 @@ class POSClosingEntry(StatusUpdater):
"Sales Invoice", d.sales_invoice, "pos_closing_entry", self.name if not cancel else None
)
def check_pce_is_cancellable(self):
if frappe.db.exists("POS Opening Entry", {"pos_profile": self.pos_profile, "status": "Open"}):
frappe.throw(
title=_("Cannot cancel POS Closing Entry"),
msg=_(
"POS Profile - {0} is currently open. Please close the POS or cancel the existing POS Opening Entry before cancelling this POS Closing Entry."
).format(frappe.bold(self.pos_profile)),
)
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
@@ -267,7 +279,7 @@ def get_invoices(start, end, pos_profile, user):
def get_payments(invoices):
if not len(invoices):
return
return []
invoices_name = [d.name for d in invoices]
@@ -301,7 +313,7 @@ def get_payments(invoices):
def get_taxes(invoices):
if not len(invoices):
return
return []
invoices_name = [d.name for d in invoices]

View File

@@ -14,6 +14,7 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
}
company() {
erpnext.utils.set_letter_head(this.frm);
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
this.frm.set_value("set_warehouse", "");
this.frm.set_value("taxes_and_charges", "");
@@ -54,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, "set_grand_total_to_default_mop")
.then((r) => {
if (!r.exc) {
this.frm.set_default_payment = r.message.set_grand_total_to_default_mop;
}
});
}
}
onload_post_render(frm) {
@@ -66,6 +77,13 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
if (doc.docstatus == 1 && !doc.is_return) {
this.frm.add_custom_button(__("Return"), this.make_sales_return.bind(this), __("Create"));
if (["Partly Paid", "Overdue", "Unpaid"].includes(doc.status)) {
this.frm.add_custom_button(
__("Payment"),
this.collect_outstanding_payment.bind(this),
__("Create")
);
}
this.frm.page.set_inner_btn_group_as_primary(__("Create"));
}
@@ -112,6 +130,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.set_default_payment = r.message.set_default_payment;
}
this.frm.script_manager.trigger("update_stock");
this.calculate_taxes_and_totals();
@@ -210,6 +229,138 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
frm: this.frm,
});
}
async collect_outstanding_payment() {
const total_amount = flt(this.frm.doc.rounded_total) | flt(this.frm.doc.grand_total);
const paid_amount = flt(this.frm.doc.paid_amount);
const outstanding_amount = flt(this.frm.doc.outstanding_amount);
const me = this;
const table_fields = [
{
fieldname: "mode_of_payment",
fieldtype: "Link",
in_list_view: 1,
label: __("Mode of Payment"),
options: "Mode of Payment",
reqd: 1,
},
{
fieldname: "amount",
fieldtype: "Currency",
in_list_view: 1,
label: __("Amount"),
options: this.frm.doc.currency,
reqd: 1,
onchange: function () {
dialog.fields_dict.payments.df.data.some((d) => {
if (d.idx == this.doc.idx) {
d.amount = this.value === null ? 0 : this.value;
dialog.fields_dict.payments.grid.refresh();
return true;
}
});
let amount = 0;
for (let d of dialog.fields_dict.payments.df.data) {
amount += d.amount;
}
let change_amount = total_amount - (paid_amount + amount);
dialog.fields_dict.outstanding_amount.set_value(
outstanding_amount - amount < 0 ? 0 : outstanding_amount - amount
);
dialog.fields_dict.paid_amount.set_value(paid_amount + amount);
dialog.fields_dict.change_amount.set_value(change_amount < 0 ? change_amount * -1 : 0);
},
},
];
const payment_method_data = await this.fetch_pos_payment_methods();
const dialog = new frappe.ui.Dialog({
title: __("Collect Outstanding Amount"),
fields: [
{
fieldname: "payments",
fieldtype: "Table",
label: __("Payments"),
cannot_add_rows: false,
in_place_edit: true,
reqd: 1,
data: payment_method_data,
fields: table_fields,
},
{
fieldname: "section_break_1",
fieldtype: "Section Break",
},
{
fieldname: "outstanding_amount",
fieldtype: "Currency",
label: __("Outstanding Amount"),
read_only: 1,
default: outstanding_amount,
},
{
fieldname: "column_break_1",
fieldtype: "Column Break",
},
{
fieldname: "paid_amount",
fieldtype: "Currency",
label: __("Paid Amount"),
read_only: 1,
default: paid_amount,
},
{
fieldname: "change_amount",
fieldtype: "Currency",
label: __("Change Amount"),
read_only: 1,
default: 0,
},
],
primary_action_label: __("Submit"),
primary_action(values) {
dialog.hide();
me.frm.call({
doc: me.frm.doc,
method: "update_payments",
args: {
payments: values.payments.filter((d) => d.amount != 0),
},
freeze: true,
callback: function (r) {
if (!r.exc) {
frappe.show_alert({
message: __("Payments updated."),
indicator: "green",
});
me.frm.reload_doc();
} else {
frappe.show_alert({
message: __("Payments could not be updated."),
indicator: "red",
});
}
},
});
},
});
dialog.show();
}
async fetch_pos_payment_methods() {
const pos_profile = this.frm.doc.pos_profile;
if (!pos_profile) return;
const pos_profile_doc = await frappe.db.get_doc("POS Profile", pos_profile);
const data = [];
pos_profile_doc.payments.forEach((pay) => {
const { mode_of_payment } = pay;
data.push({ mode_of_payment, amount: 0 });
});
return data;
}
};
extend_cscript(cur_frm.cscript, new erpnext.selling.POSInvoiceController({ frm: cur_frm }));

View File

@@ -30,24 +30,6 @@
"project",
"dimension_col_break",
"cost_center",
"customer_po_details",
"po_no",
"column_break_23",
"po_date",
"address_and_contact",
"customer_address",
"address_display",
"contact_person",
"contact_display",
"contact_mobile",
"contact_email",
"territory",
"col_break4",
"shipping_address_name",
"shipping_address",
"company_address",
"company_address_display",
"company_contact_person",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -61,6 +43,7 @@
"items_section",
"update_stock",
"scan_barcode",
"last_scanned_warehouse",
"items",
"pricing_rule_details",
"pricing_rules",
@@ -91,14 +74,6 @@
"base_total_taxes_and_charges",
"column_break_47",
"total_taxes_and_charges",
"loyalty_points_redemption",
"loyalty_points",
"loyalty_amount",
"redeem_loyalty_points",
"column_break_77",
"loyalty_program",
"loyalty_redemption_account",
"loyalty_redemption_cost_center",
"section_break_49",
"coupon_code",
"apply_discount_on",
@@ -118,13 +93,7 @@
"in_words",
"total_advance",
"outstanding_amount",
"advances_section",
"allocate_advances_automatically",
"get_advances",
"advances",
"payment_schedule_section",
"payment_terms_template",
"payment_schedule",
"payments_tab",
"payments_section",
"cash_bank_account",
"payments",
@@ -137,6 +106,10 @@
"column_break_90",
"change_amount",
"account_for_change_amount",
"advances_section",
"allocate_advances_automatically",
"get_advances",
"advances",
"column_break4",
"write_off_amount",
"base_write_off_amount",
@@ -144,9 +117,41 @@
"column_break_74",
"write_off_account",
"write_off_cost_center",
"loyalty_points_redemption",
"loyalty_points",
"loyalty_amount",
"redeem_loyalty_points",
"column_break_77",
"loyalty_program",
"loyalty_redemption_account",
"loyalty_redemption_cost_center",
"contact_and_address_tab",
"address_and_contact",
"customer_address",
"address_display",
"contact_person",
"contact_display",
"contact_mobile",
"contact_email",
"territory",
"col_break4",
"shipping_address_name",
"shipping_address",
"company_address",
"company_address_display",
"company_contact_person",
"terms_tab",
"payment_schedule_section",
"payment_terms_template",
"payment_schedule",
"terms_section_break",
"tc_name",
"terms",
"more_info_tab",
"customer_po_details",
"po_no",
"column_break_23",
"po_date",
"edit_printing_settings",
"letter_head",
"group_same_items",
@@ -292,6 +297,7 @@
"search_index": 1
},
{
"default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -398,7 +404,6 @@
"label": "Customer's Purchase Order Date"
},
{
"collapsible": 1,
"fieldname": "address_and_contact",
"fieldtype": "Section Break",
"label": "Address and Contact"
@@ -1050,7 +1055,6 @@
"print_hide": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "eval:(!doc.is_pos && !doc.is_return)",
"fieldname": "payment_schedule_section",
"fieldtype": "Section Break",
@@ -1130,8 +1134,10 @@
"read_only": 1
},
{
"collapsible": 1,
"fieldname": "section_break_88",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"label": "Changes"
},
{
"depends_on": "is_pos",
@@ -1218,7 +1224,6 @@
"print_hide": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "terms",
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
@@ -1330,7 +1335,7 @@
"in_standard_filter": 1,
"label": "Status",
"no_copy": 1,
"options": "\nDraft\nReturn\nCredit Note Issued\nConsolidated\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nCancelled",
"options": "\nDraft\nReturn\nCredit Note Issued\nConsolidated\nSubmitted\nPaid\nPartly Paid\nUnpaid\nPartly Paid and Discounted\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nCancelled",
"print_hide": 1,
"read_only": 1
},
@@ -1416,6 +1421,8 @@
"width": "50%"
},
{
"fetch_from": "sales_partner.commission_rate",
"fetch_if_empty": 1,
"fieldname": "commission_rate",
"fieldtype": "Float",
"label": "Commission Rate (%)",
@@ -1568,12 +1575,39 @@
"label": "Company Contact Person",
"options": "Contact",
"print_hide": 1
},
{
"fieldname": "payments_tab",
"fieldtype": "Tab Break",
"label": "Payments"
},
{
"fieldname": "contact_and_address_tab",
"fieldtype": "Tab Break",
"label": "Address & Contact"
},
{
"fieldname": "terms_tab",
"fieldtype": "Tab Break",
"label": "Terms"
},
{
"fieldname": "more_info_tab",
"fieldtype": "Tab Break",
"label": "More Info"
},
{
"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-01-06 15:03:19.957277",
"modified": "2025-08-04 22:22:31.471752",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
@@ -1618,6 +1652,7 @@
"role": "All"
}
],
"row_format": "Dynamic",
"search_fields": "posting_date, due_date, customer, base_grand_total, outstanding_amount",
"show_name_in_global_search": 1,
"sort_field": "creation",

View File

@@ -149,7 +149,9 @@ class POSInvoice(SalesInvoice):
"Consolidated",
"Submitted",
"Paid",
"Partly Paid",
"Unpaid",
"Partly Paid and Discounted",
"Unpaid and Discounted",
"Overdue and Discounted",
"Overdue",
@@ -215,11 +217,15 @@ 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
validate_coupon_code(self.coupon_code)
def before_submit(self):
self.set_outstanding_amount()
def on_submit(self):
# create the loyalty point ledger entry if the customer is enrolled in any loyalty program
if not self.is_return and self.loyalty_program:
@@ -373,18 +379,6 @@ class POSInvoice(SalesInvoice):
_("Payment related to {0} is not completed").format(pay.mode_of_payment)
)
def validate_pos_opening_entry(self):
opening_entries = frappe.get_list(
"POS Opening Entry", filters={"pos_profile": self.pos_profile, "status": "Open", "docstatus": 1}
)
if len(opening_entries) == 0:
frappe.throw(
title=_("POS Opening Entry Missing"),
msg=_("No open POS Opening Entry found for POS Profile {0}.").format(
frappe.bold(self.pos_profile)
),
)
def validate_stock_availablility(self):
if self.is_return:
return
@@ -417,9 +411,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"),
)
@@ -537,6 +531,10 @@ class POSInvoice(SalesInvoice):
)
)
def set_outstanding_amount(self):
total = flt(self.rounded_total) or flt(self.grand_total)
self.outstanding_amount = total - flt(self.paid_amount) if total > flt(self.paid_amount) else 0
def validate_loyalty_transaction(self):
if self.redeem_loyalty_points and (
not self.loyalty_redemption_account or not self.loyalty_redemption_cost_center
@@ -558,6 +556,8 @@ class POSInvoice(SalesInvoice):
self.status = "Draft"
return
total = flt(self.rounded_total) or flt(self.grand_total)
if not status:
if self.docstatus == 2:
status = "Cancelled"
@@ -573,6 +573,14 @@ class POSInvoice(SalesInvoice):
self.status = "Overdue and Discounted"
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) < getdate(nowdate()):
self.status = "Overdue"
elif (
0 < flt(self.outstanding_amount) < total
and self.is_discounted
and self.get_discounting_status() == "Disbursed"
):
self.status = "Partly Paid and Discounted"
elif 0 < flt(self.outstanding_amount) < total:
self.status = "Partly Paid"
elif (
flt(self.outstanding_amount) > 0
and getdate(self.due_date) >= getdate(nowdate())
@@ -709,7 +717,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)
@@ -724,6 +738,7 @@ class POSInvoice(SalesInvoice):
"utm_campaign": profile.get("utm_campaign"),
"utm_medium": profile.get("utm_medium"),
"allow_print_before_pay": profile.get("allow_print_before_pay"),
"set_default_payment": profile.get("set_grand_total_to_default_mop"),
}
@frappe.whitelist()
@@ -793,6 +808,48 @@ class POSInvoice(SalesInvoice):
if pr:
return frappe.get_doc("Payment Request", pr)
@frappe.whitelist()
def update_payments(self, payments):
if self.status == "Consolidated":
frappe.throw(_("Create Payment Entry for Consolidated POS Invoices."))
paid_amount = flt(self.paid_amount)
total = flt(self.rounded_total) or flt(self.grand_total)
if paid_amount >= total:
frappe.throw(title=_("Invoice Paid"), msg=_("This invoice has already been paid."))
idx = self.payments[-1].idx if self.payments else -1
for d in payments:
idx += 1
payment = create_payments_on_invoice(self, idx, frappe._dict(d))
paid_amount += flt(payment.amount)
payment.submit()
paid_amount = flt(flt(paid_amount), self.precision("paid_amount"))
base_paid_amount = flt(flt(paid_amount * self.conversion_rate), self.precision("base_paid_amount"))
outstanding_amount = (
flt(flt(total - paid_amount), self.precision("outstanding_amount")) if total > paid_amount else 0
)
change_amount = (
flt(flt(paid_amount - total), self.precision("change_amount")) if paid_amount > total else 0
)
pi = frappe.qb.DocType("POS Invoice")
query = (
frappe.qb.update(pi)
.set(pi.paid_amount, paid_amount)
.set(pi.base_paid_amount, base_paid_amount)
.set(pi.outstanding_amount, outstanding_amount)
.set(pi.change_amount, change_amount)
.where(pi.name == self.name)
)
query.run()
self.reload()
self.set_status(update=True)
@frappe.whitelist()
def get_stock_availability(item_code, warehouse):
@@ -818,10 +875,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"
):
@@ -844,13 +899,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, "") == "")
@@ -944,3 +1035,19 @@ def get_item_group(pos_profile):
item_groups.extend(get_descendants_of("Item Group", row.item_group))
return list(set(item_groups))
def create_payments_on_invoice(doc, idx, payment_details):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
payment = frappe.new_doc("Sales Invoice Payment")
payment.idx = idx
payment.mode_of_payment = payment_details.mode_of_payment
payment.amount = payment_details.amount
payment.base_amount = payment.amount * doc.conversion_rate
payment.parent = doc.name
payment.parentfield = "payments"
payment.parenttype = doc.doctype
payment.account = get_bank_cash_account(payment.mode_of_payment, doc.company).get("account")
return payment

View File

@@ -18,11 +18,13 @@ frappe.listview_settings["POS Invoice"] = {
Draft: "red",
Unpaid: "orange",
Paid: "green",
"Partly Paid": "yellow",
Submitted: "blue",
Consolidated: "green",
Return: "darkgrey",
"Unpaid and Discounted": "orange",
"Overdue and Discounted": "red",
"Partly Paid and Discounted": "yellow",
Overdue: "red",
};
return [__(doc.status), status_color[doc.status], "status,=," + doc.status];

View File

@@ -401,6 +401,50 @@ class TestPOSInvoice(IntegrationTestCase):
pos_inv.insert()
self.assertRaises(PartialPaymentValidationError, pos_inv.submit)
def test_partly_paid_invoices(self):
set_allow_partial_payment(self.pos_profile, 1)
pos_inv = create_pos_invoice(pos_profile=self.pos_profile.name, rate=100, do_not_save=1)
pos_inv.append(
"payments",
{"mode_of_payment": "Cash", "amount": 90},
)
pos_inv.save()
pos_inv.submit()
self.assertEqual(pos_inv.paid_amount, 90)
self.assertEqual(pos_inv.status, "Partly Paid")
pos_inv.update_payments(payments=[{"mode_of_payment": "Cash", "amount": 10}])
self.assertEqual(pos_inv.paid_amount, 100)
self.assertEqual(pos_inv.status, "Paid")
set_allow_partial_payment(self.pos_profile, 0)
def test_multi_payment_for_partly_paid_invoices(self):
set_allow_partial_payment(self.pos_profile, 1)
pos_inv = create_pos_invoice(pos_profile=self.pos_profile.name, rate=100, do_not_save=1)
pos_inv.append(
"payments",
{"mode_of_payment": "Cash", "amount": 90},
)
pos_inv.save()
pos_inv.submit()
self.assertEqual(pos_inv.paid_amount, 90)
self.assertEqual(pos_inv.status, "Partly Paid")
pos_inv.update_payments(payments=[{"mode_of_payment": "Cash", "amount": 5}])
self.assertEqual(pos_inv.paid_amount, 95)
self.assertEqual(pos_inv.status, "Partly Paid")
pos_inv.update_payments(payments=[{"mode_of_payment": "Cash", "amount": 5}])
self.assertEqual(pos_inv.paid_amount, 100)
self.assertEqual(pos_inv.status, "Paid")
set_allow_partial_payment(self.pos_profile, 0)
def test_serialized_item_transaction(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
@@ -1089,8 +1133,7 @@ def create_pos_invoice(**args):
return pos_inv
def make_batch_item(item_name):
from erpnext.stock.doctype.item.test_item import make_item
if not frappe.db.exists(item_name):
return make_item(item_name, dict(has_batch_no=1, create_new_batch=1, is_stock_item=1))
def set_allow_partial_payment(pos_profile, value):
pos_profile.reload()
pos_profile.allow_partial_payment = value
pos_profile.save()

View File

@@ -5,6 +5,7 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company",
"posting_date",
"posting_time",
"merge_invoices_based_on",
@@ -113,12 +114,22 @@
"label": "Posting Time",
"no_copy": 1,
"reqd": 1
},
{
"fieldname": "company",
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Company",
"options": "Company",
"print_hide": 1,
"remember_last_selected_value": 1,
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2024-03-27 13:10:15.620564",
"modified": "2025-07-02 17:08:04.747202",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice Merge Log",
@@ -179,8 +190,9 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -29,11 +29,10 @@ class POSInvoiceMergeLog(Document):
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.pos_invoice_reference.pos_invoice_reference import (
POSInvoiceReference,
)
from erpnext.accounts.doctype.pos_invoice_reference.pos_invoice_reference import POSInvoiceReference
amended_from: DF.Link | None
company: DF.Link
consolidated_credit_note: DF.Link | None
consolidated_invoice: DF.Link | None
customer: DF.Link
@@ -339,6 +338,11 @@ class POSInvoiceMergeLog(Document):
invoice.flags.ignore_pos_profile = True
invoice.pos_profile = ""
# Unset Commission Section
invoice.set("sales_partner", None)
invoice.set("commission_rate", 0)
invoice.set("total_commission", 0)
return invoice
def get_new_sales_invoice(self):
@@ -584,6 +588,7 @@ def create_merge_logs(invoice_by_customer, closing_entry=None):
merge_log.posting_time = (
get_time(closing_entry.get("posting_time")) if closing_entry else nowtime()
)
merge_log.company = closing_entry.get("company") if closing_entry else None
merge_log.customer = customer
merge_log.pos_closing_entry = closing_entry.get("name") if closing_entry else None
merge_log.set("pos_invoices", _invoices)

View File

@@ -491,3 +491,26 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv3.consolidated_invoice))
self.assertTrue(pos_inv2.consolidated_invoice == pos_inv3.consolidated_invoice)
def test_company_in_pos_invoice_merge_log(self):
"""
Test if the company is fetched from POS Closing Entry
"""
test_user, pos_profile = init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name)
pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
pos_inv.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 300})
pos_inv.save()
pos_inv.submit()
closing_entry = make_closing_entry_from_opening(opening_entry)
closing_entry.insert()
closing_entry.submit()
self.assertTrue(frappe.db.exists("POS Invoice Merge Log", {"pos_closing_entry": closing_entry.name}))
pos_merge_log_company = frappe.db.get_value(
"POS Invoice Merge Log", {"pos_closing_entry": closing_entry.name}, "company"
)
self.assertEqual(pos_merge_log_company, closing_entry.company)

View File

@@ -37,6 +37,8 @@ class POSOpeningEntry(StatusUpdater):
def validate(self):
self.validate_pos_profile_and_cashier()
self.check_open_pos_exists()
self.check_user_already_assigned()
self.validate_payment_method_account()
self.set_status()
@@ -49,6 +51,22 @@ class POSOpeningEntry(StatusUpdater):
if not cint(frappe.db.get_value("User", self.user, "enabled")):
frappe.throw(_("User {} is disabled. Please select valid user/cashier").format(self.user))
def check_open_pos_exists(self):
if frappe.db.exists("POS Opening Entry", {"pos_profile": self.pos_profile, "status": "Open"}):
frappe.throw(
title=_("POS Opening Entry Exists"),
msg=_(
"{0} is open. Close the POS or cancel the existing POS Opening Entry to create a new POS Opening Entry."
).format(frappe.bold(self.pos_profile)),
)
def check_user_already_assigned(self):
if frappe.db.exists("POS Opening Entry", {"user": self.user, "status": "Open"}):
frappe.throw(
title=_("Cannot Assign Cashier"),
msg=_("Cashier is currently assigned to another POS."),
)
def validate_payment_method_account(self):
invalid_modes = []
for d in self.balance_details:
@@ -71,5 +89,25 @@ class POSOpeningEntry(StatusUpdater):
def on_submit(self):
self.set_status(update=True)
def before_cancel(self):
self.check_poe_is_cancellable()
def on_cancel(self):
self.set_status(update=True)
frappe.publish_realtime(
f"poe_{self.name}",
message={"operation": "Cancelled"},
docname=f"POS Opening Entry/{self.name}",
)
def check_poe_is_cancellable(self):
from erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry import get_invoices
invoices = get_invoices(
self.period_start_date, frappe.utils.get_datetime(), self.pos_profile, self.user
)
if invoices.get("invoices"):
frappe.throw(
title=_("POS Opening Entry Cancellation Error"),
msg=_("POS Opening Entry cannot be cancelled as unconsolidated Invoices exists."),
)

View File

@@ -3,14 +3,107 @@
import unittest
import frappe
from frappe.core.doctype.user_permission.test_user_permission import create_user
from frappe.tests import IntegrationTestCase
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
class TestPOSOpeningEntry(IntegrationTestCase):
pass
@classmethod
def setUpClass(cls):
frappe.db.sql("delete from `tabPOS Opening Entry`")
cls.enterClassContext(cls.change_settings("POS Settings", {"invoice_type": "POS Invoice"}))
@classmethod
def tearDownClass(cls):
frappe.db.sql("delete from `tabPOS Opening Entry`")
def setUp(self):
# Make stock available for POS Sales
frappe.db.sql("delete from `tabPOS Opening Entry`")
make_stock_entry(target="_Test Warehouse - _TC", qty=2, basic_rate=100)
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
self.init_user_and_profile = init_user_and_profile
def tearDown(self):
frappe.set_user("Administrator")
frappe.db.sql("delete from `tabPOS Profile`")
def test_pos_opening_entry(self):
test_user, pos_profile = self.init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name)
self.assertEqual(opening_entry.status, "Open")
self.assertNotEqual(opening_entry.docstatus, 0)
def test_multiple_pos_opening_entries_for_same_pos_profile(self):
test_user, pos_profile = self.init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name)
self.assertEqual(opening_entry.status, "Open")
with self.assertRaises(frappe.ValidationError):
create_opening_entry(pos_profile, test_user.name)
def test_multiple_pos_opening_entry_for_multiple_pos_profiles(self):
test_user, pos_profile = self.init_user_and_profile()
opening_entry_1 = create_opening_entry(pos_profile, test_user.name)
self.assertEqual(opening_entry_1.status, "Open")
self.assertEqual(opening_entry_1.user, test_user.name)
cashier_user = create_user("test_cashier@example.com", "Accounts Manager", "Sales Manager")
frappe.set_user(cashier_user.name)
pos_profile2 = make_pos_profile(name="_Test POS Profile 2")
opening_entry_2 = create_opening_entry(pos_profile2, cashier_user.name)
self.assertEqual(opening_entry_2.status, "Open")
self.assertEqual(opening_entry_2.user, cashier_user.name)
def test_multiple_pos_opening_entry_for_same_pos_profile_by_multiple_user(self):
test_user, pos_profile = self.init_user_and_profile()
cashier_user = create_user("test_cashier@example.com", "Accounts Manager", "Sales Manager")
opening_entry = create_opening_entry(pos_profile, test_user.name)
self.assertEqual(opening_entry.status, "Open")
with self.assertRaises(frappe.ValidationError):
create_opening_entry(pos_profile, cashier_user.name)
def test_user_assignment_to_multiple_pos_profile(self):
test_user, pos_profile = self.init_user_and_profile()
opening_entry_1 = create_opening_entry(pos_profile, test_user.name)
self.assertEqual(opening_entry_1.user, test_user.name)
pos_profile2 = make_pos_profile(name="_Test POS Profile 2")
with self.assertRaises(frappe.ValidationError):
create_opening_entry(pos_profile2, test_user.name)
def test_cancel_pos_opening_entry_without_invoices(self):
test_user, pos_profile = self.init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name, get_obj=True)
opening_entry.cancel()
self.assertEqual(opening_entry.status, "Cancelled")
self.assertNotEqual(opening_entry.docstatus, 1)
def test_cancel_pos_opening_entry_with_invoice(self):
test_user, pos_profile = self.init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name, get_obj=True)
pos_inv1 = create_pos_invoice(pos_profile=pos_profile.name, rate=100, do_not_save=1)
pos_inv1.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 100})
pos_inv1.save()
pos_inv1.submit()
self.assertRaises(frappe.ValidationError, opening_entry.cancel)
def create_opening_entry(pos_profile, user):
def create_opening_entry(pos_profile, user, get_obj=False):
entry = frappe.new_doc("POS Opening Entry")
entry.pos_profile = pos_profile.name
entry.user = user
@@ -24,4 +117,7 @@ def create_opening_entry(pos_profile, user):
entry.set("balance_details", balance_details)
entry.submit()
if get_obj:
return entry
return entry.as_dict()

View File

@@ -135,6 +135,7 @@ frappe.ui.form.on("POS Profile", {
company: function (frm) {
frm.trigger("toggle_display_account_head");
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
erpnext.utils.set_letter_head(frm);
},
toggle_display_account_head: function (frm) {

View File

@@ -26,13 +26,14 @@
"auto_add_item_to_cart",
"validate_stock_on_save",
"print_receipt_on_order_complete",
"action_on_new_invoice",
"column_break_16",
"update_stock",
"ignore_pricing_rule",
"allow_rate_change",
"allow_discount_change",
"set_grand_total_to_default_mop",
"action_on_new_invoice",
"allow_partial_payment",
"section_break_23",
"item_groups",
"column_break_25",
@@ -423,6 +424,12 @@
"fieldtype": "Select",
"label": "Action on New Invoice",
"options": "Always Ask\nSave Changes and Load New Invoice\nDiscard Changes and Load New Invoice"
},
{
"default": "0",
"fieldname": "allow_partial_payment",
"fieldtype": "Check",
"label": "Allow Partial Payment"
}
],
"grid_page_length": 50,
@@ -451,7 +458,7 @@
"link_fieldname": "pos_profile"
}
],
"modified": "2025-05-23 12:12:32.247652",
"modified": "2025-06-24 11:19:19.834905",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",

View File

@@ -32,6 +32,7 @@ class POSProfile(Document):
"Always Ask", "Save Changes and Load New Invoice", "Discard Changes and Load New Invoice"
]
allow_discount_change: DF.Check
allow_partial_payment: DF.Check
allow_rate_change: DF.Check
applicable_for_users: DF.Table[POSProfileUser]
apply_discount_on: DF.Literal["Grand Total", "Net Total"]

View File

@@ -19,13 +19,14 @@
"fieldname": "field",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Field"
"label": "Field",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:16.969895",
"modified": "2025-07-29 18:08:40.323579",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Search Fields",
@@ -35,4 +36,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -41,56 +41,68 @@ frappe.ui.form.on("Pricing Rule", {
<tr><td>
<h4>
<i class="fa fa-hand-right"></i>
{{__('Notes')}}
${__("Notes")}
</h4>
<ul>
<li>
{{__("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria.")}}
${__("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria.")}
</li>
<li>
{{__("If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field.")}}
${__(
"If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field."
)}
</li>
<li>
{{__('Discount Percentage can be applied either against a Price List or for all Price List.')}}
${__("Discount Percentage can be applied either against a Price List or for all Price List.")}
</li>
<li>
{{__('To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled.')}}
${__(
"To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled."
)}
</li>
</ul>
</td></tr>
<tr><td>
<h4><i class="fa fa-question-sign"></i>
{{__('How Pricing Rule is applied?')}}
${__("How Pricing Rule is applied?")}
</h4>
<ol>
<li>
{{__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}}
${__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}
</li>
<li>
{{__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc.")}}
${__(
"Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc."
)}
</li>
<li>
{{__('Pricing Rules are further filtered based on quantity.')}}
${__("Pricing Rules are further filtered based on quantity.")}
</li>
<li>
{{__('If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.')}}
${__(
"If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions."
)}
</li>
<li>
{{__('Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:')}}
${__(
"Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:"
)}
<ul>
<li>
{{__('Item Code > Item Group > Brand')}}
${__("Item Code > Item Group > Brand")}
</li>
<li>
{{__('Customer > Customer Group > Territory')}}
${__("Customer > Customer Group > Territory")}
</li>
<li>
{{__('Supplier > Supplier Type')}}
${__("Supplier > Supplier Type")}
</li>
</ul>
</li>
<li>
{{__('If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.')}}
${__(
"If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict."
)}
</li>
</ol>
</td></tr>

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

@@ -169,7 +169,7 @@ class PricingRule(Document):
tocheck = frappe.scrub(self.get("applicable_for", ""))
if tocheck and not self.get(tocheck):
throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError)
throw(_("{0} is required").format(_(self.meta.get_label(tocheck))), frappe.MandatoryError)
if self.apply_rule_on_other:
o_field = "other_" + frappe.scrub(self.apply_rule_on_other)
@@ -702,17 +702,6 @@ def set_transaction_type(args):
args.transaction_type = "buying"
@frappe.whitelist()
def make_pricing_rule(doctype, docname):
doc = frappe.new_doc("Pricing Rule")
doc.applicable_for = doctype
doc.set(frappe.scrub(doctype), docname)
doc.selling = 1 if doctype == "Customer" else 0
doc.buying = 1 if doctype == "Supplier" else 0
return doc
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):

View File

@@ -206,6 +206,56 @@ class TestPricingRule(IntegrationTestCase):
details = get_item_details(args)
self.assertEqual(details.get("discount_percentage"), 10)
def test_unset_group_condition(self):
"""
If args are not set for group condition, then pricing rule should not be applied.
"""
from erpnext.stock.get_item_details import get_item_details
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule",
"apply_on": "Item Code",
"items": [{"item_code": "_Test Item"}],
"currency": "USD",
"selling": 1,
"rate_or_discount": "Discount Percentage",
"rate": 0,
"discount_percentage": 10,
"applicable_for": "Territory",
"territory": "All Territories",
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
args = frappe._dict(
{
"item_code": "_Test Item",
"company": "_Test Company",
"price_list": "_Test Price List",
"currency": "_Test Currency",
"doctype": "Sales Order",
"conversion_rate": 1,
"price_list_currency": "_Test Currency",
"plc_conversion_rate": 1,
"order_type": "Sales",
"customer": "_Test Customer",
"name": None,
}
)
# without territory in customer
customer = frappe.get_doc("Customer", "_Test Customer")
territory = customer.territory
customer.territory = None
customer.save()
details = get_item_details(args)
self.assertEqual(details.get("discount_percentage"), 0)
customer.territory = territory
customer.save()
def test_pricing_rule_for_variants(self):
from erpnext.stock.get_item_details import get_item_details

View File

@@ -223,6 +223,10 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
)
frappe.flags.tree_conditions[key] = condition
elif allow_blank:
condition = f"ifnull({table}.{field}, '') = ''"
return condition

View File

@@ -40,6 +40,13 @@ class TestProcessDeferredAccounting(IntegrationTestCase):
si.save()
si.submit()
original_gle = [
["Debtors - _TC", 3000.0, 0, "2023-07-01"],
[deferred_account, 0.0, 3000, "2023-07-01"],
]
check_gl_entries(self, si.name, original_gle, "2023-07-01")
process_deferred_accounting = frappe.get_doc(
dict(
doctype="Process Deferred Accounting",
@@ -63,6 +70,12 @@ class TestProcessDeferredAccounting(IntegrationTestCase):
]
check_gl_entries(self, si.name, expected_gle, "2023-07-01")
# cancel the process deferred accounting document
process_deferred_accounting.cancel()
# check if gl entries are cancelled
check_gl_entries(self, si.name, original_gle, "2023-07-01")
change_acc_settings()
def test_pda_submission_and_cancellation(self):

View File

@@ -54,6 +54,9 @@ frappe.ui.form.on("Process Statement Of Accounts", {
};
});
frm.set_query("account", function () {
if (!frm.doc.company) {
frappe.throw(__("Please set Company"));
}
return {
filters: {
company: frm.doc.company,
@@ -61,6 +64,9 @@ frappe.ui.form.on("Process Statement Of Accounts", {
};
});
frm.set_query("cost_center", function () {
if (!frm.doc.company) {
frappe.throw(__("Please set Company"));
}
return {
filters: {
company: frm.doc.company,
@@ -68,17 +74,36 @@ frappe.ui.form.on("Process Statement Of Accounts", {
};
});
frm.set_query("project", function () {
if (!frm.doc.company) {
frappe.throw(__("Please set Company"));
}
return {
filters: {
company: frm.doc.company,
},
};
});
frm.set_query("print_format", function () {
return {
filters: {
print_format_for: "Report",
report: frm.doc.report,
disabled: 0,
print_format_type: "Jinja",
},
};
});
if (frm.doc.__islocal) {
frm.set_value("from_date", frappe.datetime.add_months(frappe.datetime.get_today(), -1));
frm.set_value("to_date", frappe.datetime.get_today());
}
},
company: function (frm) {
frm.set_value("account", "");
frm.set_value("cost_center", "");
frm.set_value("project", "");
erpnext.utils.set_letter_head(frm);
},
report: function (frm) {
let filters = {
company: frm.doc.company,
@@ -91,6 +116,16 @@ frappe.ui.form.on("Process Statement Of Accounts", {
filters: filters,
};
});
frm.set_query("print_format", function () {
return {
filters: {
print_format_for: "Report",
report: frm.doc.report,
disabled: 0,
print_format_type: "Jinja",
},
};
});
},
customer_collection: function (frm) {
frm.set_value("collection_name", "");

View File

@@ -27,6 +27,7 @@
"sales_person",
"show_remarks",
"based_on_payment_terms",
"show_future_payments",
"section_break_3",
"customer_collection",
"collection_name",
@@ -37,6 +38,7 @@
"column_break_17",
"customers",
"preferences",
"print_format",
"orientation",
"include_break",
"include_ageing",
@@ -78,18 +80,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 +332,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');",
@@ -376,7 +379,7 @@
"default": "0",
"fieldname": "ignore_exchange_rate_revaluation_journals",
"fieldtype": "Check",
"label": "Ignore Exchange Rate Revaluation Journals"
"label": "Ignore Exchange Rate Revaluation and Gain / Loss Journals"
},
{
"default": "0",
@@ -397,10 +400,23 @@
"fieldtype": "Select",
"label": "Categorize By",
"options": "\nCategorize by Voucher\nCategorize by Voucher (Consolidated)"
},
{
"default": "0",
"depends_on": "eval:(doc.report == 'Accounts Receivable');",
"fieldname": "show_future_payments",
"fieldtype": "Check",
"label": "Show Future Payments"
},
{
"fieldname": "print_format",
"fieldtype": "Link",
"label": "Print Format",
"options": "Print Format"
}
],
"links": [],
"modified": "2025-04-30 14:43:23.643006",
"modified": "2025-09-03 14:24:43.608565",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",

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