Compare commits

...

938 Commits

Author SHA1 Message Date
Nabin Hait
5bb4058ef4 fix: Maintain same rate in Stock Ledger until stock become positive (#27227)
* fix: Maintain same rate in Stock Ledger until stock become positive

* fix: Maintain same rate in Stock Ledger until stock become positive

(cherry picked from commit 10754831c3)

# Conflicts:
#	erpnext/stock/stock_ledger.py
2025-02-24 00:13:13 +00:00
Frappe PR Bot
987a95d2b5 fix: sync translations from crowdin (#46036)
* fix: Persian translations

* fix: Bosnian translations

* fix: Turkish translations

* fix: Persian translations

* fix: Bosnian translations
2025-02-23 10:38:54 +01:00
Marica
c3b45c933a Merge pull request #45932 from 0xD0M1M0/fix_discount_payment_entry
fix: discount accounting
2025-02-21 20:37:06 +05:30
Ravibharathi
1ec182430d feat: add total weight in shipment (#46049)
Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com>
2025-02-21 15:15:21 +01:00
Diptanil Saha
8e6959dfad fix: pos opening entry dialog not saving on change data (#46066) 2025-02-21 17:50:51 +05:30
0xD0M1M0
a91fe5cbb3 feat: add testcase for discount_payment_entry 2025-02-20 17:12:21 +01:00
0xD0M1M0
8c5aea15ac Merge branch 'frappe:develop' into fix_discount_payment_entry 2025-02-20 15:57:51 +01:00
rohitwaghchaure
f68730f444 Merge pull request #46037 from rohitwaghchaure/fixed-support-31955
fix: inventory dimension for maintenance visit
2025-02-20 11:41:41 +05:30
Rohit Waghchaure
cd4ba69262 fix: inventory dimension for maintence visit 2025-02-20 09:05:35 +05:30
Frappe PR Bot
78dedc0773 fix: sync translations from crowdin (#45997) 2025-02-19 14:20:18 +01:00
rohitwaghchaure
75379b79fc Merge pull request #46021 from rohitwaghchaure/fixed-support-31874
fix: incorrect stock value difference for adjustment entry
2025-02-19 16:39:45 +05:30
Khushi Rawat
83cafb892c Merge pull request #46022 from khushi8112/fetch-asset-location-from-purchase-doc
fix: reset location only if there is value in row item location field
2025-02-19 16:30:20 +05:30
Akhil Narang
a1cbcda4c5 Merge pull request #46003 from akhilnarang/fix-xss
fix(send_message): escape HTML in the text
2025-02-19 16:14:19 +05:30
Rohit Waghchaure
df83e427a3 fix: incorrect stock value difference for adjustment entry 2025-02-19 16:02:39 +05:30
Khushi Rawat
7f8d08c8eb fix: reset location only if there is value in row item location field 2025-02-19 16:02:01 +05:30
rohitwaghchaure
8e42764274 Merge pull request #45838 from CaseSolvedUK/item-fix
fix: remove public access to list items
2025-02-19 15:50:13 +05:30
mergify[bot]
65c45a3f5b feat: added ability to use custom html format for process statement of accounts (copy #45746) (#46011)
feat: added ability to use custom html format for process statement of accounts (#45746)

* feat: added ability to use custom print format for process statement of accounts documents.

* fix: handles missing hook issues

* chore: linter changes

---------

Co-authored-by: Boy4099 <mashtawayne4099@gmail.com>
Co-authored-by: ruthra kumar <ruthra@erpnext.com>
(cherry picked from commit a0cd08e9ea)

Co-authored-by: Steve Wilson <stevew9009@gmail.com>
2025-02-19 15:44:35 +05:30
Ejaaz Khan
941085000a fix: round sum amount in JE auditing PF (#45961) 2025-02-19 15:40:55 +05:30
Venkatesh
17a2f44290 fix(pos profile): check company while validating mandatory accounting dimension (#45974) 2025-02-19 15:39:01 +05:30
Sanket Shah
24394765a6 fix: handle division by zero error (#45966)
Co-authored-by: Sanket322 <shahsanket322003.com>
2025-02-19 15:37:54 +05:30
Khushi Rawat
fa31a0282e Merge pull request #45898 from nabinhait/asset-depr-schedule-patch
fix: patch for creating asset depreciation schedule records
2025-02-19 15:37:27 +05:30
Khushi Rawat
38e1054eb7 Merge pull request #45872 from khushi8112/set-purchase-doc-row-item-to-asset
fix: enable asset value editing for duplicate item code
2025-02-19 15:30:53 +05:30
Khushi Rawat
2bb79197aa fix: reset location only if there is value in row item location field 2025-02-19 15:04:26 +05:30
Bhavansathru
73e82b7afa fix: fetch child account data for selected parent (#45904)
* fix: fetch child account data for selected parent

* fix: change reference name

---------

Co-authored-by: venkat102 <venkatesharunachalam659@gmail.com>
2025-02-19 13:57:31 +05:30
Khushi Rawat
4821c44227 Merge pull request #45895 from khushi8112/fix-scrapping-of-fully-depreciated-asset
fix: do not reschedule depreciation for fully depreciated asset on scrap
2025-02-19 13:06:39 +05:30
Khushi Rawat
44c1425e73 fix: validate if no matching item found 2025-02-19 13:01:27 +05:30
rohitwaghchaure
4b87610d95 Merge pull request #45750 from mihir-kandoi/st20447
feat: added option to enforce free item qty in pricing rule
2025-02-19 12:49:01 +05:30
Akhil Narang
448a5db20f fix(send_message): escape HTML in the text
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2025-02-19 12:23:10 +05:30
ruthra kumar
5fed3866b6 Merge pull request #45882 from aerele/quotation-exchange-rate
fix(quotation): fetch exchange rate on currency change
2025-02-19 10:50:38 +05:30
rohitwaghchaure
f05c1d7e7b Merge pull request #45980 from mihir-kandoi/st31872
fix: check if employee is currently working on another workstation
2025-02-18 20:41:22 +05:30
rohitwaghchaure
32f616ad87 Merge pull request #45977 from rohitwaghchaure/fixed-support-31935
fix: millisecond issue for posting datetime
2025-02-18 20:08:15 +05:30
rohitwaghchaure
93a8440908 Merge pull request #45971 from mihir-kandoi/st32087
fix: set sco_qty field of PO to non negative
2025-02-18 19:58:00 +05:30
rohitwaghchaure
be813b5bba Merge pull request #45976 from rohitwaghchaure/fixed-support-32073
fix: slow query
2025-02-18 19:56:37 +05:30
Rohit Waghchaure
ac9e5c0163 fix: millisecond issue for posting datetime 2025-02-18 18:58:45 +05:30
Mihir Kandoi
4487edb255 fix: throw correct exception 2025-02-18 14:49:52 +05:30
Mihir Kandoi
8234e659c8 fix: check if employee is currently working on another workstation 2025-02-18 14:22:39 +05:30
ruthra kumar
927eae79d5 Merge pull request #45765 from aerele/dimensions-in-order-item
fix: add accounting dimensions section in sales order item
2025-02-18 14:10:49 +05:30
Rohit Waghchaure
8cfab57fc8 fix: slow query 2025-02-18 13:52:26 +05:30
rohitwaghchaure
74621eeb1b Merge pull request #45970 from rohitwaghchaure/fixed-support-32040
fix: serial no status for internal transfer delivery note
2025-02-18 13:51:00 +05:30
ruthra kumar
1eea76cbad Merge pull request #45723 from aerele/validate-payment-request-total
fix: validate payment request total of partly paid invoice
2025-02-18 13:11:08 +05:30
Rohit Waghchaure
3333331a3d fix: serial no status for internal transfer delivery note 2025-02-18 12:59:10 +05:30
Mihir Kandoi
dfc3dc4944 fix: set sco_qty field of PO to non negative 2025-02-18 12:37:07 +05:30
ruthra kumar
7c7aa831ec Merge pull request #45965 from frappe/l10n_develop
fix: sync translations from crowdin
2025-02-18 12:12:22 +05:30
Diptanil Saha
70260c8c86 fix: pos checkout button color on dark mode (#45967) 2025-02-18 11:48:04 +05:30
ruthra kumar
c46af238d4 Merge pull request #45687 from aerele/validate_equity_account
fix: add validation to allow equity account
2025-02-18 11:44:34 +05:30
Frappe PR Bot
7e61b67ba8 fix: German translations 2025-02-18 05:48:36 +05:30
Frappe PR Bot
5e8124900f fix: Bosnian translations 2025-02-18 05:48:32 +05:30
Frappe PR Bot
3788339ea0 fix: Swedish translations 2025-02-18 05:48:20 +05:30
Frappe PR Bot
fe47ca8566 fix: sync translations from crowdin (#45927)
* fix: Swedish translations

* fix: Bosnian translations

* fix: Bosnian translations

* fix: French translations

* fix: Spanish translations

* fix: Arabic translations

* fix: Hungarian translations

* fix: Polish translations

* fix: Russian translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Chinese Simplified translations

* fix: Persian translations

* fix: Bosnian translations

* fix: German translations

* fix: Esperanto translations
2025-02-17 20:07:11 +01:00
Mihir Kandoi
844f1636c0 fix: set default value to 0 as per new logic 2025-02-17 18:47:35 +05:30
Mihir Kandoi
f3d598881c refactor: rename field 2025-02-17 18:21:22 +05:30
rohitwaghchaure
2fcc5e3f55 Merge pull request #45946 from rohitwaghchaure/fixed-support-32008
fix: provision to enable naming series for SABB
2025-02-17 17:00:34 +05:30
Rohit Waghchaure
fe43975cdd fix: provision to enable naming series for SABB 2025-02-17 16:36:55 +05:30
rohitwaghchaure
c2b4a79b5b Merge pull request #45950 from rohitwaghchaure/fixed-bom-creator-issue
fix: remove unused fields
2025-02-17 16:11:55 +05:30
Soham Kulkarni
98cc1558d3 Small UI changes (#45938)
* fix: change erpnext logo and home workpsace icon

* fix: actually change home workspace icon

* fix: typo in hooks.py
2025-02-17 15:40:22 +05:30
Rohit Waghchaure
f206034a79 fix: remove unused fields 2025-02-17 15:40:17 +05:30
0xD0M1M0
6f1bc5225a fix: auto create asset due to message error (#45934)
* fix: auto create asset due to message error

* fix: linters
2025-02-17 15:12:26 +05:30
Diptanil Saha
5506b44b6f fix: improve pos return (#45671)
* fix: pos return validation for zero qty item

* fix: pos return invoice onload ui

* feat: added item qty returned in pos ui

* refactor: removed console log statement

* feat: check return can be made before loading it on pos

* fix: pos edit invoice onload ui

* fix: returned

* refactor: code cleanup
2025-02-17 15:00:56 +05:30
Diptanil Saha
d94802067b fix: disable partial payment in pos (#45752)
* fix: disable partial payment in pos

* test: disable partial payment

* test: removed print statement

* test: using save method to auto calculate paid_amount

* test: paid_amount calculation using save method

* test: added save method to calculate paid_amount

* test: outstanding amount

* test: added test for partial payments in pos invoice

* fix: custom validation error for partial payment

* test: using partial payment validation

* fix: validate only on submit
2025-02-17 14:26:50 +05:30
rohitwaghchaure
6c8cb9717d Merge pull request #45941 from rohitwaghchaure/fixed-support-31066
fix: letter head for quality inspection
2025-02-17 13:57:23 +05:30
Rohit Waghchaure
cdd41373b6 fix: letter head for quality inspection 2025-02-17 13:20:52 +05:30
ruthra kumar
419b149d05 Merge pull request #45630 from ruthra-kumar/remove_acc_balance_field_from_payment_entry
refactor: remove redundant balance fields from Payment Entry
2025-02-17 10:58:02 +05:30
Frappe PR Bot
019f6422be chore: update POT file (#45935) 2025-02-16 12:15:43 +01:00
0xD0M1M0
947a4fb091 fix: only negative for "Pay" 2025-02-15 22:36:34 +01:00
0xD0M1M0
03d515208a fix: discount accounting 2025-02-15 21:23:05 +01:00
rohitwaghchaure
9e4c82e055 Merge pull request #45914 from rohitwaghchaure/fixed-reposting-issue
fix: start reposting button not working
2025-02-14 21:28:20 +05:30
Diptanil Saha
60a5f4f30d fix: pos accounting dimension fieldname error (#45899)
* fix: pos accounting dimension fieldname error

* fix: method to get enabled accounting dimensions

* fix: fetch enabled accounting dimensions

* fix: clear flags for accounting_dimensions_details on_update

* refactor: validation for doctype

* fix: using get_checks_for_pl_and_bs_accounts for accounting dimensions
2025-02-14 17:31:53 +05:30
Diptanil Saha
bee26e046e fix: prevent duplicate pos fields in pos settings (#45873)
fix: restrict duplicate pos fields in pos settings
2025-02-14 17:26:54 +05:30
Frappe PR Bot
e6b6849940 fix: sync translations from crowdin (#45876)
* fix: Swedish translations

* fix: Turkish translations

* fix: Persian translations

* fix: Bosnian translations

* fix: Spanish translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Persian translations

* fix: Bosnian translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Chinese Simplified translations

* fix: Persian translations

* fix: Bosnian translations
2025-02-14 12:26:34 +01:00
ruthra kumar
6e67a1ba7c Merge pull request #45912 from aerele/add-payment-gateway
fix: include missing payment_gateway parameter in Payment Request URL
2025-02-14 16:44:04 +05:30
Diptanil Saha
f0a6399056 feat: disable auto setting grand total to default mode of payment (#45591) 2025-02-14 16:43:11 +05:30
Rohit Waghchaure
c81ce29e4c fix: start reposting button not working 2025-02-14 15:33:45 +05:30
rohitwaghchaure
0a364ed1c9 Merge pull request #45903 from rohitwaghchaure/fixed-support-31510
fix: allow scrap item with zero qty
2025-02-14 15:15:55 +05:30
Navin-S-R
dbac8cfc94 fix: include missing payment_gateway parameter in Payment Request URL 2025-02-14 13:14:27 +05:30
Rohit Waghchaure
706cb64279 fix: allow scrap item with zero qty 2025-02-13 19:10:21 +05:30
Nabin Hait
7324dcb7c8 fix: patch for creating asset depreciation schedule records 2025-02-13 18:02:56 +05:30
Khushi Rawat
fd4c4f98fa fix: do not reschedule depreciation for fully depreciated asset on scrap 2025-02-13 14:21:29 +05:30
ruthra kumar
a81867bc43 Merge pull request #45804 from aerele/auto-email-multiselect
fix(report): add options to multiselectlist fields
2025-02-13 14:16:16 +05:30
ruthra kumar
6886f5ef41 Merge pull request #45874 from ruthra-kumar/incorrect_taxable_amount_on_other_charges_calculation
fix: incorrect taxable_amount on `other_charges_calculation`
2025-02-13 13:08:56 +05:30
Diptanil Saha
72f8fc8a7b style: pos checkout button color (#45890)
style: pos checkout button color
2025-02-13 00:09:21 +05:30
rohitwaghchaure
5f554e1ec3 Merge pull request #45786 from barredterra/skip-warning-for-free-items
fix: skip warning for free items
2025-02-12 14:48:25 +05:30
venkat102
2f77a8bed1 fix(quotation): fetch exchange rate on currency change 2025-02-12 12:54:30 +05:30
rohitwaghchaure
b839094551 Merge pull request #45879 from rohitwaghchaure/fixed-SABB-naming
fix: changed naming series to random for SABB
2025-02-12 10:19:17 +05:30
Rohit Waghchaure
a007dc285d fix: changed naming series to random for SABB 2025-02-12 09:55:20 +05:30
rohitwaghchaure
3e990153a4 Merge pull request #45865 from mihir-kandoi/st30672-2
fix: dont update rate of free item on save
2025-02-12 08:42:19 +05:30
rohitwaghchaure
591ad7641f Merge pull request #45875 from mihir-kandoi/serial-batch-bundle-precision-fix
fix: add precision in serial_batch_bundle.py
2025-02-12 08:35:29 +05:30
Mihir Kandoi
4bf85d1a5a fix: add precision in serial_batch_bundle.py 2025-02-11 22:51:17 +05:30
ruthra kumar
6ab2106322 fix: incorrect taxable_amount on other_charges_calculation 2025-02-11 17:52:15 +05:30
rohitwaghchaure
c522071b58 Merge pull request #45862 from rohitwaghchaure/fixed-support-31345
fix: remove serial no if qty is zero
2025-02-11 16:56:56 +05:30
rohitwaghchaure
5df8609b33 Merge pull request #45869 from rohitwaghchaure/fixed-support-31464
fix: stock reco current valuation rate
2025-02-11 16:53:04 +05:30
Mihir Kandoi
4dcac56486 fix: add is_new in if condition 2025-02-11 16:29:01 +05:30
Khushi Rawat
da1b4cb9ab fix: link correct row item of purchase doc 2025-02-11 16:17:42 +05:30
Rohit Waghchaure
8d8f3afb39 fix: stock reco current valuation rate 2025-02-11 16:14:39 +05:30
Khushi Rawat
8af9dcb33e fix: make purchase_receipt_item and purchase_invoice_item fields of data type 2025-02-11 16:05:02 +05:30
Diptanil Saha
b95b13ecd8 fix: added validation for required invoice_fields in POS (#45780)
fix: added missing validation for required invoice_fields
2025-02-11 16:04:36 +05:30
Mihir Kandoi
6591e76a63 fix: dont update rate of free item on save 2025-02-11 15:32:35 +05:30
Smit Vora
c33c6b6560 Merge pull request #45532 from ljain112/fix-lcv-gl
fix: correct amt in account currency for lcv with manually distributed charges.
2025-02-11 15:32:01 +05:30
Smit Vora
0fdaa541f1 Merge pull request #45772 from ljain112/po-portal
fix: Party name in Supplier Portal for Purchase Order
2025-02-11 15:01:27 +05:30
Smit Vora
0bae273d41 fix: do not allow "Finance Book" in Accounting Dimensions (#45696) 2025-02-11 14:55:32 +05:30
Lakshit Jain
494310293c fix(regional): removed payment schedule validation in sales invoice for italy (#45852) 2025-02-11 14:50:55 +05:30
Rohit Waghchaure
3a4ae8c463 fix: remove serial no if qty is zero 2025-02-11 13:31:24 +05:30
ruthra kumar
110412d8ad Merge pull request #45794 from ljain112/fix-gl-rev
fix: correct amount in transaction currency for reverse gl entries
2025-02-11 12:59:24 +05:30
ruthra kumar
675b3330d9 Merge pull request #45792 from ljain112/fix-gl-val
fix: do not validate party against Receivable and Payable account for cancelled gl entries
2025-02-11 12:13:40 +05:30
ruthra kumar
8296e28689 Merge pull request #45839 from frappe/l10n_develop
fix: sync translations from crowdin
2025-02-11 10:39:43 +05:30
ruthra kumar
3977a7a06e Merge pull request #45781 from Sanket322/total_row_in_non_group
fix: Added Total Row for `Gross Profit` Report in Non-Grouped Invoices
2025-02-11 10:20:08 +05:30
ruthra kumar
1c725dee5d Merge pull request #45832 from ruthra-kumar/fix_migration_issue_for_reconciliation_sync
fix: possible model sync issue
2025-02-11 09:54:48 +05:30
Frappe PR Bot
e8871257a2 fix: Bosnian translations 2025-02-11 03:39:50 +05:30
Frappe PR Bot
a11b8db389 fix: Turkish translations 2025-02-11 03:39:41 +05:30
Frappe PR Bot
3c8214827c fix: Swedish translations 2025-02-11 03:39:37 +05:30
CaseSolved
2bd596ee3d fix: remove public access to list items 2025-02-10 20:46:41 +00:00
ruthra kumar
0069581aa3 fix: possible model sync issue 2025-02-10 17:16:09 +05:30
Raffael Meyer
cbcdc5e7e5 Merge pull request #45745 from HenningWendtland/buying-project
fix: map project from rfq to supplier quotation
2025-02-10 12:05:51 +01:00
Diptanil Saha
0b9c28620f fix: pos numpad editable action buttons (#45823) 2025-02-10 16:23:54 +05:30
HenningWendtland
8fa39bec61 fix: add project field map from mr to rfq 2025-02-10 11:45:58 +01:00
rohitwaghchaure
03290ef45f Merge pull request #45774 from DaizyModi/fix-attribute-error
fix: AttributeError in `get_item_details` when selecting/scanning batch in Delivery Note
2025-02-10 15:47:19 +05:30
ruthra kumar
71a507d30b Merge pull request #45747 from Sanket322/valid_response_json
fix: Handle Empty JSON in Report Parsing
2025-02-10 11:42:01 +05:30
ruthra kumar
e6176db2c9 Merge pull request #45809 from frappe/l10n_develop
fix: sync translations from crowdin
2025-02-10 11:01:56 +05:30
ruthra kumar
bcad6cb757 Merge pull request #45762 from ruthra-kumar/sync_received_and_paid_if_unset
refactor: set received and paid amount based on each other, if unset
2025-02-10 10:36:43 +05:30
ruthra kumar
95f6b586ff Merge pull request #45793 from asmitahase/employee-image
fix: unable to remove image from employee
2025-02-10 10:32:12 +05:30
ruthra kumar
c636cc33b3 refactor: remove paid_to_account_balance 2025-02-10 10:16:19 +05:30
ruthra kumar
9b5c4a0144 refactor: remove paid_from_account_balance 2025-02-10 10:16:04 +05:30
ruthra kumar
1bb6cd33a3 refactor: remove party_balance 2025-02-10 10:15:39 +05:30
rohitwaghchaure
4178154b19 Merge pull request #45810 from rohitwaghchaure/fixed-support-31257
fix: not able to select the item in the sales invoice
2025-02-10 10:08:50 +05:30
Rohit Waghchaure
35388e7a04 fix: not able to select the item in the sales invoice 2025-02-10 09:27:36 +05:30
Frappe PR Bot
91f6c65c0a fix: Esperanto translations 2025-02-10 03:17:28 +05:30
Frappe PR Bot
7137331355 fix: German translations 2025-02-10 03:17:25 +05:30
Frappe PR Bot
5e2879e9ea fix: Bosnian translations 2025-02-10 03:17:22 +05:30
Frappe PR Bot
06a93ffc80 fix: Persian translations 2025-02-10 03:17:19 +05:30
Frappe PR Bot
862ca7ddd3 fix: Chinese Simplified translations 2025-02-10 03:17:16 +05:30
Frappe PR Bot
e4530232e4 fix: Turkish translations 2025-02-10 03:17:12 +05:30
Frappe PR Bot
ed7ad79c2c fix: Swedish translations 2025-02-10 03:17:09 +05:30
Frappe PR Bot
ec9af4ae29 fix: Russian translations 2025-02-10 03:17:06 +05:30
Frappe PR Bot
5c002df014 fix: Polish translations 2025-02-10 03:17:03 +05:30
Frappe PR Bot
814be2b80a fix: Hungarian translations 2025-02-10 03:17:00 +05:30
Frappe PR Bot
b0bb3ca798 fix: Arabic translations 2025-02-10 03:16:57 +05:30
Frappe PR Bot
7e752756cf fix: Spanish translations 2025-02-10 03:16:54 +05:30
Frappe PR Bot
613c2a0379 fix: French translations 2025-02-10 03:16:50 +05:30
Frappe PR Bot
e2b586d5a3 fix: sync translations from crowdin (#45798)
* fix: Swedish translations

* fix: Bosnian translations

* fix: Swedish translations

* fix: Persian translations

* fix: Bosnian translations
2025-02-09 13:47:15 +01:00
Frappe PR Bot
b0d197119f chore: update POT file (#45805) 2025-02-09 11:20:14 +01:00
venkat102
8785342fce fix(report): add options to multiselectlist fields 2025-02-08 22:55:20 +05:30
ljain112
0809e00455 fix: do not validate party against Receivable and Payable account for cancelled gl entries 2025-02-07 18:30:26 +05:30
ljain112
6077c248b0 fix: correct amount in tansaction currency for reverse gl entries 2025-02-07 17:48:45 +05:30
Asmita Hase
0207d2d7b6 fix: unable to remove image from employee
fix: employee image disappears when newly created user_id is linked to employee
2025-02-07 17:27:44 +05:30
ruthra kumar
7b955b2ea6 Merge pull request #45725 from karm1000/set_max_date
fix: set max_date range for date of birth to today in employee
2025-02-07 16:15:10 +05:30
barredterra
772776ad8a fix: skip warning for free items 2025-02-07 11:43:25 +01:00
ruthra kumar
0df18daf10 Merge pull request #45644 from aerele/update-party-balance
fix: add allow_on_submit for party_balance, paid_from_account_balance and paid_to_account_balance
2025-02-07 16:10:17 +05:30
ruthra kumar
8f3cc6af16 Merge pull request #45640 from aerele/repost-accounting-ledger-payment-entry
feat: add repost accounting ledger entry for payment entry
2025-02-07 16:09:42 +05:30
harshpwctech
88e68bb803 Bug fix in email_campaign's update_status function. (#45679)
During the scheduler event of set_email_campaign_status, the function calling update_status isn't saving the modified status field.
2025-02-07 13:13:19 +05:30
ruthra kumar
b80b5574d3 Merge pull request #45639 from ruthra-kumar/incorrect_tds_on_0_rate_ldc
fix: '0' rate LDC's Invoice net totals should be ignored
2025-02-07 13:12:53 +05:30
Sanket322
2d32ddacc3 fix: add total row in non_grouped_invoices 2025-02-07 12:37:33 +05:30
ruthra kumar
0cdd346f8f test: ldc @ 0 rate 2025-02-07 12:18:01 +05:30
Frappe PR Bot
3d5b52f3bf fix: sync translations from crowdin (#45776)
* fix: Swedish translations

* fix: Bosnian translations
2025-02-07 00:17:18 +01:00
rohitwaghchaure
c83398471c Merge pull request #45767 from rohitwaghchaure/fixed-support-30947
fix: the project document timed out while opening
2025-02-06 22:07:22 +05:30
DaizyModi
820b32eb8a fix: Attibute error selling_price_list 2025-02-06 21:54:57 +05:30
ljain112
fc8663421b fix: Party name in Supplier Portal for Purchase Order 2025-02-06 18:37:22 +05:30
Rohit Waghchaure
33d03b1542 fix: the project document timed out while opening 2025-02-06 16:04:51 +05:30
rohitwaghchaure
fd8c78628f Merge pull request #45763 from rohitwaghchaure/fixed-support-30415
fix: stock reservation not working for sales invoice with update stock
2025-02-06 15:05:07 +05:30
Rohit Waghchaure
0c9d0ea1f4 fix: stock reservation not working for sales invoice with update stock 2025-02-06 14:46:19 +05:30
ruthra kumar
99e721e622 refactor: set paid amount based on received amount if unset 2025-02-06 14:15:24 +05:30
ruthra kumar
5ff540bd82 refactor: set received amount based on paid amount 2025-02-06 14:00:48 +05:30
Sugesh393
7d47869f4b fix: add accounting dimensions section in sales order item 2025-02-06 13:31:10 +05:30
Sugesh393
f8472c32d9 test: add unit test to validate payment request grand_total for partly paid invoice 2025-02-06 11:59:29 +05:30
ruthra kumar
325c4e3536 fix: '0' rate LDC's Invoice net totals should be ignored 2025-02-06 11:05:04 +05:30
Frappe PR Bot
52c687ecc9 fix: sync translations from crowdin (#45756)
* fix: Swedish translations

* fix: Turkish translations

* fix: Bosnian translations
2025-02-05 23:32:06 +01:00
Mihir Kandoi
ac3259b8f1 test: added test 2025-02-05 21:34:19 +05:30
Mihir Kandoi
366ae85d85 fix: tests 2025-02-05 19:18:01 +05:30
Mihir Kandoi
19c01b1457 feat: added option to enforce free item qty in pricing rule 2025-02-05 18:48:52 +05:30
Sanket322
133e0417b8 fix: handle response when json is None 2025-02-05 17:41:07 +05:30
HenningWendtland
d0479036bb fix: map project from rfq to supplier quotation 2025-02-05 12:11:13 +01:00
rohitwaghchaure
54a8d41f88 Merge pull request #45739 from mihir-kandoi/st30984
fix: create job card with wip warehouse set to source warehouse if material transfer to wip warehouse is skipped in work order
2025-02-05 16:39:11 +05:30
rohitwaghchaure
e72687d3eb Merge pull request #45741 from rohitwaghchaure/fixed-removed-unused-field
fix: removed unused field
2025-02-05 16:38:45 +05:30
ruthra kumar
fb7bba8cd0 Merge pull request #45604 from aerele/item_tax_template
fix: filter the item tax template using the input text
2025-02-05 16:30:07 +05:30
rohitwaghchaure
ab486d2515 Merge pull request #45734 from mihir-kandoi/st31003
fix: added correct options for incoming_rate field of delivery note item
2025-02-05 16:16:42 +05:30
Rohit Waghchaure
2d7a576da5 fix: removed unused field 2025-02-05 16:11:44 +05:30
rohitwaghchaure
6a2f2ae3fe Merge pull request #45692 from mihir-kandoi/st30672
fix: fetch rate from item price list when document is saved
2025-02-05 15:52:37 +05:30
Mihir Kandoi
723e902470 fix: create job card with wip warehouse set to source warehouse if material transfer to wip warehouse is skipped in work order 2025-02-05 15:48:08 +05:30
Khushi Rawat
f6fca3acec Merge pull request #45735 from khushi8112/asset-value-adjustment-cancellation-issue
fix: set asset value correctly after cancelling value adjustment
2025-02-05 15:25:47 +05:30
ruthra kumar
218670a720 Merge pull request #45717 from iamejaaz/30567-purchase-invoice-duplicate
fix(Purchase Invoice): default payment terms template selected while duplicating
2025-02-05 15:16:57 +05:30
Khushi Rawat
fee3846144 fix: set asset value correctly after cancelling value adjustment 2025-02-05 15:06:55 +05:30
Mihir Kandoi
417bf49a8d fix: added correct options for incoming_rate field of delivery note item 2025-02-05 14:55:51 +05:30
ruthra kumar
54279ee21d Merge pull request #45590 from aerele/tax-withholding-category
fix: remove tds account in taxes table on change of Tax Withholding C…
2025-02-05 14:08:29 +05:30
ruthra kumar
98e727a061 Merge pull request #45447 from aerele/pricing-rule-pos-qty
fix(pos): add item in the existing item row when discount is applied
2025-02-05 13:59:08 +05:30
ruthra kumar
79d4852d7d Merge pull request #45686 from aerele/process-statement-of-accounts
fix: allow multiple email ids
2025-02-05 13:48:57 +05:30
Mihir Kandoi
07adfadd58 test: added test 2025-02-05 13:12:25 +05:30
ruthra kumar
7f34b490f4 Merge pull request #45610 from ljain112/fix-pe-inv
fix: respect user set account if not advance account for getting outsanding invoices in payment entry
2025-02-05 12:09:16 +05:30
ruthra kumar
85378f9d1a chore: fix typo 2025-02-05 11:52:52 +05:30
Sugesh393
899c18df18 fix: validate payment request total of partly paid invoice 2025-02-05 11:00:55 +05:30
Frappe PR Bot
848b98e6d6 fix: sync translations from crowdin (#45720)
* fix: Swedish translations

* fix: Turkish translations

* fix: Chinese Simplified translations

* fix: Persian translations

* fix: Bosnian translations
2025-02-05 00:22:13 +01:00
rohitwaghchaure
b57a2612ce Merge pull request #45678 from mihir-kandoi/45572-2
fix: copy correct uom from delivery note when creating packing list
2025-02-05 00:35:19 +05:30
rohitwaghchaure
0edba914fa Merge pull request #45710 from mihir-kandoi/30355
fix: show only items with inspection enabled on create QI dialog
2025-02-05 00:33:39 +05:30
Ejaaz Khan
bfc01441a0 refactor: remove log 2025-02-05 00:09:16 +05:30
Ejaaz Khan
fb3f08a441 fix: payment schedule table is empty while duplicating record 2025-02-05 00:06:48 +05:30
Ejaaz Khan
18127603fe fix: default payment terms template selected while duplicating 2025-02-04 23:39:29 +05:30
Karm Soni
cd87ad0613 fix: set max_date range for date of birth to today in employee 2025-02-04 19:22:51 +05:30
Mihir Kandoi
ffd10d1fe9 fix: semgrep 2025-02-04 17:50:26 +05:30
Aayush Dalal
d1c927530e fix: handling company in bank reconciliation tool (#45582)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-02-04 11:44:01 +00:00
Mihir Kandoi
c92ec312b9 fix: show only items with inspection enabled on create QI dialog 2025-02-04 16:33:27 +05:30
rohitwaghchaure
3947b5943e Merge pull request #45701 from mihir-kandoi/st30429
fix: subcontracting validation precision issue
2025-02-04 15:23:03 +05:30
rohitwaghchaure
ab2d6fdefd Merge pull request #45698 from rohitwaghchaure/feat-report-incorrect-sabb
feat: report to find incorrect SABB
2025-02-04 15:15:41 +05:30
Diptanil Saha
a20116816e fix: pos payment cash shortcut decimal (#45702) 2025-02-04 15:08:37 +05:30
Rohit Waghchaure
7e24395e00 feat: report to find incorrect SABB 2025-02-04 13:47:55 +05:30
Mihir Kandoi
8720d412bd fix: subcontracting valiation precision issue 2025-02-04 13:21:09 +05:30
Diptanil Saha
51a65899ec fix: point of sale padding (#45697) 2025-02-04 13:09:27 +05:30
ljain112
a44be73a98 fix: do not allow "Finance Book" in Accounting Dimensions 2025-02-04 12:24:15 +05:30
Shariq Ansari
2482a3a205 Merge pull request #45694 from shariquerik/cannot-create-customer 2025-02-04 12:10:19 +05:30
Shariq Ansari
716edeb465 fix: only system manager was able to create customer & prospect 2025-02-04 11:54:05 +05:30
Mihir Kandoi
fee318a275 fix: logical error failing tests 2025-02-04 11:46:11 +05:30
rethik
f82837a4a2 fix: remove party type from validate 2025-02-04 11:07:41 +05:30
Sudharsanan11
9950e4aa0c fix: check billing address 2025-02-04 10:59:10 +05:30
Mihir Kandoi
1e4b9fbdf0 fix: fetch rate from item price list when document is saved 2025-02-04 10:54:57 +05:30
Frappe PR Bot
4c39dc5493 fix: sync translations from crowdin (#45691) 2025-02-04 01:35:52 +01:00
rohitwaghchaure
2394dd71e6 Merge pull request #45680 from rohitwaghchaure/fixed-sabb-query
fix: slow SABB query
2025-02-03 20:56:38 +05:30
rethik
9422ce5aee test: add unit test to validate account type and party type 2025-02-03 19:29:59 +05:30
rethik
2c8e3f3409 fix: add validate to allow equity account and party_type shareholder 2025-02-03 19:22:37 +05:30
Sudharsanan11
423decb93c fix: allow multiple email ids 2025-02-03 18:27:32 +05:30
ruthra kumar
daf9c9d34a Merge pull request #45247 from UmakanthKaspa/feature/update-item-name
feat: show item name alongside item code in the update items dialog
2025-02-03 16:53:21 +05:30
ruthra kumar
d762180231 refactor: reuse values from get_item_details 2025-02-03 16:45:12 +05:30
Rohit Waghchaure
81978a0bd8 fix: slow SABB query 2025-02-03 15:34:29 +05:30
UmakanthKaspa
7b6e8b9c29 feat: show item name alongside item code in the update items dialog 2025-02-03 15:31:16 +05:30
Mihir Kandoi
3cdaa80526 fix: copy correct uom from devliery note when creating packing list 2025-02-03 14:49:50 +05:30
ruthra kumar
adfbfe5b32 Merge pull request #45660 from frappe/pot_develop_2025-02-02
chore: update POT file
2025-02-03 14:31:41 +05:30
Ankush Menat
827afbfa2e fix: track employee changes (#45674)
closes https://github.com/frappe/erpnext/issues/45571
2025-02-03 08:51:50 +00:00
ruthra kumar
1fb3a4333d Merge pull request #45631 from deepeshgarg007/current_subscription_invoice
fix: Do not check for cancelled invoices
2025-02-03 14:11:13 +05:30
ruthra kumar
4b434d01f3 Merge pull request #45659 from frappe/mergify/bp/develop/pr-45617
fix: ignore expired batch for pick list (backport #45617)
2025-02-03 14:07:45 +05:30
ruthra kumar
cd0faf12a4 Merge pull request #45661 from frappe/l10n_develop
fix: sync translations from crowdin
2025-02-03 14:06:20 +05:30
Shariq Ansari
1362e2b6bf Merge pull request #45637 from shariquerik/notes-tab 2025-02-03 13:22:36 +05:30
Shariq Ansari
018df3135a fix: renamed Commments Tab to Notes tab in Lead doctype 2025-02-03 12:12:36 +05:30
rohitwaghchaure
0a25fe981b Merge pull request #45619 from mihir-kandoi/45442
feat: set bank account of company to default company bank account fro…
2025-02-03 12:00:35 +05:30
rohitwaghchaure
60da21be55 Merge pull request #45621 from mihir-kandoi/delivered-button
fix: delivered button of purchase order
2025-02-03 11:51:37 +05:30
rohitwaghchaure
3cdc636111 Merge pull request #45648 from mihir-kandoi/st30593
fix: consider process_loss_qty in work order
2025-02-03 11:50:31 +05:30
Frappe PR Bot
bd2c3711c0 fix: Bosnian translations 2025-02-03 03:17:38 +05:30
Frappe PR Bot
589325e14b fix: Persian translations 2025-02-03 03:17:35 +05:30
Frappe PR Bot
cd20d7aa8e fix: Chinese Simplified translations 2025-02-03 03:17:31 +05:30
frappe-pr-bot
99c3fb6ba5 chore: update POT file 2025-02-02 09:35:01 +00:00
Dany Robert
2a258c1629 fix: ignore expired batch for pick list
(cherry picked from commit 786db3d0fa)
2025-02-02 08:04:04 +00:00
Frappe PR Bot
4b345cf495 fix: sync translations from crowdin (#45656)
* fix: Swedish translations

* fix: Persian translations

* fix: Bosnian translations
2025-02-01 23:48:25 +01:00
Frappe PR Bot
33ce49730a fix: sync translations from crowdin (#45650) 2025-02-01 20:01:17 +01:00
Mihir Kandoi
95fda47b6c fix: consider process_loss_qty in work order 2025-02-01 00:35:12 +05:30
rohitwaghchaure
75567dc9ff Merge pull request #45646 from rohitwaghchaure/fixed-support-30611
fix: not able to make manufacturing entry for alternate items
2025-01-31 23:47:43 +05:30
Rohit Waghchaure
1607aa1a44 fix: not able to make manufacturing entry for alternate items 2025-01-31 23:28:54 +05:30
rohitwaghchaure
1a83316112 Merge pull request #45642 from rohitwaghchaure/fixed-support-30559
fix: actual qty showing blank for sub-assembly items
2025-01-31 22:38:04 +05:30
Sugesh393
707c01487e fix: add allow_on_submit for party_balance, paid_from_account_balance and paid_to_account_balance 2025-01-31 17:49:28 +05:30
Rohit Waghchaure
5be2e71a35 fix: actual qty showing blank for sub-assembly items 2025-01-31 16:49:55 +05:30
l0gesh29
5676d60ed3 feat: add repost accounting ledger entry for payment entry 2025-01-31 16:00:00 +05:30
rohitwaghchaure
3e35c48cf7 Merge pull request #45626 from rohitwaghchaure/fixed-support-29212-1
fix: validation to prevent submission, if the SABB is not linked to a stock transaction
2025-01-31 14:43:12 +05:30
Rohit Waghchaure
f976115a2b fix: validation to prevent submission if the SABB is not linked to a stock transaction 2025-01-31 14:04:27 +05:30
ruthra kumar
e2db3b9cfc Merge pull request #45615 from ljain112/fix-pe-erroe
fix: correct error message in payment entry
2025-01-31 12:56:14 +05:30
Deepesh Garg
2c94867b0e fix: Do not check for cancelled invoices 2025-01-31 12:17:53 +05:30
rohitwaghchaure
a913c9b202 Merge pull request #45629 from mihir-kandoi/st30495
fix: attribute 'msgbox' not found in sales invoice.js
2025-01-31 12:03:47 +05:30
Diptanil Saha
fe51535392 fix: pos print receipt on submit (#45632) 2025-01-31 12:00:00 +05:30
Deepesh Garg
701fc02050 fix: Do not check for cancelled invoices 2025-01-31 11:44:51 +05:30
Mihir Kandoi
5643385c22 fix: attribute 'msgbox' not found in sales invoice.js 2025-01-31 11:26:01 +05:30
Diptanil Saha
5a1851dfe3 fix: loading print receipt only at order complete (#45627) 2025-01-31 11:17:48 +05:30
ruthra kumar
437444fe04 Merge pull request #45623 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-31 10:54:40 +05:30
Frappe PR Bot
00f9a36980 fix: Swedish translations 2025-01-31 03:11:13 +05:30
Mihir Kandoi
41649cf52d fix: bind this to function 2025-01-30 22:53:00 +05:30
ljain112
592704cfd0 fix: correct error message in payment entry 2025-01-30 17:27:44 +05:30
rohitwaghchaure
b3ffb82586 Merge pull request #45612 from rohitwaghchaure/fixed-posting-date
fix: posting_date to posting_datetime in stock related queries
2025-01-30 17:05:26 +05:30
Rohit Waghchaure
e61ab48145 fix: posting_date to posting_datetime in stock related queries 2025-01-30 16:04:06 +05:30
rohitwaghchaure
b8ee15269c Merge pull request #45609 from rohitwaghchaure/fixed-support-30336
fix: reposting issue with s3 backup
2025-01-30 15:58:14 +05:30
Mihir Kandoi
ce7702cc19 feat: set bank account of company to default company bank account from masters 2025-01-30 12:50:01 +05:30
ljain112
9faf78d3e5 fix: respect user set account if not advance account for getting outstanding invoices in payment entry 2025-01-30 12:32:14 +05:30
Rohit Waghchaure
6b454ca9a7 fix: reposting issue with s3 backup 2025-01-30 11:59:40 +05:30
Frappe PR Bot
9a34c4c1ec fix: sync translations from crowdin (#45608)
* fix: Turkish translations

* fix: Persian translations
2025-01-30 11:20:01 +05:30
Bhavan23
4dd37ba033 fix: filter the item tax template using the input text 2025-01-29 22:19:30 +05:30
rohitwaghchaure
968e235a3f Merge pull request #45486 from rohitwaghchaure/fixed-SABB-performance-issue
perf: stock entry with batch
2025-01-29 20:49:09 +05:30
rohitwaghchaure
90eefac6f6 Merge pull request #45600 from rohitwaghchaure/fixed-validation-msg
fix: validation message
2025-01-29 20:41:39 +05:30
Rohit Waghchaure
4c8dff942d fix: validation message 2025-01-29 20:36:58 +05:30
rohitwaghchaure
378afd2f65 Merge pull request #45596 from frappe/mergify/bp/develop/pr-45595
fix: do not allow to manually submit the SABB (backport #45595)
2025-01-29 16:44:12 +05:30
Sanket Shah
aaf720ab61 fix: Gross Profit Report with Correct Totals and Gross Margin (#45548)
Co-authored-by: Sanket322 <shahsanket322003.com>
2025-01-29 16:42:51 +05:30
Rohit Waghchaure
d042c841e4 fix: do not allow to manually submit the SABB
(cherry picked from commit 2b16eb5381)
2025-01-29 11:08:59 +00:00
ruthra kumar
409e512d47 Merge pull request #45569 from ljain112/fix-vch-outstanding
fix: update voucher outstanding from payment ledger
2025-01-29 16:11:02 +05:30
Safvan Huzain
3f2e93dcb6 fix(query): remove duplicate docstatus condition (#45586)
fix: remove duplicate docstatus condition in query
2025-01-29 10:27:01 +00:00
l0gesh29
79b5a3e1dd fix: remove tds account in taxes table on change of Tax Withholding Category 2025-01-29 15:37:38 +05:30
ruthra kumar
72b940e3d3 Merge pull request #45441 from ljain112/fix-tax-withhel-details
fix: show payment entries in tax withheld vouchers
2025-01-29 15:35:50 +05:30
ruthra kumar
9ae8e94e6c Merge pull request #45585 from ruthra-kumar/auto_add_taxes
refactor: auto add taxes from template
2025-01-29 15:28:12 +05:30
ruthra kumar
d1086722bf refactor: auto add taxes from template 2025-01-29 14:38:50 +05:30
Sugesh G
d748b491ee fix: use currency from opportunity while creating quotation (#45540) 2025-01-29 12:35:45 +05:30
rohitwaghchaure
5e8e7dd3d8 Merge pull request #45536 from rtdany10/precision-return
fix: return qty error due to precision
2025-01-29 12:19:54 +05:30
Ejaaz Khan
5a023dc8d4 fix: add multiple item issue in stock entry (#45544) 2025-01-29 12:19:01 +05:30
Lakshit Jain
9f20854bd9 fix: get stock balance filtered by company for validating stock value in jv (#45549)
* fix: get stock balance filtered by company for validating stock value in jv

* test: error is raised  on validate
2025-01-29 12:16:11 +05:30
ruthra kumar
a64a4f9b20 Merge pull request #45575 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-29 11:25:43 +05:30
Frappe PR Bot
ac32c554af fix: Turkish translations 2025-01-29 03:14:46 +05:30
Frappe PR Bot
ceb4f249cb fix: Swedish translations 2025-01-29 03:14:43 +05:30
rohitwaghchaure
2609f9809d Merge pull request #43270 from rohitwaghchaure/feat-stock-reservation-for-wo
feat: stock reservation for Work Order
2025-01-28 18:06:57 +05:30
ljain112
dd77070351 fix: update voucher outstanding from payment ledger 2025-01-28 17:54:16 +05:30
Rohit Waghchaure
4d050441b3 feat: stock reservation for Work Order 2025-01-28 16:42:57 +05:30
Akhil Narang
8e77b26641 Merge pull request #45554 from akhilnarang/fixup-44604
fix(book_appointment): stop trying to use pytz api with zoneinfo
2025-01-28 16:25:27 +05:30
Akhil Narang
b08da0f6bd fix(book_appointment): stop trying to use pytz api with zoneinfo
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2025-01-28 16:09:26 +05:30
ruthra kumar
b1eb604363 Merge pull request #45560 from ruthra-kumar/rename_swiss_coa
chore: rename file to standard name format
2025-01-28 16:03:19 +05:30
ruthra kumar
7bc075376b chore: rename file to standard name format 2025-01-28 14:34:49 +05:30
ruthra kumar
7e7209e448 Merge pull request #45452 from aerele/payment-entry-transaction-currency
fix(payment entry): get amount in transaction currency
2025-01-28 14:33:30 +05:30
ruthra kumar
9964ddc0e9 Merge pull request #45551 from eagleautomate/swiss_coa
feat: Add chart of accounts for Switzerland
2025-01-28 11:33:57 +05:30
Sanket Shah
9933d3c8ff fix: update fields on change of item code In Update Items of Sales Order (#45125)
* fix: update fields on change of item code

* fix: minor update

* fix: set the new values always

* Revert "fix: set the new values always"

This reverts commit 44daa0a641.

---------

Co-authored-by: Sanket322 <shahsanket322003.com>
Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2025-01-28 11:27:28 +05:30
ruthra kumar
813cfdfff6 Merge pull request #45552 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-28 11:03:49 +05:30
Rohit Waghchaure
0b1b964b77 perf: stock entry with batch 2025-01-28 09:49:37 +05:30
Frappe PR Bot
d1fbeb11cb fix: Turkish translations 2025-01-28 03:03:54 +05:30
Frappe PR Bot
dc7e7118af fix: Swedish translations 2025-01-28 03:03:50 +05:30
Frappe PR Bot
26afba142e fix: French translations 2025-01-28 03:03:33 +05:30
eagleautomate
2c644ec2ef feat: Add chart of accounts for Switzerland
240812 Schulkontenrahmen VEB - DE
2025-01-27 19:29:36 +05:30
ruthra kumar
47c2c5377c Merge pull request #45345 from Sanket322/set_discount_properly
fix:  maintain existing discounts in get_pricing_rule_for_item
2025-01-27 16:01:46 +05:30
Dany Robert
3078578692 fix: return qty error due to precision 2025-01-27 09:54:06 +00:00
ruthra kumar
49570a5544 Merge pull request #45302 from aerele/validate-dimensions-company
feat: add company level validation for accounting dimension
2025-01-27 14:53:49 +05:30
meera-greycube
e88f96b92d feat : company field required for multi company setup (#45415)
* Update vehicle.json

feat : company field required for multi company setup

* Update vehicle.json

allow_rename fixed in vehicle.json

* fix: fix permission issue
2025-01-27 14:28:11 +05:30
ruthra kumar
e55d4030ec Merge pull request #45284 from aerele/pos-return-currency
fix: set party_account_currency for pos_invoice returns
2025-01-27 14:27:41 +05:30
ljain112
db38e7bf5a fix: correct amt in account currency for lcv with manually distributed charges. 2025-01-27 14:22:36 +05:30
Raffael Meyer
11f65f20a0 feat(Sales Invoice): allow linking to project without adding timesheets (#44295)
* feat(Sales Invoice): allow linking to project without adding timesheets

* test: add timesheet data
2025-01-27 13:20:57 +05:30
Diptanil Saha
2ac8c92e7f fix: currency decimal on POS Past Order List (#45524)
* fix: currency decimal on POS

* fix: removed precision
2025-01-27 13:02:24 +05:30
ruthra kumar
fb285749dd Merge pull request #45300 from HarryPaulo/fix-prevent-commit
fix: prevent unnecessary db.commit for contact insert
2025-01-27 12:18:07 +05:30
Frappe PR Bot
887645e55f fix: sync translations from crowdin (#45522)
* fix: French translations

* fix: Spanish translations

* fix: Arabic translations

* fix: Hungarian translations

* fix: Polish translations

* fix: Russian translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Chinese Simplified translations

* fix: Persian translations

* fix: Bosnian translations

* fix: German translations

* fix: Esperanto translations
2025-01-26 23:19:32 +01:00
venkat102
af97f42429 fix(payment entry): get amount in transaction currency 2025-01-26 19:52:06 +05:30
Frappe PR Bot
eabdd5992b chore: update POT file (#45451) 2025-01-26 13:54:13 +01:00
Frappe PR Bot
29341245b8 fix: sync translations from crowdin (#45444)
* fix: Swedish translations

* fix: Turkish translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Persian translations
2025-01-26 12:15:18 +05:30
rohitwaghchaure
b5afd901f3 Merge pull request #45443 from rohitwaghchaure/fixed-support-29487
fix: allow to fix negative stock for batch using stock reco
2025-01-25 15:03:22 +05:30
Rohit Waghchaure
2e8cde3378 fix: allow to fix negative stock for batch using stock reco 2025-01-25 14:44:25 +05:30
ljain112
d97e78e5d3 fix: variable names 2025-01-25 13:16:06 +05:30
ljain112
55733d4f18 fix: show payment entries in Tax Withheld Vouchers 2025-01-25 13:04:12 +05:30
venkat102
bee2c04d0b fix(pos): add item in the existing item row when discount is applied 2025-01-25 12:59:04 +05:30
rohitwaghchaure
53704b98b5 fix: do not check budget during reposting (#45432) 2025-01-24 12:00:45 +00:00
rohitwaghchaure
bad1ac9fbc Merge pull request #45423 from rohitwaghchaure/fixed-support-29882
fix: precision issue in stock entry
2025-01-24 17:07:16 +05:30
Raffael Meyer
4008ca5ddd feat(UX): scroll to required field (#44367) 2025-01-24 16:36:46 +05:30
Rohit Waghchaure
9f3b8520fe fix: precision issue in stock entry 2025-01-24 16:07:25 +05:30
Sanket Shah
d862e9b771 fix: validate items against selling settings (#45288)
fix: validate_for_duplicate_items

Co-authored-by: Sanket322 <shahsanket322003.com>
2025-01-24 15:10:43 +05:30
Venkatesh
97acbb3134 fix: disable load_after_mapping when purchase order created from sales order (#45405) 2025-01-24 15:02:56 +05:30
Raffael Meyer
a9bc395e98 fix: secure bulk transaction (#45386) 2025-01-24 14:44:26 +05:30
Tufan Kaynak
42edb9f5b1 fix(material request): mapping Sales Order Item Delivery Date to Mate… (#45227)
* fix(material request): mapping Sales Order Item Delivery Date to Material Request Item Required By

as mentioned in https://discuss.frappe.io/t/item-delivery-date-on-sales-order-is-not-transferred-to-material-request-item-required-by-date/140479 
fixing
When you create a Material Request directly on the Sales Order via → Create → Material Request, Delivery Date on Sales Order Item is not transferred to Material Request Item Required By date.

* fix(linters): meaningless linters formatting message applied

In order to pass the linters test which I find meaningless as it asks for the comma after the last item in a dictionary data type

* fix(linters): formatting code for linters pass

Linters formatting applied
2025-01-24 14:20:20 +05:30
Martin Luessi
e82911041d fix: remove unnecessary auth from plaid connector (#44305) 2025-01-24 13:11:32 +05:30
rohitwaghchaure
3d7f1026ca Merge pull request #45335 from rohitwaghchaure/fixed-valuation-for-batch
fix: valuation for batch
2025-01-24 12:50:55 +05:30
Diptanil Saha
54d234e05d fix: resolved pos return setting to default mode of payment instead of user selection (#45377)
* fix: resolved pos return setting to default mode of payment instead of user selection

* refactor: removed console log statement

* refactor: moved get_payment_data to sales_and_purchase_return.py
2025-01-24 12:41:01 +05:30
Diptanil Saha
78c7c1c631 feat: full screen on pos (#45404)
* feat: full screen on pos

* refactor: variables for label

* fix: refactor and handled button label change

* refactor: rename enable fullscreen label
2025-01-24 07:07:36 +00:00
Rohit Waghchaure
8028dd2683 fix: version 2025-01-24 12:32:16 +05:30
mahsem
cd3f03696e fix: use frappe.datetime.str_to_user (#45216)
* fix: default_datetime_format

* fix: add_format_datetime

* fix: update to str_to_user  in point_of_sale/pos_controller.js

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>

* fix: convert_to_str_to_user

* fix: linters

* fix: whitespace

---------

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-01-24 12:16:47 +05:30
Sugesh G
6ec18fb40d fix: set expense_account and cost_center based on company in stock entry (#45159)
* fix: set expense_account and cost_center based on company in stock entry

* fix: remove is_perpetual_inventory_enabled validation for cost_center
2025-01-24 12:13:44 +05:30
ruthra kumar
5bf90dccbb Merge pull request #45412 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-24 11:05:12 +05:30
Frappe PR Bot
9888c62e13 fix: Swedish translations 2025-01-24 02:26:17 +05:30
Rohit Waghchaure
5088d8576f fix: valuation for batch 2025-01-23 20:38:14 +05:30
Raffael Meyer
d92f9330fa fix: get default stock uom (#45384)
Co-authored-by: Sagar Vora <sagar@resilient.tech>
2025-01-23 14:32:39 +01:00
mergify[bot]
d1329c2910 fix: add condition to check if item is delivered by supplier in make_purchase_order_for_default_supplier() (backport #45370) (#45409)
fix: add condition to check if item is delivered by supplier in make_purchase_order_for_default_supplier() (#45370)

(cherry picked from commit 69464ab7ff)

Co-authored-by: Shanuka Hewage <89955436+Shanuka-98@users.noreply.github.com>
2025-01-23 18:18:58 +05:30
meike289
1758e125e0 fix: fix creating documents from sales invoice (#45346)
Co-authored-by: Meike Nedwidek <nedwidek@kk-software.de>
2025-01-23 17:54:00 +05:30
ruthra kumar
85b6fdd067 Merge pull request #45248 from niyazrazak/patch-22
chore: consider currency precision in bank clearance
2025-01-23 16:57:28 +05:30
ruthra kumar
c889bdba0f chore: import statements and linter 2025-01-23 16:39:03 +05:30
ruthra kumar
766b5fa5ed Merge pull request #44790 from ruthra-kumar/configurable_posting_date_for_exc_gain_loss
refactor: configurable posting date for Exc Gain / Loss journal
2025-01-23 16:28:21 +05:30
ruthra kumar
3923b784e3 Merge pull request #45129 from marination/ac-match-simplify
fix: Wrong `bank_ac_no` filter + simplify logic in automatch
2025-01-23 16:27:49 +05:30
ruthra kumar
7b8a099d95 Merge pull request #44950 from mahsem/postal_code_move_and_fixes
fix: postal_code_move_and_fixes
2025-01-23 16:17:15 +05:30
ruthra kumar
a71718883e refactor: support JE posting date in semi-auto reconciilation tool 2025-01-23 16:11:35 +05:30
ruthra kumar
2f3281579a test: exc gain/loss posting date based on configuration 2025-01-23 14:44:40 +05:30
ruthra kumar
b2c3da135e refactor: only apply configuration on normal payments
patch to update default value
2025-01-23 14:12:24 +05:30
ruthra kumar
95af63e305 refactor: allow reconciliation date for exchange gain / loss 2025-01-23 13:48:09 +05:30
rohitwaghchaure
f79eea2261 Merge pull request #45394 from rohitwaghchaure/fixed-support-30031
fix: JobCardTimeLog' object has no attribute 'remaining_time_in_mins'
2025-01-23 13:22:17 +05:30
ruthra kumar
5257413a93 refactor: configurable posting date for Exc Gain / Loss journal 2025-01-23 13:06:30 +05:30
Rohit Waghchaure
41dda35db7 fix: JobCardTimeLog' object has no attribute 'remaining_time_in_mins' 2025-01-23 13:03:37 +05:30
Sanket322
50223c6bec fix: remove applied pricing rule 2025-01-23 11:55:12 +05:30
Sanket Shah
2a400dd3f8 perf: optimize DB calls with frappe.get_all (#45289)
* perf: reduce multiple db queries

* fix: use frappe._dict instread of extra iteration

---------

Co-authored-by: Sanket322 <shahsanket322003.com>
2025-01-23 11:29:41 +05:30
Frappe PR Bot
551fa500e8 fix: sync translations from crowdin (#45387)
* fix: Swedish translations

* fix: Turkish translations
2025-01-23 11:18:59 +05:30
Mihir Kandoi
fe43d20545 fix: added item_group filter in item_code field in stock balance report (#45340)
* fix: added item_group filter in item_code field in stock balance report

* feat: added filter to not show non stock items
2025-01-23 11:17:35 +05:30
rohitwaghchaure
8e18c572f4 Merge pull request #45367 from rohitwaghchaure/fixed-incorrect-calculation-of-qty
fix: batch qty calculation
2025-01-23 09:40:16 +05:30
Rohit Waghchaure
f07a71a882 fix: batch qty calculation 2025-01-22 21:06:43 +05:30
rohitwaghchaure
c5f21a5686 Merge pull request #45382 from rohitwaghchaure/fixed-support-29769
fix: precision issue causing incorrect status
2025-01-22 20:17:20 +05:30
Rohit Waghchaure
4a7586cc01 fix: precision issue causing incorrect status 2025-01-22 18:04:52 +05:30
ruthra kumar
3fbd2ca0d9 refactor: configurable posting date for Exc Gain / Loss journal 2025-01-22 17:54:00 +05:30
Diógenes Souza
b26f0b6633 fix: System was allowing to save payment schedule amount less than grand total (#45322)
* fix: System was allowing to save payment schedule amount less than grand_total

* style: After run pre-commit
2025-01-22 17:52:26 +05:30
Rethik M
05579959f2 fix: validate non-stock item for exchange loss/gain (#45306)
* fix: validate non-stock item

* test: add unit test to validate non-stock item exchange difference

* fix: use usd supplier
2025-01-22 17:44:53 +05:30
gavin
4481ca83ff fix: set preferred email in Employee via backend controller (#45320)
fix: set preferred email in Employee (backend)

Set "Preferred Email" for Employee via validate. Unset value when
prefered_contact_email is also unset.
2025-01-22 17:41:41 +05:30
Khushi Rawat
9ff3101b2d fix: added debounce to prevent multiple clicks (#45369)
* fix: added debounce to prevent multiple clicks

* fix: linters check
2025-01-22 17:26:38 +05:30
mergify[bot]
8b6a20d501 fix: precision on work order total qty (backport #45341) (#45361)
fix: precision on work order total qty (#45341)

* fix: precision on work order total qty

* chore: linters

(cherry picked from commit 53468202de)

Co-authored-by: Dany Robert <rtdany10@gmail.com>
2025-01-22 17:25:50 +05:30
Raffael Meyer
be2593bb51 refactor!: remove redundant title field from sales transactions (#45115)
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2025-01-22 11:35:41 +00:00
Ejaaz Khan
5207917993 feat: set default view as tree-view (#45365)
feat: set default view as treeview
2025-01-22 16:18:31 +05:30
Deepesh Garg
84d379914c Merge pull request #45371 from deepeshgarg007/closing_balance_patch_rerun
fix: Do no query GLs if no PCVs are posted
2025-01-22 14:02:23 +05:30
Deepesh Garg
f4d1a54588 fix: Do no query GLs if no PCVs are posted 2025-01-22 13:46:37 +05:30
ruthra kumar
1c6a7830c3 Merge pull request #45363 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-22 12:12:43 +05:30
Frappe PR Bot
4455312b73 fix: Turkish translations 2025-01-22 01:34:43 +05:30
Sugesh393
36bae55299 chore: update variable names for improved readability 2025-01-21 17:38:24 +05:30
Niklas Liechti
dedb96d337 refactor: return job_id to be able to react to it when job is finished. (#45111) 2025-01-21 17:38:12 +05:30
ruthra kumar
d73c17aa98 Merge pull request #45242 from aerele/pos-invoice-item
fix: include pos invoice in modifing key for returned item validation
2025-01-21 16:34:59 +05:30
ruthra kumar
4f55356c79 Merge pull request #45215 from aerele/handle_aed_exchange_rate_manually
fix: calculate AED exchange rate based on pegged value with USD
2025-01-21 13:58:21 +05:30
Deepesh Garg
993f40fa43 perf: Ignore is_opening column in GL Queries (#45327)
* perf: Ignore is_opening column in GL Queries

* chore: Remove unwanted changes

* chore: Remove unwanted changes

* chore: Remove unwanted changes

* chore: Remove unwanted changes

* chore: Remove unwanted changes

* chore: Remove unwanted changes
2025-01-21 13:45:25 +05:30
ruthra kumar
2e535955b3 refactor: use dictionary for better expandability 2025-01-21 12:15:26 +05:30
ruthra kumar
dd923332cb refactor: fix type error 2025-01-21 12:15:26 +05:30
Frappe PR Bot
7b0c21e989 fix: sync translations from crowdin (#45323)
* fix: Swedish translations

* fix: Turkish translations

* fix: French translations

* fix: Spanish translations

* fix: Arabic translations

* fix: Hungarian translations

* fix: Polish translations

* fix: Russian translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Chinese Simplified translations

* fix: Persian translations

* fix: Bosnian translations

* fix: German translations

* fix: Esperanto translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Persian translations
2025-01-20 22:57:21 +01:00
rohitwaghchaure
6c32397313 Merge pull request #45282 from mihir-kandoi/44976
feat: Add corrective job card operating cost as additional costs in s…
2025-01-20 22:48:46 +05:30
rohitwaghchaure
5638dac414 Merge pull request #45344 from iamejaaz/broken-bom-tree
fix: broken image issue in BOM Tree
2025-01-20 22:48:05 +05:30
Sanket322
e2a32b7257 fix: use user defined discount amount or default 2025-01-20 18:01:31 +05:30
Ejaaz Khan
7c6e279599 fix: broken image issue in BOM Tree 2025-01-20 17:49:18 +05:30
Diptanil Saha
68fb1b28eb fix: set invoice start date to subscription start date (#45342) 2025-01-20 17:06:02 +05:30
Mihir Kandoi
47f8a86003 fix: logical error in where condition of qb query 2025-01-20 12:41:28 +05:30
ruthra kumar
5fb158a6f7 Merge pull request #45202 from DaizyModi/fix-party-bank-acc-in-pe
fix: Correct Party Bank Account mapping in `Payment Entry` from Transactional Doctypes
2025-01-20 12:22:10 +05:30
ruthra kumar
30e87c37dc Merge pull request #45334 from mahsem/translation_fixes
fix: translation fixes
2025-01-20 12:11:32 +05:30
ruthra kumar
f9200a9575 Merge pull request #45167 from aerele/validate-sales-person
fix: validate linked sales person
2025-01-20 11:49:14 +05:30
mahsem
3697ba0772 fix: linters 2025-01-19 21:00:02 +01:00
mahsem
1d81a9f933 fix: translation fixes 2025-01-19 20:52:58 +01:00
Frappe PR Bot
da34d7923d chore: update POT file (#45331) 2025-01-19 11:47:50 +01:00
rohitwaghchaure
04364d680f Merge pull request #44783 from rohitwaghchaure/fixed-support-27273
fix: do not reset picked items
2025-01-18 14:22:54 +05:30
Rohit Waghchaure
34a80bfcd3 fix: do not reset picked items 2025-01-18 12:44:30 +05:30
rohitwaghchaure
76ba17808b Merge pull request #45298 from rohitwaghchaure/fixed-qi-company
fix: company in quality inspection
2025-01-18 12:14:54 +05:30
Rohit Waghchaure
397cd79e1e fix: company in quality inspection 2025-01-18 11:09:00 +05:30
Diptanil Saha
97e3770872 fix: fixed typo in manufacturing settings and field rename (#45238)
* chore: field rename and patch entry

* chore: patch file rename and description improvement

---------

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2025-01-17 11:54:39 +00:00
ruthra kumar
8f9b5aaae7 Merge pull request #44811 from sagarvora/fix-pcv-patch-99
fix!: ensure multiple PCVs in same fiscal year are considered in patch
2025-01-17 17:00:40 +05:30
Diptanil Saha
d13c03676b chore: quickbooks migrator integration removal (#45240) 2025-01-17 16:53:36 +05:30
Diptanil Saha
98d401bee4 fix: fetching items from blanket order to sales/purchase order (#45262)
* fix: blanket order with zero item quantity

* fix: item quantity validation

* refactor: resolve linter issue
2025-01-17 16:53:06 +05:30
Nabin Hait
ec487c14d9 fix: Ambiguous column error while creating Sales Return (#45275) 2025-01-17 16:51:07 +05:30
Nabin Hait
2d45d0e5d5 fix: updated modified timestamp for stock entry type (#45280) 2025-01-17 16:50:43 +05:30
Lakshit Jain
ada272a29b fix: round off tax withholding amount (#45271) 2025-01-17 16:50:15 +05:30
Patrick Eißler
8d66142865 fix(Project): re-phrase welcome email (#45175) 2025-01-17 12:17:32 +01:00
Sagar Vora
84e0b41c4f fix: ensure multiple PCVs in same fiscal year are considered in patch 2025-01-17 16:44:06 +05:30
Sanket Shah
19c8708e5e fix: don't update party-type on change of cost center in Journal Entry (#45291)
fix: don't update party-type on change of cost center

Co-authored-by: Sanket322 <shahsanket322003.com>
2025-01-17 16:42:04 +05:30
Ejaaz Khan
aa38895caf feat: add option to update modified on communication recieved (#45307) 2025-01-17 16:40:35 +05:30
rohitwaghchaure
9163f60191 fix: sales return for multi-uom (#45303) 2025-01-17 16:35:59 +05:30
Sugesh393
454067198e fix: set company related values 2025-01-17 11:46:17 +05:30
Sugesh393
c94091d68f test: add new unit test for company validation in accounting dimension 2025-01-17 11:45:51 +05:30
Sugesh393
60efd3e219 feat: add company level validation for accounting dimension 2025-01-17 11:41:52 +05:30
Frappe PR Bot
0e7e9b5f0a fix: sync translations from crowdin (#45299)
* fix: Turkish translations

* fix: Persian translations
2025-01-16 22:49:23 +01:00
HarryPaulo
87de5c7450 fix: prevent unnecessary db.commit for contact insert [Linters] 2025-01-16 17:51:22 -03:00
HarryPaulo
5f15b0b65b fix: prevent unnecessary db.commit 2025-01-16 17:40:54 -03:00
Mihir Kandoi
063a205e5a refactor: added condition which checks for corrective operation setting 2025-01-16 20:55:27 +05:30
rohitwaghchaure
43ce185429 Merge pull request #45283 from rohitwaghchaure/fixed-github-45219
fix: Does not allow to create Sub-Asseblies of Sub Assemblies
2025-01-16 14:57:56 +05:30
Rohit Waghchaure
318a945d66 fix: Does not allow to create Sub-Asseblies of Sub Assemblies 2025-01-16 13:51:11 +05:30
ruthra kumar
6628d290de Merge pull request #45285 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-16 11:10:32 +05:30
Mihir Kandoi
4fb48b7f22 test: Added test for new feature 2025-01-16 10:08:47 +05:30
Frappe PR Bot
ed2764ab8d fix: Persian translations 2025-01-15 23:49:21 +05:30
Frappe PR Bot
a7cd17ac8b fix: Turkish translations 2025-01-15 23:49:14 +05:30
Sugesh393
484ecf2479 test: add new unit test to check payments amount of pos_invoice returns 2025-01-15 18:27:57 +05:30
Sugesh393
2af6fca7fa fix: set party_account_currency for pos_invoice returns 2025-01-15 18:20:20 +05:30
Mihir Kandoi
2bf10f68a8 feat: Add corrective job card operating cost as additional costs in stock entry 2025-01-15 18:14:19 +05:30
rohitwaghchaure
cb91e8e69e Merge pull request #45278 from rohitwaghchaure/fixed-github-45246
fix: status of the serial no for the raw materials
2025-01-15 18:13:34 +05:30
Rohit Waghchaure
9607b16dcf fix: status of the serial no for the raw materials 2025-01-15 17:53:11 +05:30
Lakshit Jain
37a5767be5 fix: check if tds deducted based on Purchase Taxes and Charges (#45161) 2025-01-15 15:31:56 +05:30
rohitwaghchaure
195254756f Merge pull request #45270 from mihir-kandoi/st29053
fix: Skip WIP Warehouse transfer
2025-01-15 15:05:49 +05:30
Lakshit Jain
a4453fb77b fix: use currency defined in plan for subscription invoice (#45104) 2025-01-15 14:52:25 +05:30
Mihir Kandoi
6edb454eea test: Added new test to check wip skip 2025-01-15 13:49:11 +05:30
rohitwaghchaure
001d1eb3f9 Merge pull request #45259 from rohitwaghchaure/fixed-support-29045
fix: incorrect valuation for sales return with different warhouse
2025-01-14 18:33:34 +05:30
Rohit Waghchaure
3a2e816759 fix: incorrect valuation for sales return with different warhouse 2025-01-14 18:11:17 +05:30
ruthra kumar
ce9c606f71 refactor: allow users to configure interval for Semi-Auto payment reconciliation (#45211)
* refactor: configurable interval for reconciliation trigger

* refactor: set default value for interval

* refactor: configurable queue size

* refactor: use patch to setup default cron job

* refactor: use 'after_migrate' to setup cron for reconciliation

User specified interval will be used

* chore: type casting

* refactor: use scheduler_event to persist cron

* chore: rename field

* chore: use configured queue size

* chore: remove unwanted field
2025-01-14 16:59:15 +05:30
Mihir Kandoi
09d26a835f fix: tests 2025-01-14 16:27:49 +05:30
ruthra kumar
aea69af4ff Merge pull request #45182 from ruthra-kumar/configurable_reconciliation_dates
refactor: configurable reconciliation dates for Advance Payments
2025-01-14 15:18:46 +05:30
ruthra kumar
fd442a36a9 Merge pull request #45260 from ruthra-kumar/incorrect_label
fix: incorrect label in Item-wise sales register
2025-01-14 13:55:20 +05:30
ruthra kumar
9ee5fcc602 refactor: only update reconcile_effect_on advance in separate acc 2025-01-14 13:52:21 +05:30
ruthra kumar
d9013e1054 fix: incorrect label in Item-wise sales register 2025-01-14 13:34:12 +05:30
rohitwaghchaure
9bb7d4e428 Merge pull request #45241 from rohitwaghchaure/fixed-support-28979
fix: auto fetch batch and serial no for draft stock transactions
2025-01-14 12:35:17 +05:30
mahsem
a3165c5719 fix: change string to be able to translate (#45090)
* fix: change_string_to_translate

* fix: debit note translation

* chore: update 'modified' field

---------

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2025-01-14 06:26:01 +00:00
ruthra kumar
601bc3026d Merge pull request #45249 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-14 11:17:27 +05:30
ruthra kumar
aeedaae761 Merge pull request #45078 from Sanket322/cancel_subscription
fix: don't create invoice if `current_invoice_start ` is in future
2025-01-14 10:12:33 +05:30
ruthra kumar
2e8723407f Merge pull request #45074 from Sanket322/set_shipping_address
fix: set billing and shipping address on change of company
2025-01-14 10:04:13 +05:30
ruthra kumar
4b483e176d Merge pull request #45001 from ljain112/fix-tds-excess
fix: deduct tds on excess amount if checked
2025-01-14 10:02:06 +05:30
ruthra kumar
f7a93640b0 Merge pull request #44798 from aerele/apply_pricing_rule
fix: update  discounting on mixed conditions
2025-01-14 09:58:03 +05:30
Frappe PR Bot
8f8cddb03c fix: Persian translations 2025-01-13 23:39:50 +05:30
Frappe PR Bot
ea4526ad30 fix: Turkish translations 2025-01-13 23:39:40 +05:30
Frappe PR Bot
6c5a9f5a74 fix: sync translations from crowdin (#45174) 2025-01-13 18:02:50 +01:00
Mihir Kandoi
bbb5f8056b fix: Skip WIP Warehouse transfer 2025-01-13 21:32:34 +05:30
NIYAZ RAZAK
83bb3926b1 chore: consider currency precision 2025-01-13 18:53:59 +03:00
ruthra kumar
9fa1865cb7 refactor: backwards compatibility 2025-01-13 17:17:18 +05:30
Rohit Waghchaure
88ab9be79c fix: auto fetch batch and serial no for draft stock transactions 2025-01-13 17:17:03 +05:30
venkat102
2936139c79 fix: include pos invoice in modifing key for returned item validation 2025-01-13 16:51:25 +05:30
ruthra kumar
a4271aa5d1 refactor: save reconcile effect on reference table 2025-01-13 16:20:58 +05:30
ruthra kumar
7e7775aa44 refactor: store reconciliation date in reference
Helps with reposting
2025-01-13 15:56:41 +05:30
Diptanil Saha
e529f82392 fix: batch number search on pos (#45209)
* fix: price of items with batch number not having seperate item price on pos search bar

* fix: introduced batch number based sorting
2025-01-13 12:06:46 +05:30
Ejaaz Khan
eea0eff001 fix: ui issues across multiple pages (#45224)
* fix: ui issues across multiple pages

* refactor: change cur_from to frm
2025-01-13 11:56:59 +05:30
Ejaaz Khan
6eb3b0b1c2 refactor: remove columns from list in child table (#45189) 2025-01-13 11:54:44 +05:30
Ejaaz Khan
53c282c86e refactor: remove party type from general ledger print format (#45196)
refactor: remove party type from print format
2025-01-13 11:52:45 +05:30
Frappe PR Bot
959434601d chore: update POT file (#45231) 2025-01-12 11:27:09 +01:00
rohitwaghchaure
c6c7d7832a Merge pull request #45207 from rohitwaghchaure/fixed-support-29140
fix: incorrect valuation rate for PI based revaluation
2025-01-11 10:07:54 +05:30
rohitwaghchaure
edb254e43e Merge pull request #45214 from rohitwaghchaure/fixed-support-29172
fix: delivery_document_no column issue
2025-01-11 10:07:26 +05:30
Kavin
455ef6f084 fix: calculate AED exchange rate based on pegged value with USD 2025-01-10 18:20:47 +05:30
Rohit Waghchaure
61efb2bb39 fix: delivery_document_no column issue 2025-01-10 18:19:48 +05:30
ruthra kumar
856ec08484 Merge pull request #45195 from sokumon/coa-ui
fix: coa actions cleanup
2025-01-10 16:08:19 +05:30
rohitwaghchaure
31005c5984 Merge pull request #45076 from frappe/valuation_in_ageing_report
feat: Added valuation of quantity for each age group in stock ageing …
2025-01-10 14:25:50 +05:30
Rohit Waghchaure
14ce2337df fix: incorrect valuation rate for PI based revaluation 2025-01-10 14:20:48 +05:30
ruthra kumar
e0517852bc test: ensure reconciliation date config takes effect 2025-01-10 12:17:13 +05:30
rohitwaghchaure
e4d3235b9c Merge pull request #45204 from frappe/mergify/bp/develop/pr-45197
fix: precision loss causing process loss variance (backport #45197)
2025-01-10 12:00:37 +05:30
rohitwaghchaure
5ccf4a1783 chore: fix conflicts 2025-01-10 11:25:53 +05:30
FATHIH MOHAMMED
1ef9f7f8fd fix: precision loss causing process loss variance
(cherry picked from commit d84601b2a3)

# Conflicts:
#	erpnext/stock/doctype/stock_entry/stock_entry.py
2025-01-10 05:49:59 +00:00
DaizyModi
376bdc75f4 fix: Correct Party Bank Account mapping in Payment Entry 2025-01-10 11:06:39 +05:30
ruthra kumar
c8e93e7a61 refactor: hide old checkbox 2025-01-09 20:41:29 +05:30
ruthra kumar
bb8d2c994c refactor: payment entry to handle posting date on configuation 2025-01-09 20:41:29 +05:30
ruthra kumar
fb6c72a247 refactor: test cases updated 2025-01-09 20:41:29 +05:30
ruthra kumar
a8a8ac71b6 refactor: patch to migrate checkbox to select 2025-01-09 20:41:27 +05:30
ruthra kumar
8b2c981fc3 refactor: introduce select fields in company and payment entry 2025-01-09 20:22:05 +05:30
sokumon
108a91d788 fix: coa actions cleanup 2025-01-09 16:49:24 +05:30
rohitwaghchaure
1f1c01d88e Merge pull request #44988 from frappe/35225
feat: Validate sub assembly and material request items in Production …
2025-01-09 16:28:29 +05:30
rohitwaghchaure
90339511aa Merge pull request #45190 from diptanilsaha/fix-typo-in-manufacturing-settings
fix: typo in manufacturing settings
2025-01-09 16:26:01 +05:30
diptanilsaha
a9b761f862 fix: typo in manufacturing settings 2025-01-09 16:05:40 +05:30
rohitwaghchaure
4ec824d71e Merge pull request #45183 from rohitwaghchaure/fixed-support-29059
fix: not able to see create Quality Inspection button
2025-01-09 14:36:52 +05:30
rohitwaghchaure
bb9dd7b8cc Merge pull request #45180 from rohitwaghchaure/fixed-support-28867
fix: do not add ordered items from Quotation to new Sales Order
2025-01-09 14:34:13 +05:30
Rohit Waghchaure
b291835ccd fix: not able to see create Quality Inspection button 2025-01-09 14:31:01 +05:30
Rohit Waghchaure
2e930eb97b fix: do not add ordered items from Quotation to new Sales Order 2025-01-09 13:52:34 +05:30
rohitwaghchaure
00dadc1a89 Merge pull request #45177 from rohitwaghchaure/fixed-support-29008
fix: timeout error for work order
2025-01-09 13:47:17 +05:30
Rohit Waghchaure
b4ceda6f2c fix: timeout error for work order 2025-01-09 13:27:43 +05:30
Khushi Rawat
7ea73d8265 chore: removal of decapitalization feature (#45162)
* chore: removal of decapitalization feature

* fix: rearrangement of asset capitalization doctype fields
2025-01-08 20:44:12 +05:30
Raffael Meyer
9e760e54a5 fix(Timesheet): ignore permissions when updating Task and Project (#45168) 2025-01-08 13:36:31 +01:00
Sudharsanan11
e614f07795 fix: validate linked sales person 2025-01-08 13:51:33 +05:30
Ejaaz Khan
81d8f257aa refactor: validate due date code and message according to doctype (#45126)
* refactor: change message of date comparision and refactor code

* refactor: commonify function call for sales and purchase invoice

* refactor: remove redundant mandatory error validation
2025-01-08 12:49:02 +05:30
Mihir Kandoi
dbb572eec1 test: Valuation of ageing stock 2025-01-08 11:52:24 +05:30
ruthra kumar
2b453219fc Merge pull request #45148 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-08 09:01:02 +05:30
ruthra kumar
ca44a31420 Merge pull request #45154 from ruthra-kumar/remove_possible_deadlock_in_auto_reconcile
fix: possible deadlock while using auto reconciliation
2025-01-08 09:00:42 +05:30
ruthra kumar
4620025dcd chore: remove 'Experimental' tag 2025-01-08 08:22:37 +05:30
ruthra kumar
5df9a8ab99 Merge pull request #45112 from marination/bank-reco-bank-balance
fix: Missing company filter breaks `get_account_balance` in Bank Reco
2025-01-08 08:16:21 +05:30
Frappe PR Bot
731822efac fix: Spanish translations 2025-01-07 21:48:22 +05:30
rohitwaghchaure
a24d7e8ecd Merge pull request #45144 from rohitwaghchaure/fixed-support-28796
fix: issue in returning components against the SCO
2025-01-07 18:31:18 +05:30
Rohit Waghchaure
729ce1dc50 fix: issue in returning components against the SCO 2025-01-07 18:11:56 +05:30
Diptanil Saha
31dd32dcdf fix: serial and batch no. buttons on pos (#45048) 2025-01-07 18:06:02 +05:30
Khushi Rawat
6850019649 feat: work in progress status for asset (#45066)
* feat: work in progress status for asset

* fix: test case correction

* fix(patch): added patch to update status of assets

* fix: updated tests
2025-01-07 17:38:21 +05:30
Diptanil Saha
2788739c1e feat: pos configuration for print receipt on complete order (#45024) 2025-01-07 17:35:01 +05:30
Diptanil Saha
9f77793f16 chore: removal of tally migration feature (#45100) 2025-01-07 17:28:46 +05:30
Ejaaz Khan
a0f17f8e73 refactor: change sales invoice button position (#45130) 2025-01-07 17:17:59 +05:30
Venkatesh
dc5bff9008 fix: ignore crm deal in tax_rule search filter (#45134) 2025-01-07 17:11:31 +05:30
marination
8521796811 fix: Wrong bank_ac_no filter + simplify convoluted logic 2025-01-07 13:28:55 +05:30
Sanket322
61d4593236 fix: minor update for readability 2025-01-07 12:44:29 +05:30
ruthra kumar
3bc74f219a Merge pull request #45121 from ruthra-kumar/revert_44989
fix: discount resetting on date change
2025-01-07 11:20:43 +05:30
ruthra kumar
886281f81a fix: discount resetting on date change
revert #44989
2025-01-07 11:14:42 +05:30
Raffael Meyer
9eede907f8 fix(Project): make status in confirmation dialog translatable (#45118) 2025-01-06 22:12:53 +00:00
Raffael Meyer
6f5fea6b52 refactor(Project): extract custom button function (#45116) 2025-01-06 21:58:38 +00:00
Frappe PR Bot
3ca3707603 fix: sync translations from crowdin (#45113) 2025-01-06 18:25:54 +01:00
marination
d7bf73cffa fix: Override pre-commit behaviour due to conflicts with CI 2025-01-06 21:14:41 +05:30
marination
8de0fe78ea fix: Missing company filter breaks get_account_balance in Bank Reco 2025-01-06 20:27:06 +05:30
Mihir Kandoi
87f1f6e15c fix: Attempt to fix status updater 1 2025-01-06 19:47:44 +05:30
rohitwaghchaure
7afe3cccd6 Merge pull request #45107 from rohitwaghchaure/fixed-support-28773
fix: Returned Qty in Work Order Consumed Materials report
2025-01-06 16:05:54 +05:30
Rohit Waghchaure
30d68a31e0 fix: Returned Qty in Work Order Consumed Materials report 2025-01-06 15:23:57 +05:30
Diptanil Saha
d79e561248 fix: update customer contact details on pos (#45071)
* fix: update customer contact details on pos

* refactor: removed console log statement
2025-01-06 14:53:44 +05:30
ruthra kumar
03abde6993 Merge pull request #45006 from diptanilsaha/fix-price_list_rate-for-pos-search-term
fix: pos search by term items price
2025-01-06 14:08:51 +05:30
ruthra kumar
c7370e214f Merge pull request #45099 from sokumon/new-button-in-coa
fix: show new button in coa if create access
2025-01-06 13:49:12 +05:30
sokumon
3125bc8a16 fix: show new button in coa if create access 2025-01-06 12:26:06 +05:30
rohitwaghchaure
7bbd70a7e2 Merge pull request #45097 from iamejaaz/subcontracting-links
feat: add subcontracting links in manufacturing workspace
2025-01-06 12:22:23 +05:30
rohitwaghchaure
acb5eeb281 Merge pull request #45084 from frappe/45082
fix: Alternative Items button in Work Order
2025-01-06 12:21:25 +05:30
Mihir Kandoi
b8838bd9b9 fix: Alternative Item button dissapearing on Save event 2025-01-06 11:22:06 +05:30
Ejaaz Khan
d42ee40b17 refactor: revert modified by in subcontracting 2025-01-06 11:00:54 +05:30
ruthra kumar
19f1e089bd Merge pull request #45047 from Abdeali099/use-constants
refactor: use variables for app name, title, and home route in hooks
2025-01-06 10:51:32 +05:30
Ejaaz Khan
bddffbb04f feat: add subcontracting links on manufacturing 2025-01-06 10:49:26 +05:30
ruthra kumar
2b88c13002 Merge pull request #45081 from frappe/mergify/copy/develop/pr-44949
Add phone number field when channel is phone on Payment Request doctype (copy #44949)
2025-01-06 10:09:54 +05:30
ruthra kumar
988b680244 Merge pull request #44952 from mahsem/Hold_to_On_Hold
fix: Hold_to_On_Hold
2025-01-06 08:44:33 +05:30
ruthra kumar
4d74724a34 Merge pull request #44943 from creative-paramu/bank_reconcilation_company_filter
fix: Bank Reconciliation Statement Report Company Filter
2025-01-06 08:35:44 +05:30
ruthra kumar
b6fe43b63a Merge pull request #45051 from aerele/currency-validation
fix: ignore currency validation while canceling the voucher
2025-01-06 08:25:05 +05:30
ruthra kumar
d39fa07620 Merge pull request #45088 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-06 06:19:28 +05:30
Frappe PR Bot
34a4efbc59 fix: Esperanto translations 2025-01-05 20:36:22 +05:30
Frappe PR Bot
d34ebcfe9a fix: German translations 2025-01-05 20:36:19 +05:30
Frappe PR Bot
7b5f026b8b fix: Bosnian translations 2025-01-05 20:36:16 +05:30
Frappe PR Bot
630009e28f fix: Persian translations 2025-01-05 20:36:12 +05:30
Frappe PR Bot
9727bcc281 fix: Chinese Simplified translations 2025-01-05 20:36:09 +05:30
Frappe PR Bot
3c96ccf990 fix: Turkish translations 2025-01-05 20:36:06 +05:30
Frappe PR Bot
74791fd619 fix: Swedish translations 2025-01-05 20:36:02 +05:30
Frappe PR Bot
ee3f3fc799 fix: Russian translations 2025-01-05 20:35:59 +05:30
Frappe PR Bot
7bcd5f5bcb fix: Polish translations 2025-01-05 20:35:56 +05:30
Frappe PR Bot
af027cf980 fix: Hungarian translations 2025-01-05 20:35:53 +05:30
Frappe PR Bot
b3e2e8e123 fix: Arabic translations 2025-01-05 20:35:49 +05:30
Frappe PR Bot
43408c1b6d fix: Spanish translations 2025-01-05 20:35:46 +05:30
Frappe PR Bot
609f789807 fix: French translations 2025-01-05 20:35:42 +05:30
Frappe PR Bot
cacc90c224 chore: update POT file (#45092) 2025-01-05 11:26:50 +01:00
rohitwaghchaure
a76c3b5f3f Merge pull request #45087 from rohitwaghchaure/fixed-support-28646
fix: invoice against purchase receipt with returned quantity
2025-01-04 20:37:08 +05:30
Frappe PR Bot
ae4e55bf3a fix: Persian translations 2025-01-04 20:28:58 +05:30
Frappe PR Bot
07ba0281f7 fix: Swedish translations 2025-01-04 20:28:52 +05:30
Rohit Waghchaure
d5babf4237 fix: invoice against purchase receipt with returned quantity 2025-01-04 19:59:19 +05:30
rohitwaghchaure
9e86a02a91 Merge pull request #45083 from rohitwaghchaure/fixed-support-28669
fix: consider expired batches in stock reco
2025-01-04 19:26:05 +05:30
Mihir Kandoi
e28382afc1 fix: Alternative Items button in Work Order 2025-01-04 17:22:16 +05:30
Mihir Kandoi
1f2d7da426 fix: Fixed final test case 2025-01-04 15:22:28 +05:30
Mihir Kandoi
f996f71d16 fix: Fixed more test cases 2025-01-04 15:17:31 +05:30
Rohit Waghchaure
f51c9f578c fix: consider expired batches in stock reco 2025-01-04 12:58:07 +05:30
ruthra kumar
ba90a6a4bf chore: fix json 2025-01-04 05:45:58 +05:30
Joseph Mania
947ab72441 refactor: phone number field when channel is phone on Payment Request (#44949)
Co-authored-by: maniamartial <martialamania19@gmail.com>
(cherry picked from commit cfa062df86)
2025-01-04 05:29:34 +05:30
ruthra kumar
5245c54de9 Merge pull request #44983 from Sanket322/budget_based_on_distribution
fix: add monthly distributation and write query in qb
2025-01-04 05:17:10 +05:30
Frappe PR Bot
e39638bdcd fix: sync translations from crowdin (#45055) 2025-01-03 16:07:51 +01:00
Mihir Kandoi
839b79ffd0 fix: Test case for ageing report 2025-01-03 20:00:36 +05:30
Sanket322
ce99764772 fix: pass right existing address 2025-01-03 18:04:56 +05:30
Sanket322
058fdca981 fix: don't create invoice if invoice start date is in future 2025-01-03 17:44:05 +05:30
Mihir Kandoi
2f80c4dee5 feat: Added valuation of quantity for each age group in stock ageing report 2025-01-03 16:51:44 +05:30
Sanket322
f46f1bead4 fix: set billing and shipping address on change of company 2025-01-03 16:44:24 +05:30
Ankush Menat
4f690affc9 perf: Skip link checking on repost's remove_attached_file (#45061)
This is internal detail, doesn't need to do horrible link checks in
framework.
2025-01-02 16:59:31 +00:00
ruthra kumar
413fef332a Merge pull request #45056 from ruthra-kumar/partial_revert_44989
chore: partial revert #44989
2025-01-02 20:56:33 +05:30
ruthra kumar
63d547fb4a chore: partial revert #44989 2025-01-02 20:50:28 +05:30
rohitwaghchaure
3221c89218 Merge pull request #45053 from sokumon/ux-issues
fix(style): set image width in BOM
2025-01-02 19:00:25 +05:30
sokumon
b634ba7f54 fix(style): set image width in BOM 2025-01-02 17:37:46 +05:30
venkat102
49885f8eae fix: ignore party account validation while canceling the voucher 2025-01-02 17:27:34 +05:30
Abdeali Chharchhoda
71d1205f53 refactor: use variables for app name, title, and home route in hooks 2025-01-02 16:40:12 +05:30
venkat102
15d488b9aa fix: ignore currency validation while canceling the voucher 2025-01-02 16:10:12 +05:30
rohitwaghchaure
bdece96510 Merge pull request #45043 from rohitwaghchaure/fixed-github-44909
fix: validate components and their qty as per BOM in the stock entry
2025-01-02 13:44:29 +05:30
Rohit Waghchaure
b1de82ddad fix: validate components and their qty as per BOM in the stock entry 2025-01-02 13:11:19 +05:30
Mihir Kandoi
5dacfd5cda fix: Test case and refactored some code 2025-01-02 12:28:01 +05:30
ruthra kumar
e609a6a038 Merge pull request #45040 from ruthra-kumar/use_idx_for_identifying
refactor: use `idx` for identifying row
2025-01-02 12:16:40 +05:30
rohitwaghchaure
1f26feca2e Merge pull request #45039 from rohitwaghchaure/fixed-github-34729
fix: removed unused code
2025-01-02 12:16:16 +05:30
ruthra kumar
51354c894a refactor: use idx for identifying row 2025-01-02 11:54:55 +05:30
ruthra kumar
53d8e32961 Merge pull request #45033 from frappe/l10n_develop
fix: sync translations from crowdin
2025-01-02 10:47:35 +05:30
Rohit Waghchaure
dc5f2d35ac fix: removed unused code 2025-01-02 10:26:51 +05:30
rohitwaghchaure
d2b0e0fa2d Merge pull request #45036 from rohitwaghchaure/fixed-support-28464
fix: Auto BOM cost update issue
2025-01-02 10:24:25 +05:30
Rohit Waghchaure
28ea3ddd51 fix: BOM cost update issue 2025-01-02 09:44:32 +05:30
Frappe PR Bot
81a6e42620 fix: Persian translations 2025-01-01 19:47:03 +05:30
Mihir Kandoi
015fd4a05b fix: Made requested changes by mentor and fixed some bugs in Production Plan Summary report 2025-01-01 16:51:48 +05:30
rohitwaghchaure
5e977cf5a7 Merge pull request #44999 from frappe/fix_multiple_sco_pr
fix: Added patch and fallback code to prevent future issues similar …
2025-01-01 16:35:41 +05:30
rohitwaghchaure
e92af10f14 fix: slow stock transactions (#45025) 2025-01-01 14:50:26 +05:30
Mihir Kandoi
d1d01482df fix: Removed patch as instructed by mentor 2025-01-01 13:49:49 +05:30
ruthra kumar
8aa3157307 Merge pull request #44989 from aerele/update_apply_pricing_rules
fix: apply apply_pricing_rule on date change
2025-01-01 10:11:30 +05:30
rohitwaghchaure
b84c8ff960 fix: incorrect quality inspection linked in purchase receipt (#44985) 2025-01-01 08:30:00 +05:30
rohitwaghchaure
7db9bcaeac fix: precision issue (#45013) 2025-01-01 08:29:14 +05:30
rohitwaghchaure
a9cc23f242 fix: duplicate validate for stock closing entry (#45016) 2025-01-01 08:28:52 +05:30
Mihir Kandoi
575fb43f9c fix: Fixed logic in if condition causing tests to fail 2024-12-31 20:33:05 +05:30
Frappe PR Bot
2cd915fb4d fix: sync translations from crowdin (#45014)
* fix: Swedish translations

* fix: Persian translations
2024-12-31 15:41:15 +01:00
ruthra kumar
b60bd17d1d refactor: store result in variable before enumeration
helps to inspect result while debugging
2024-12-31 17:04:37 +05:30
ruthra kumar
c6634d03ad Merge pull request #44987 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-31 16:58:45 +05:30
ruthra kumar
fa3c882656 Merge pull request #44940 from aerele/bank_reconciliation_multi_currency
fix(Bank Reconciliation Tool): fetch amount in company  currency
2024-12-31 15:57:27 +05:30
ruthra kumar
e58d73525b Merge pull request #44903 from ljain112/fix-bank-reco
fix: set paid amount in party currency in bank reco payment entry
2024-12-31 15:52:35 +05:30
ruthra kumar
ebc0ed8a31 Merge pull request #44884 from ljain112/fix-item-tax-template
fix: update item_tax_rate in backend
2024-12-31 15:50:39 +05:30
diptanilsaha
2beb485d77 fix: load search term price with customer default price list 2024-12-31 14:55:01 +05:30
ljain112
a203e3ffaf fix: deduct tds on excess amount if checked 2024-12-31 13:46:50 +05:30
diptanilsaha
4b6cae156e fix: load price list rate for pos search term 2024-12-31 13:22:18 +05:30
Mihir Kandoi
65dc3505c4 fix: Added patch and fallback code to prevent future issues similiar to helpdesk ticket 28246 2024-12-31 12:53:30 +05:30
Khushi Rawat
079ec864de fix: copy accounting dimensions to asset and sales invoice (#44964)
* fix: copy accounting dimensions to asset and sales invoice

* fix: replace sql query with query builder

* refactor: reuse function for accounting dimensions

* fix: loop handling

* fix: use explicit param
2024-12-31 07:05:51 +00:00
rohitwaghchaure
7c4aecf834 fix: negative stock balance (#44990) 2024-12-31 12:30:15 +05:30
Vishnu VS
d6980a9493 fix(report): Purchase Order Analysis pymysql.err (#44957) 2024-12-31 12:21:57 +05:30
Diptanil Saha
d1ae0d784e fix: load customer default price list in pos during item selection (#44991)
fix: load customer default price list in pos
2024-12-31 12:14:29 +05:30
DHINESH00
2cbab9b875 fix: apply apply_pricing_rule date change 2024-12-30 22:47:37 +05:30
Mihir Kandoi
22d38c2af4 feat: Validate sub assembly and material request items in Production Plan and fix Production Plan summary reports not showing correct received quantity from subcontracted POs 2024-12-30 20:12:14 +05:30
Frappe PR Bot
7a5d958aba fix: Swedish translations 2024-12-30 19:48:02 +05:30
Sanket322
27195c7c96 fix: add monthly distributation and write query in qb 2024-12-30 17:56:17 +05:30
ruthra kumar
54cb99eae3 Merge pull request #44855 from mahsem/in_contex_translation_fixes
fix: in_context_translation_fixes
2024-12-30 15:56:01 +05:30
ruthra kumar
7926bf066a Merge pull request #44975 from aerele/filter-project
fix: add company filter to project
2024-12-30 15:27:37 +05:30
DHINESH00
a984aaae36 fix: fetch amount in company currency 2024-12-30 15:15:33 +05:30
ruthra kumar
bb0cf3bf78 Merge pull request #44761 from aerele/pos_discount
fix: apply discount on qty change
2024-12-30 14:56:02 +05:30
venkat102
b92f8bc514 fix: include company in filter condition 2024-12-30 14:18:55 +05:30
venkat102
1a7b09e576 fix: add company filter to project 2024-12-30 14:18:13 +05:30
ruthra kumar
ee418ffefa Merge pull request #44883 from aerele/account-party-validation
fix: Validate party on non receivable / payable account
2024-12-30 13:32:54 +05:30
Diptanil Saha
98cbb7e900 fix: pos payment using non-default mode of payment (#44920)
* fix: pos payment using non-default mode of payment (#41108)

* fix: included css syntax

* refactor: created a function to sanitize the class name

* refactor: reusing method to sanitize class name

* refactor: function rename
2024-12-30 13:27:49 +05:30
ruthra kumar
867aa9dd86 Merge pull request #44552 from HUMENTH/develop
Fix: Added Order Number and Order Date fields to the Blanket Order form.
2024-12-30 12:32:34 +05:30
ruthra kumar
4f398d8edc Merge pull request #44921 from ljain112/fix-val-itt
fix: get item tax template based on posting date
2024-12-30 12:28:58 +05:30
ruthra kumar
93b70b98bb Merge pull request #44906 from Sanket322/company_address_in_purchase_invoice
fix: set/update billing address on change of company
2024-12-30 12:22:08 +05:30
Himanshu Shivhare
5a284df51d refactor: Order Number and Order Date fields to Blanket Order 2024-12-30 12:11:32 +05:30
ruthra kumar
784a62eae8 Merge pull request #44958 from ruthra-kumar/fix_test_data_issue_on_manufacturing
refactor(test): make manufacturing test idempotent
2024-12-30 11:29:58 +05:30
ruthra kumar
f3be246df3 refactor(test): make manufacturing test idempotent 2024-12-30 11:03:25 +05:30
rohitwaghchaure
9fdeb5f826 fix: incorrect filter for BOM (#44954) 2024-12-30 09:47:16 +05:30
Frappe PR Bot
e216547084 fix: sync translations from crowdin (#44944) 2024-12-29 18:31:46 +01:00
mahsem
92b1f314ef fix: Hold_to_On_Hold 2024-12-29 14:15:52 +01:00
Frappe PR Bot
6e0dd271f5 chore: update POT file (#44951) 2024-12-29 11:33:25 +01:00
mahsem
185bbb4c20 fix: postal_code_move_and_fixes 2024-12-28 09:25:30 +01:00
creative-paramu
50c92034ba Bank Reconciliation Statement Report Company Filter 2024-12-27 17:54:20 +05:30
rohitwaghchaure
9661c1d081 fix: ignore validate while making WO from MR (#44939) 2024-12-27 16:43:11 +05:30
ruthra kumar
6f8d6c81d5 Merge pull request #44904 from Sanket322/ignore_duplicate
fix: ignore duplicate while creating default templates
2024-12-27 14:46:58 +05:30
ljain112
70b1077286 fix: set paid amount in party currency in bank reco payment entry 2024-12-27 14:21:00 +05:30
ruthra kumar
bcae2810b9 Merge pull request #44892 from Sanket322/payment_schedule_in_is_paid
fix: clear payment schedule in purchase invoice for is_paid
2024-12-27 13:23:07 +05:30
rohitwaghchaure
303c52f134 fix: ignore inventory dimension for SABB and Pick List (#44933) 2024-12-27 12:57:52 +05:30
Sanket322
187c74ae09 fix: use meta to check field instead of doctype 2024-12-27 12:53:41 +05:30
ruthra kumar
0589fa7f3e refactor: early return is always better
validate_advance_entries() has a heavy IO bound operation. Early
return on unwanted cases is always better.
2024-12-27 12:48:25 +05:30
Sanket322
cb197fd01f fix: move code from purchase invoice to buying controller 2024-12-27 12:35:36 +05:30
Diptanil Saha
cfcc24a341 fix (pos closing entry): validation for 100 pc discount on pos invoice (#44899) 2024-12-27 11:34:41 +05:30
ruthra kumar
4f29908aa9 Merge pull request #44907 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-27 11:34:32 +05:30
ruthra kumar
e85142f996 Merge pull request #44816 from mahsem/strings_for_translation
fix: strings for translation
2024-12-27 10:56:57 +05:30
ruthra kumar
78b0b3047c Merge pull request #44815 from mahsem/relabel_rate_to_tax_rate
fix: relabel rate to tax rate
2024-12-27 10:54:30 +05:30
Shreyas Sojitra
751a0a93ef fix: attribute order in create multiple variants dialog (#44800)
* Fix : show multiple variants dialog

Fixed attribute order in create multiple variant dialog.

* fix(dialog): attribute order in create multiple variants dialog

Fixed attribute order in create multiple variant dialog.
2024-12-27 10:53:17 +05:30
rohitwaghchaure
c9088f4955 refactor: stock closing balance -> stock closing entry (#44489)
* refactor: stock closing balance

* perf: batchwise balance history report

* fix: stock ageing data for stock balance report
2024-12-26 22:57:58 +05:30
rohitwaghchaure
ab1cca0c40 fix: not able to make purchase receipt from SCR (#44919) 2024-12-26 19:09:45 +05:30
Frappe PR Bot
8f82219986 fix: Turkish translations 2024-12-26 18:35:12 +05:30
Frappe PR Bot
f5e53c9661 fix: Swedish translations 2024-12-26 18:35:08 +05:30
Nabin Hait
b998933ef0 fix: Show order tax amount in customer currency on the portal (#44915) 2024-12-26 18:18:35 +05:30
Diptanil Saha
ac26622d6e fix: limit discount value to 100 in pos cart (#44916)
* fix: limit discount value to 100 in pos cart

* fix: error message on invalid discount
2024-12-26 12:45:53 +00:00
ljain112
976e35d547 fix: get item tax template based on posting date 2024-12-26 17:18:39 +05:30
rohitwaghchaure
1319ce4bc1 fix: material request status (#44917) 2024-12-26 15:58:39 +05:30
rohitwaghchaure
614a8f106d fix: allow zero valuation rate (#44902) 2024-12-25 22:20:23 +05:30
Frappe PR Bot
888da9c1ab fix: Turkish translations 2024-12-25 18:30:08 +05:30
Frappe PR Bot
9f8448bb15 fix: Spanish translations 2024-12-25 18:29:59 +05:30
Sanket322
0adfebee85 fix: set/update billing address on change of company 2024-12-25 18:14:10 +05:30
Sanket322
9368485594 fix: ignore duplicate while creating default templates 2024-12-25 15:22:53 +05:30
Frappe PR Bot
8bcfd2429d fix: sync translations from crowdin (#44898)
* fix: Swedish translations

* fix: Turkish translations

* fix: Persian translations
2024-12-24 12:47:12 +00:00
ruthra kumar
42c8ce68ad Merge pull request #44787 from vishakhdesai/refactor-bt-allocation-query
fix: refactor query in`get_total_allocated_amount` in bank_transaction
2024-12-24 17:52:30 +05:30
ruthra kumar
0b113815c9 Merge pull request #44860 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-24 17:03:44 +05:30
ruthra kumar
7378eff0ca Merge pull request #44878 from aerele/consolidated-financial-pnl
fix: show profit and loss after period closing
2024-12-24 17:02:43 +05:30
ruthra kumar
f0a34aa587 Merge pull request #44889 from aerele/payment-entry-clearance-date
refactor: use db_set instead of set_value to trigger notification
2024-12-24 16:42:02 +05:30
Sanket322
e1fc239f3d fix: clear payment schedule in purchase invoice for is_paid 2024-12-24 16:38:51 +05:30
Karuppasamy923
8abbece7c4 fix: Set account type payable for advance account 2024-12-24 16:00:40 +05:30
venkat102
f8b923edfe refactor: use db_set instead of set_value to trigger notification 2024-12-24 15:34:39 +05:30
ljain112
de54c0b41f fix: update item_tax_rate in backend 2024-12-24 15:15:30 +05:30
rohitwaghchaure
021d077808 fix: set project in GL from the SLE (#44879) 2024-12-24 14:49:41 +05:30
Karuppasamy923
a10a15b2c3 test: add unit test to validate on non receivable / payable account 2024-12-24 13:54:37 +05:30
Karuppasamy923
c6a2d86ba6 fix: validate party on non receivable / payable account 2024-12-24 13:53:25 +05:30
ruthra kumar
c59d3bda7e Merge pull request #44794 from ljain112/fix-ldc
fix: correct tds rate with lower deduction certificate
2024-12-24 13:44:30 +05:30
venkat102
dc5cd93bf0 fix: show profit and loss after period closing 2024-12-24 12:35:38 +05:30
Abdeali Chharchhodawala
d4b21f532a fix: add Stock UOM when adding new item in POS list (#44780) 2024-12-24 10:22:32 +05:30
ruthra kumar
60694838f3 Merge pull request #44763 from vishakhdesai/fix-si-issue
fix: Paid + Write Off Amount issue in Sales Invoice
2024-12-24 10:17:16 +05:30
rohitwaghchaure
079b86044e fix: posting_time issue (#44870) 2024-12-24 09:06:37 +05:30
Khushi Rawat
0b1c3208a0 Merge pull request #44854 from khushi8112/asset-fields-precision-check
fix: asset fields precision check
2024-12-24 00:00:34 +05:30
Khushi Rawat
2f7e6230a6 fix: test case correction 2024-12-23 23:37:51 +05:30
mahsem
1f4e1811de fix: whitespace 2024-12-23 17:42:33 +01:00
Diptanil Saha
948556def5 Merge pull request #44856 from diptanilsaha/fix-pos-invoice-advanced-received
fix: fetch advance payment entries on pos invoice
2024-12-23 20:59:00 +05:30
rohitwaghchaure
c9b143b509 fix: stock entry not fetching expired batches (#44863) 2024-12-23 20:28:06 +05:30
rohitwaghchaure
7d41805d0e fix: Warehouse wise Stock Value chart roles (#44865) 2024-12-23 20:27:19 +05:30
rohitwaghchaure
54d7b742ab perf: slow query related to stock ledger entry (#44861) 2024-12-23 18:36:43 +05:30
Frappe PR Bot
2aff3ced52 fix: Esperanto translations 2024-12-23 17:32:50 +05:30
Frappe PR Bot
7497f0ca52 fix: German translations 2024-12-23 17:32:46 +05:30
Frappe PR Bot
42f2b965d1 fix: Bosnian translations 2024-12-23 17:32:43 +05:30
Frappe PR Bot
70405d9026 fix: Persian translations 2024-12-23 17:32:39 +05:30
Frappe PR Bot
4c5e9c005c fix: Chinese Simplified translations 2024-12-23 17:32:34 +05:30
Frappe PR Bot
789469f784 fix: Turkish translations 2024-12-23 17:32:31 +05:30
Frappe PR Bot
643163cc24 fix: Swedish translations 2024-12-23 17:32:26 +05:30
Frappe PR Bot
e98881cc56 fix: Russian translations 2024-12-23 17:32:21 +05:30
Frappe PR Bot
ab36dfe5ef fix: Polish translations 2024-12-23 17:32:17 +05:30
Frappe PR Bot
3892f2a1fa fix: Hungarian translations 2024-12-23 17:32:14 +05:30
Frappe PR Bot
abf624b994 fix: Arabic translations 2024-12-23 17:32:10 +05:30
Frappe PR Bot
05ceb25abc fix: Spanish translations 2024-12-23 17:32:04 +05:30
Frappe PR Bot
5cb86b1367 fix: French translations 2024-12-23 17:32:00 +05:30
rohitwaghchaure
a515a399cf fix: incoming rate should be zero for rejected items (#44857) 2024-12-23 16:58:07 +05:30
mahsem
a87e7fde03 fix: in_contex_translation_fixes 2024-12-23 11:30:00 +01:00
Diptanil Saha
a7078e5702 fix: fetch advance payment entries on pos invoice 2024-12-23 15:54:16 +05:30
Khushi Rawat
92b8768ae2 fix: asset field precision check 2024-12-23 15:42:18 +05:30
rohitwaghchaure
a2c2b8b5ad fix: do not validate qc for scrap item (#44844) 2024-12-23 15:39:04 +05:30
ruthra kumar
2dfd7472a4 Merge pull request #44850 from ruthra-kumar/remove_hardcoded_names_in_test
refacto(test): remove hardcoded names
2024-12-23 15:25:26 +05:30
ruthra kumar
ab91abb144 refacto(test): remove hardcoded names 2024-12-23 14:54:15 +05:30
Nijith anil
6f00a87a9c fix(ux): purchase invoice link in error message (#44797)
* fix(ux): purchase invoice link in error message

* chore: fix linter

---------

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2024-12-23 09:18:32 +00:00
ruthra kumar
ab01b8fc63 Merge pull request #44738 from aerele/tds-section-code
fix: fetch tax withholding category from the voucher
2024-12-23 14:34:17 +05:30
ruthra kumar
10b7c3e0ac Merge pull request #44716 from ljain112/fix-gp-serial
fix: avg. buying amount for product bundle item with serial and batch no in gross profit report
2024-12-23 14:33:14 +05:30
ruthra kumar
fc57fb22a5 Merge pull request #44813 from vishakhdesai/acc-rec-fix
fix: update correct cost center in Accounts Receivable Report
2024-12-23 14:20:28 +05:30
ruthra kumar
fad00fedaa Merge pull request #44808 from aerele/difference_posting_date_in_si_pi
feat: Added difference_posting_date field in Sales Invoice Advance and Purchase Invoice Advance
2024-12-23 14:09:07 +05:30
Mihir Kandoi
b7699012b2 feat: Create subcontracted PO from Material Request (#44745)
* feat: Create subcontracted PO from Material Request

* fix: Made minor changes in logic to pass all test cases

* refactor: Made changes suggested by mentor and simplified logic

* test: Made changes to tests
2024-12-23 13:11:44 +05:30
ruthra kumar
cf57cb73f0 Merge pull request #44786 from ljain112/fic-adv-pv
fix: correct args for get_advance_payment_entries_for_regional
2024-12-23 12:57:42 +05:30
ruthra kumar
a2a642a5b1 Merge pull request #44751 from ljain112/fix-gp-service-item
fix: buying rate for service item in gross profit report
2024-12-23 11:45:18 +05:30
DHINESH00
547c8004eb fix: Semgrep rules 2024-12-23 11:23:23 +05:30
ljain112
cc3f4bb0b0 fix: avg. buying amount for product bundle item with serial and batch no in gross profit report 2024-12-23 11:22:41 +05:30
ruthra kumar
5567a41a2a Merge pull request #44681 from frappe/mergify/bp/develop/pr-44679
fix: Stock Entry uses incorrect company when generated from Pick List (backport #44679)
2024-12-23 11:12:34 +05:30
ruthra kumar
bcb7617630 Merge pull request #44644 from barredterra/lost-quotation-permissions
fix: permissions for marking Quotation as lost
2024-12-23 11:10:26 +05:30
rohitwaghchaure
fe0036e707 fix: incorrect Material Transferred for Manufacturing qty (#44823) 2024-12-23 10:57:47 +05:30
ruthra kumar
b1c9716fec Merge pull request #44812 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-23 10:21:55 +05:30
ruthra kumar
c100b68ad1 Merge pull request #44826 from Abdeali099/bank-account-typo-fix
fix: Remove typo from `Bank Account` on trash
2024-12-23 10:21:24 +05:30
ruthra kumar
085ef5df8f Merge pull request #44825 from deepeshgarg007/ledger_repost
fix: Ledger repost support for extending app doctypes
2024-12-23 09:44:43 +05:30
Abdeali Chharchhoda
ba28f6bf73 fix: Remove typo 2024-12-23 08:48:46 +05:30
Deepesh Garg
919abd2c03 fix: Add hooks for repost allowed doctypes 2024-12-22 20:34:31 +05:30
Frappe PR Bot
31803a2f53 chore: update POT file (#44822) 2024-12-22 15:09:01 +01:00
Frappe PR Bot
a4c34ad759 fix: Swedish translations 2024-12-22 17:22:40 +05:30
mahsem
3be633f6f1 fix: strings for translation 2024-12-21 15:08:19 +01:00
mahsem
1eb8b0ceef fix: relabel rate to tax rate 2024-12-21 13:49:54 +01:00
Frappe PR Bot
bf4d696f17 fix: Persian translations 2024-12-21 17:09:33 +05:30
Frappe PR Bot
7cd6bfc8a4 fix: Swedish translations 2024-12-21 17:09:29 +05:30
rohitwaghchaure
56f561cdaa fix: Duplicate entry ' EF1DE8B2E1B6' for key 'PRIMARY' (#44809) 2024-12-21 10:01:12 +05:30
vishakhdesai
3b36ce560c fix: do not set cost_center update_voucher_balance as it is set in init_voucher_balance 2024-12-20 18:41:51 +05:30
vishakhdesai
09776e9a5a fix: update correct cost center in Accounts Receivable Report 2024-12-20 18:03:42 +05:30
Frappe PR Bot
913001e44c fix: Turkish translations 2024-12-20 17:02:43 +05:30
Frappe PR Bot
5057a4e1b2 fix: Swedish translations 2024-12-20 17:02:40 +05:30
Frappe PR Bot
afea92c01d fix: Spanish translations 2024-12-20 17:02:36 +05:30
ruthra kumar
a764d16674 Merge pull request #44703 from mahsem/Swedish_tax_templates
fix: Swedish tax templates
2024-12-20 14:11:47 +05:30
rs-rethik
854e37c05c fix: update query 2024-12-20 14:00:54 +05:30
rs-rethik
2d58e845e6 refactor: convert sql query to query builder 2024-12-20 12:42:47 +05:30
ruthra kumar
6db1b3fef8 Merge pull request #44795 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-20 12:14:33 +05:30
rs-rethik
c14a2d73bf test: add unit test to validate journal entry posting date 2024-12-20 12:13:35 +05:30
rs-rethik
ff1d040a6e feat: use difference_posting_date for journal entry posting_date 2024-12-20 12:10:08 +05:30
rs-rethik
225e56cbca feat: add difference_posting_date field 2024-12-20 12:07:20 +05:30
ruthra kumar
82306c5a85 Merge pull request #44665 from mahsem/Swedish_2024_COA
fix: add Swedish_2024_COA
2024-12-20 11:56:11 +05:30
rohitwaghchaure
a7b5e2565b fix: slow posting datetime update (#44799) 2024-12-20 10:12:12 +05:30
DHINESH00
d541259da9 fix: update discounting on mixed conditions 2024-12-19 17:15:11 +05:30
Frappe PR Bot
e3a7f2f2e7 fix: Persian translations 2024-12-19 17:05:19 +05:30
Frappe PR Bot
b9e96f62ef fix: Turkish translations 2024-12-19 17:05:14 +05:30
Frappe PR Bot
51137cf001 fix: Swedish translations 2024-12-19 17:05:10 +05:30
ljain112
cb9c12d495 fix: correct tds rate with lower deduction certificate 2024-12-19 16:27:04 +05:30
rohitwaghchaure
3662a6a41d fix: closing stock balance permissions (#44791) 2024-12-19 14:59:33 +05:30
ruthra kumar
93ec962aae Merge pull request #44746 from ljain112/fix-itt
fix: correct args for get_item_tax_map
2024-12-19 13:52:33 +05:30
rohitwaghchaure
90baa38f64 perf: SABB (#44764) 2024-12-19 13:00:31 +05:30
vishakhdesai
2ce07865d3 fix: failing tests fixed 2024-12-19 12:55:11 +05:30
vishakhdesai
6b847cdb62 fix: refactor query in get_total_allocated_amount in bank_transaction 2024-12-19 12:27:06 +05:30
ljain112
df13a4cc2f fix: correct args for get_advance_payment_entries_for_regional 2024-12-19 12:04:04 +05:30
ruthra kumar
700dc05b55 Merge pull request #44785 from ruthra-kumar/expanded_screenshot
chore: expand screenshot section by default
2024-12-19 10:55:45 +05:30
ruthra kumar
ce9f10b387 chore: expand screenshot section by default 2024-12-19 10:43:36 +05:30
Mihir Kandoi
3eba6bf3dd feat(subcontracting): Added provision to create multiple Subcontracting Orders against a single Purchase Order (#44711)
* feat(subcontracting): Added provision to create multiple Subcontracting Orders from a single Subcontracted Purchase Order

* refactor(new_sc_flow_2): Fixed error thrown by semgrep
2024-12-18 20:38:21 +05:30
rohitwaghchaure
779dd2d798 fix: POS Closing entry issue (#44772) 2024-12-18 20:19:36 +05:30
ruthra kumar
6f99e9959d Merge pull request #44771 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-18 17:54:02 +05:30
vishakhdesai
1fd7ba7c88 fix: Paid + Write Off Amount issue in Sales Invoice 2024-12-18 17:29:55 +05:30
Nabin Hait
febdf4c61e fix: added docs.frappe.io in documentation_url (#44776) 2024-12-18 11:58:22 +00:00
Frappe PR Bot
c798a68e5d fix: Persian translations 2024-12-18 15:42:28 +05:30
Frappe PR Bot
663372a23e fix: Swedish translations 2024-12-18 15:42:23 +05:30
ruthra kumar
7fed467354 Merge pull request #44765 from ljain112/fix-pl-error
fix: 'str' object has no attribute 'get_sql'
2024-12-18 14:12:29 +05:30
ljain112
9a43acb65c fix: 'str' object has no attribute 'get_sql' 2024-12-18 13:47:37 +05:30
ruthra kumar
54eedaeeff Merge pull request #44758 from ruthra-kumar/fix_broken_link
fix: use utility method to generate url
2024-12-18 11:02:01 +05:30
ruthra kumar
b970eb8b15 fix: use utility method to generate url 2024-12-18 10:54:21 +05:30
DHINESH00
352b82bc0b fix: apply discount on qty change 2024-12-18 10:51:04 +05:30
ruthra kumar
878f76455b Merge pull request #44708 from aerele/pricing-rule-discount
fix: update discount when pricing rule is changed
2024-12-17 20:42:04 +05:30
ruthra kumar
5c9e8fb4da Merge pull request #44695 from ljain112/fix-fin-stat
fix: User permissions in financial statements
2024-12-17 20:37:35 +05:30
ljain112
5ea131c763 fix: using query.walk() for escaping 2024-12-17 18:49:38 +05:30
ljain112
8d6e79a16f fix: buying rate for service item in gross profit report 2024-12-17 17:54:08 +05:30
ruthra kumar
7ac7a40aec Merge pull request #44739 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-17 17:30:04 +05:30
ruthra kumar
3342fa1440 Merge pull request #44685 from aerele/mop-bank-account
fix: set company bank account if default account not set in mode of p…
2024-12-17 17:18:35 +05:30
ljain112
fe4eb8e6db fix: correct args for get_item_tax_map 2024-12-17 17:03:41 +05:30
ruthra kumar
a819b1feaa Merge pull request #44742 from ruthra-kumar/readme_update
chore: update readme
2024-12-17 15:55:16 +05:30
ruthra kumar
8205000195 chore: move screenshots to key features 2024-12-17 15:41:26 +05:30
Frappe PR Bot
4387e09ee8 fix: Swedish translations 2024-12-17 14:52:45 +05:30
Frappe PR Bot
3be6390a12 fix: Spanish translations 2024-12-17 14:52:34 +05:30
ruthra kumar
c33b9922a5 chore: more screenshots 2024-12-17 14:17:08 +05:30
ruthra kumar
c25ef357a5 chore: update headers 2024-12-17 14:15:12 +05:30
venkat102
09e64594db fix: fetch tax withholding category from the voucher 2024-12-17 13:15:41 +05:30
venkat102
1663c7983e chore: use get function 2024-12-17 13:15:02 +05:30
rohitwaghchaure
1f5d7072e7 fix: purchase return entry issue (#44721) 2024-12-17 12:29:20 +05:30
ruthra kumar
37fb6d12da Merge pull request #44660 from vorasmit/tds-jv-base-total
fix: better indicator base amount for Tax Witholding in Journal Entry
2024-12-17 11:49:37 +05:30
ruthra kumar
94c64235d4 Merge pull request #44650 from aerele/multiselect_cc_in_process_statement_of_accounts
feat: Multiselect cc in process statement of accounts
2024-12-17 11:34:54 +05:30
ruthra kumar
8b89cc69c1 Merge pull request #44712 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-17 11:29:19 +05:30
mahsem
8a5f7ec4d7 feat: swedish COA 2024-12-17 11:22:42 +05:30
rs-rethik
5401cf9647 chore: remove irrelevant import 2024-12-17 11:10:25 +05:30
rs-rethik
494ac04f8e refactor: convert sql query to query builder 2024-12-17 11:10:25 +05:30
rs-rethik
2a6be127ef fix: update cc_to multiselect in process statement of accounts 2024-12-17 11:10:25 +05:30
rs-rethik
4de180feee feat: change type link to multiselect 2024-12-17 11:10:25 +05:30
rohitwaghchaure
852596dbe6 fix: pos invoice return reference missing (#44720) 2024-12-17 11:05:18 +05:30
ruthra kumar
84dff3601a Merge pull request #44646 from barredterra/validate-discount-date
feat: validate discount date in payment schedule
2024-12-17 10:58:15 +05:30
Frappe PR Bot
b565b67cc7 fix: Esperanto translations 2024-12-17 10:38:22 +05:30
Frappe PR Bot
12634d0bd6 fix: German translations 2024-12-17 10:38:22 +05:30
Frappe PR Bot
fda57420a5 fix: Bosnian translations 2024-12-17 10:38:22 +05:30
Frappe PR Bot
bf0cfc4704 fix: Persian translations 2024-12-17 10:38:22 +05:30
Frappe PR Bot
4af0365719 fix: Chinese Simplified translations 2024-12-17 10:38:22 +05:30
Frappe PR Bot
30d2a2bce5 fix: Turkish translations 2024-12-17 10:38:22 +05:30
Frappe PR Bot
e82f993d94 fix: Swedish translations 2024-12-17 10:38:22 +05:30
Frappe PR Bot
9e8304c16f fix: Russian translations 2024-12-17 10:38:21 +05:30
Frappe PR Bot
efa00fd9c6 fix: Polish translations 2024-12-17 10:38:21 +05:30
Frappe PR Bot
e90d2c2cfe fix: Hungarian translations 2024-12-17 10:38:21 +05:30
Frappe PR Bot
30735b339d fix: Arabic translations 2024-12-17 10:38:21 +05:30
Frappe PR Bot
7eb7a7fa36 fix: Spanish translations 2024-12-17 10:38:21 +05:30
Frappe PR Bot
0e68c433db fix: French translations 2024-12-17 10:38:21 +05:30
rohitwaghchaure
95da0913f6 fix: unsupported operand type (#44722) 2024-12-17 09:19:58 +05:30
rohitwaghchaure
5f539619bc fix: delink SABB from cancelled SLEs (#44691) 2024-12-16 22:23:13 +05:30
ruthra kumar
5d16e4aefe Merge pull request #44714 from ruthra-kumar/update_readme
chore: update readme
2024-12-16 19:55:39 +05:30
ruthra kumar
ac4ee1b005 chore: more changes
- reduce image count and update hero image
- update docker setup
2024-12-16 19:28:30 +05:30
ruthra kumar
9ebdd4d79a Merge pull request #44713 from ruthra-kumar/ci_trigger
fix: broken CI
2024-12-16 16:52:18 +05:30
ruthra kumar
dc02cb8119 chore: update readme 2024-12-16 16:44:38 +05:30
ruthra kumar
eb1e36ca22 fix: broken CI
- always install wkhtmltopdf
- remove specific version on mariadb-client
2024-12-16 16:27:13 +05:30
ruthra kumar
f8cf1983a4 Merge pull request #44704 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-16 10:45:17 +05:30
venkat102
8338d1d5b4 fix: update discount when pricing rule is changed 2024-12-15 22:55:24 +05:30
Frappe PR Bot
62c553edeb chore: update POT file (#44707) 2024-12-15 12:27:21 +01:00
Frappe PR Bot
37fc2068b5 fix: Persian translations 2024-12-15 12:55:00 +05:30
Frappe PR Bot
15d2ca0c06 fix: Persian translations 2024-12-14 12:54:15 +05:30
Frappe PR Bot
4d34eefde4 fix: Swedish translations 2024-12-14 12:54:09 +05:30
mahsem
73112fa3c9 fix: Swedish tax templates 2024-12-14 07:12:19 +01:00
mahsem
6119d4384a fix: better description of tab name (#44697) 2024-12-13 19:46:31 +01:00
ruthra kumar
4409dadfe2 Merge pull request #44585 from blaggacao/fix/old-data-from-2009-in-migration
fix: migration; make it resilient against old, non-conforming data
2024-12-13 18:22:06 +05:30
ruthra kumar
3a4d8a7bbd Merge pull request #44676 from ljain112/fix-ac-rec-pay,emt-term
fix: remove invalid filter in Account Receivable report
2024-12-13 17:08:41 +05:30
ljain112
578ca230fe fix: remove invalid filter in Account Receivable report 2024-12-13 16:37:19 +05:30
ruthra kumar
d07f9d746a refactor: ignore selective malformed json 2024-12-13 16:00:39 +05:30
Navin R C
48b49cdea4 fix: SQL syntax error in Purchase Receipt query for empty filters (#44636)
fix(po-analysis): handle SQL error due to empty data in IN() clause

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-12-13 10:19:38 +00:00
ruthra kumar
168baae118 Merge pull request #44696 from akhilnarang/add-type-selling-workspace
fix(selling): set workspace type and app
2024-12-13 15:17:06 +05:30
ruthra kumar
693b073088 Merge pull request #44556 from aerele/ledger-summary-report
feat: add accounting dimensions in ledger summary reports
2024-12-13 15:12:18 +05:30
ruthra kumar
2c5b5d4117 Merge pull request #44604 from akhilnarang/drop-pytz-usage
refactor: drop pytz
2024-12-13 15:02:14 +05:30
Akhil Narang
f704ade417 fix(selling): set workspace type and app
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-12-13 14:40:15 +05:30
Khushi Rawat
d8f55923c9 Merge pull request #44690 from khushi8112/handle-zero-salvage-value-case
fix: handle zero salvage value case
2024-12-13 14:31:03 +05:30
ljain112
a626372d66 fix: User permissions in financial statements 2024-12-13 13:46:15 +05:30
Khushi Rawat
325b20491a fix: make rate of depreciation mandatory 2024-12-13 12:36:30 +05:30
Khushi Rawat
d84aeef0bb fix: handle zero salvage value case 2024-12-13 12:31:38 +05:30
ruthra kumar
faa6a3dec0 Merge pull request #43930 from lbrandh/fix_timestrings
fix: use get_datetime_as_string with correct time format
2024-12-13 12:07:56 +05:30
Diógenes Souza
d2cab83003 fix: Wrong allocated_amount for sales_team in gross_profit report (#42989)
* fix: Wrong allocated_amount for sales_team in gross_profit report

* style: Removes whitespaces

---------

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2024-12-13 11:56:55 +05:30
venkat102
91c7e3d5f3 fix: set company bank account if default account not set in mode of payment 2024-12-13 11:22:17 +05:30
Nicolas Pereira
cd693b5fa4 fix: Stock Entry uses incorrect company when generated from Pick List (#44679)
(cherry picked from commit 00898be8e4)
2024-12-13 04:52:54 +00:00
ruthra kumar
63123471b3 Merge pull request #44621 from mahsem/doc.status_POS
fix: add doc.status to translation from POS
2024-12-13 10:22:23 +05:30
ruthra kumar
ecc213b06f Merge pull request #44668 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-13 10:12:57 +05:30
ruthra kumar
b584212edb chore: Update images in readme (#44667)
* chore: image files

* chore: typo and links

* chore: update logo

* chore: link screenshots

* chore: change image width

* chore: border radius for images

* chore: more formatting
2024-12-12 17:09:22 +05:30
rohitwaghchaure
4385349e36 fix: validate returned serial nos and batches (#44669) 2024-12-12 15:24:40 +05:30
Venkatesh
9ef9ff3de8 fix: make projected qty editable after submit (#44670) 2024-12-12 14:56:20 +05:30
Frappe PR Bot
4d12134552 fix: German translations 2024-12-12 12:37:03 +05:30
Frappe PR Bot
7199b6c094 fix: Swedish translations 2024-12-12 12:36:59 +05:30
rohitwaghchaure
15c7d26378 fix: valuation rate for batch in stock reconciliation (#44657)
fix: valuation rate for batch in stock reco
2024-12-11 21:02:38 +05:30
ruthra kumar
033075c023 Merge pull request #44663 from ruthra-kumar/update_readme
chore: update readme
2024-12-11 20:59:44 +05:30
ruthra kumar
4c68fa46e7 chore: use numbered list 2024-12-11 20:33:34 +05:30
ruthra kumar
a793017628 chore: update readme 2024-12-11 20:28:15 +05:30
Smit Vora
56a0a0db18 fix: better indicator base amount for Tax Witholding in Journal Entry 2024-12-11 17:57:47 +05:30
Venkatesh
3595783202 Merge pull request #44533 from aerele/consolidated-gl
Consider against_voucher_no when voucher_no is filtered
2024-12-11 10:32:30 +00:00
ruthra kumar
67ac3a5173 Merge pull request #44651 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-11 14:58:17 +05:30
ruthra kumar
3f4832631f Merge pull request #44493 from aerele/free-item-seperate-row
fix: update free item qty while adding same item in seperate row
2024-12-11 14:53:59 +05:30
ruthra kumar
542d0140f2 Merge pull request #44652 from frappe/ruthra-kumar-patch-1 2024-12-11 12:57:57 +05:30
ruthra kumar
d9408eae44 chore: footer logo 2024-12-11 12:55:41 +05:30
ruthra kumar
644c48ba46 chore: add end tag 2024-12-11 12:51:59 +05:30
ruthra kumar
687894584f chore(readme): update links 2024-12-11 12:46:24 +05:30
ruthra kumar
f03a0d8015 Update README.md 2024-12-11 12:40:53 +05:30
Frappe PR Bot
3a2b805a55 fix: Persian translations 2024-12-11 12:38:28 +05:30
Frappe PR Bot
ae89a81ecb fix: Swedish translations 2024-12-11 12:38:24 +05:30
Sugesh393
79fd881ad5 chore: update variable names 2024-12-11 11:29:21 +05:30
Khushi Rawat
eac3ae5627 Merge pull request #44647 from khushi8112/rename-cost-to-value
fix: switched asset terminology from cost to value
2024-12-11 01:09:26 +05:30
Khushi Rawat
ee9a2952d6 fix: switched asset terminology from cost to value 2024-12-11 00:18:04 +05:30
barredterra
11644241fa feat: validate discount date in payment schedule 2024-12-10 17:23:00 +01:00
ruthra kumar
a7d964212e Merge pull request #44293 from ruthra-kumar/refactor_transaction_js
refactor: move `item_code` reactivity to server-side
2024-12-10 21:12:42 +05:30
barredterra
4d5241486f fix: permissions for marking Quotation as lost 2024-12-10 14:28:22 +01:00
ruthra kumar
1467610109 fix: linter; dont change doc after DB update 2024-12-10 17:48:13 +05:30
ruthra kumar
267d9606f8 refactor(test): disable unwanted dimensions 2024-12-10 17:48:13 +05:30
ruthra kumar
22c1608745 test: assert all reqd are set 2024-12-10 17:48:13 +05:30
ruthra kumar
c97e058bc6 chore: rename and move test file 2024-12-10 17:48:13 +05:30
ruthra kumar
8a710f85e2 refactor: replcate deprecated cur_frm 2024-12-10 17:48:13 +05:30
ruthra kumar
6ea9c0c48d refactor: pass config through boot 2024-12-10 17:48:13 +05:30
ruthra kumar
67b28a7864 refactor: configurable reactivity 2024-12-10 17:48:13 +05:30
ruthra kumar
b21d5934e6 refactor: make it configurable 2024-12-10 17:48:13 +05:30
ruthra kumar
a06a6ccaa6 test: auto-filling of basic details on items 2024-12-10 17:48:13 +05:30
ruthra kumar
5b4987e160 chore: cleanup code 2024-12-10 17:48:13 +05:30
ruthra kumar
364126d2e4 refactor: remove unneccesary 'item' variable 2024-12-10 17:48:13 +05:30
ruthra kumar
d68f30769a refactor: only use 'item_obj' 2024-12-10 17:48:13 +05:30
ruthra kumar
d0153065b0 chore: rename method 2024-12-10 17:48:13 +05:30
ruthra kumar
af580c9977 refactor: dynamic dimension handling and more 2024-12-10 17:48:13 +05:30
ruthra kumar
88e6b572a8 refactor: move remaining logic
Handle internal parties
conversion factor and applying pricing list rate
2024-12-10 17:48:13 +05:30
ruthra kumar
600d92100c refactor: use helper method to fetch item details 2024-12-10 17:48:12 +05:30
ruthra kumar
ce1ee98a12 refactor: moving item code trigger to server side
1 to 1 barebones migration
2024-12-10 17:48:12 +05:30
ruthra kumar
f2783fbb55 Merge pull request #44630 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-10 15:47:29 +05:30
Khushi Rawat
968762cb3e Merge pull request #44631 from khushi8112/salvage-value-precision
fix: precision check for salvage value
2024-12-10 13:38:05 +05:30
Khushi Rawat
da09316d4c fix: precision check for salvage value 2024-12-10 12:54:02 +05:30
Frappe PR Bot
b839663c48 fix: Swedish translations 2024-12-10 12:32:47 +05:30
ruthra kumar
01d1c67869 Merge pull request #44581 from ljain112/fix-drop-ship
fix: allow all dispatch address for drop ship invoice
2024-12-10 10:17:47 +05:30
mahsem
94d7e5964b fix: add doc.status to translation from POS 2024-12-09 16:24:23 +01:00
rohitwaghchaure
f5c038cd1b fix: 'Use Multi-Level BOM' checkbox default value (#44618) 2024-12-09 20:22:51 +05:30
rohitwaghchaure
616bb383c5 fix: do not allow to inward same serial nos multiple times (#44617) 2024-12-09 19:01:33 +05:30
Sugesh393
7614f166d8 refactor: convert sql queries to qb queries 2024-12-09 18:32:45 +05:30
ruthra kumar
6e02e29e4e Merge pull request #44545 from ljain112/fix-pr-adv
fix: only show advance payment entries where "book_advance_payments_in_separate_party_account" is true
2024-12-09 16:25:47 +05:30
ruthra kumar
d847f75ade chore: remove 'debug' param and linter fix 2024-12-09 15:59:40 +05:30
rohitwaghchaure
314c7b8d2a fix: not able to make sales return entry (#44605) 2024-12-09 14:55:47 +05:30
ruthra kumar
2195529c26 Merge pull request #44607 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-09 14:02:32 +05:30
ruthra kumar
f9f8ef0e17 Merge pull request #44513 from ljain112/draft-status-color
fix: correct color for draft in list view
2024-12-09 13:33:48 +05:30
rohitwaghchaure
9ad79625e0 fix: description overwrite on qty change (#44606) 2024-12-09 12:37:36 +05:30
Frappe PR Bot
603ca0963a fix: Turkish translations 2024-12-09 12:35:01 +05:30
Frappe PR Bot
0c18fb575e fix: Swedish translations 2024-12-09 12:34:58 +05:30
ruthra kumar
a08a66df92 Merge pull request #44495 from devdiogenes/prevent-set_payment_schedule-si-return
fix: Prevent set_payment_schedule when creating Sales Invoice that is return
2024-12-09 12:21:04 +05:30
Akhil Narang
af3743f09e refactor: drop pytz
Follow up to https://github.com/frappe/frappe/pull/28093 so I can drop the pytz dependency

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-12-09 11:37:09 +05:30
ruthra kumar
a6aaaa5525 Merge pull request #44582 from mahsem/doc.status
fix: add doc.status for translation
2024-12-09 11:20:46 +05:30
Frappe PR Bot
f0270f69f0 fix: sync translations from crowdin (#44583)
* fix: Swedish translations

* fix: Swedish translations

* fix: French translations

* fix: Spanish translations

* fix: Arabic translations

* fix: Hungarian translations

* fix: Polish translations

* fix: Russian translations

* fix: Swedish translations

* fix: Turkish translations

* fix: Chinese Simplified translations

* fix: Persian translations

* fix: Bosnian translations

* fix: German translations

* fix: Esperanto translations
2024-12-08 19:49:02 +01:00
Frappe PR Bot
426fe96e5f chore: update POT file (#44599) 2024-12-08 11:04:16 +01:00
rohitwaghchaure
42d238da14 fix: BOM has not attr required items (#44598) 2024-12-08 15:28:35 +05:30
rohitwaghchaure
8806d17ef1 fix: currency symbol in SCO and SCR (#44577) 2024-12-07 14:05:36 +05:30
rohitwaghchaure
d871e21a40 fix: BOM name issue (#44586) 2024-12-07 12:20:58 +05:30
David
14a57795d5 fix: migration; make it resilient against old, non-conforming data 2024-12-06 17:52:54 +01:00
rohitwaghchaure
93e9517f5d fix: BOM for variant items (#44580) 2024-12-06 22:14:50 +05:30
mahsem
dda272220b fix: add docstatus for translation 2024-12-06 14:59:16 +01:00
ljain112
125a352bc2 fix: allow all dispatch address for drop ship invoice 2024-12-06 17:41:44 +05:30
rohitwaghchaure
b7a3c6b6ca fix: BOM name issue (#44575)
fix: bom name issue
2024-12-06 16:54:38 +05:30
Raffael Meyer
72256565bb fix(Bank Transaction): error in party matching should not block submitting (#44416) 2024-12-06 10:19:23 +01:00
ruthra kumar
d5a208cf69 Merge pull request #44538 from mahsem/patch-10
fix: add labels for translation in purchase_order_analysis.py
2024-12-06 12:18:43 +05:30
ruthra kumar
cc931d20c2 Merge pull request #44539 from mahsem/patch-11
fix: add labels for translation in production_analytics.py
2024-12-06 12:14:36 +05:30
ruthra kumar
0e38e9417d Merge pull request #44541 from mahsem/patch-12
fix: add labels for translation in quality_inspection_summary.py
2024-12-06 12:13:34 +05:30
ruthra kumar
c116815c14 Merge pull request #44558 from mahsem/patch-4
fix: add string for translation in delayed_tasks_summary.py
2024-12-06 12:12:42 +05:30
ruthra kumar
53d183ae03 Merge pull request #44559 from mahsem/patch-9
fix: add strings for translation payment_terms_status_for_sales_order.py
2024-12-06 12:07:58 +05:30
ruthra kumar
93c75901cf Merge pull request #44560 from mahsem/patch-13
fix: add labels for translation in sales_order_analysis.py
2024-12-06 11:37:54 +05:30
ruthra kumar
e8e13674ef Merge pull request #44557 from frappe/l10n_develop
fix: sync translations from crowdin
2024-12-06 11:32:45 +05:30
Sugesh393
b9f9fc0afe Merge branch 'develop' of https://github.com/aerele/erpnext into ledger-summary-report 2024-12-05 21:34:36 +05:30
mahsem
8a554a5538 fix: add labels for translation in sales_order_analysis.py 2024-12-05 16:40:00 +01:00
mahsem
7d244051c8 fix: add strings for translation payment_terms_status_for_sales_order.py 2024-12-05 16:20:31 +01:00
mahsem
84b54f549a fix: add string for translation in delayed_tasks_summary.py 2024-12-05 16:13:07 +01:00
Frappe PR Bot
c26114b66a fix: Turkish translations 2024-12-05 19:52:53 +05:30
Frappe PR Bot
98da9b56e9 fix: Swedish translations 2024-12-05 19:52:48 +05:30
Sugesh393
9610a33d23 fix: remove irrelavent conditions 2024-12-05 18:51:29 +05:30
Deepesh Garg
1ac292285e chore: Ignore stock validation for non stock invoices (#44549)
* chore: Ignore stock validation for non stock invoices

* chore: Ignore stock validation for non stock invoices
2024-12-05 18:14:23 +05:30
David Arnold
30c3892f9d chore: adapt filter signature to frappe/frappe#28218 (#44553) 2024-12-05 11:32:32 +00:00
rohitwaghchaure
1571dff3ef fix: variant qty while making work order from BOM (#44548) 2024-12-05 15:51:33 +05:30
ljain112
ffd6a8424b fix: only show advance payment entries where "book_advance_payments_in_separate_party_account" is true 2024-12-05 15:18:44 +05:30
mahsem
6ff4704345 fix: add labels for translation in quality_inspection_summary.py 2024-12-05 09:17:35 +01:00
mahsem
9b09116576 fix: add labels for translation in production_analytics.py 2024-12-05 09:02:05 +01:00
mahsem
342a398bec fix: add labels for translation in purchase_order_analysis.py 2024-12-05 08:41:02 +01:00
Sugesh393
901bcd5c43 feat: add accounting dimensions in ledger summary reports 2024-12-05 10:14:15 +05:30
ljain112
143acf2330 fix: correct color for draft in list view 2024-12-04 20:40:08 +05:30
Diógenes Souza
d1dc7ec7bf Merge branch 'frappe:develop' into prevent-set_payment_schedule-si-return 2024-12-03 17:51:03 -03:00
venkat102
329d14957b fix: validate negative qty 2024-12-04 01:08:54 +05:30
venkat102
8bce382834 fix: update free item qty while adding same item in seperate row 2024-12-04 00:56:36 +05:30
lukas.brandhoff
0c83f48f78 fix: use get_datetime_as_string with correct time format 2024-10-30 11:46:21 +00:00
devdiogenes
ac0cb9db5a fix: Prevent set_payment_schedule when creating Sales Invoice that is return 2024-07-26 14:33:42 -03:00
450 changed files with 71920 additions and 56734 deletions

View File

@@ -10,6 +10,7 @@ WEBSITE_REPOS = [
DOCUMENTATION_DOMAINS = [
"docs.erpnext.com",
"docs.frappe.io",
"frappeframework.com",
]

View File

@@ -6,7 +6,7 @@ cd ~ || exit
sudo apt update
sudo apt remove mysql-server mysql-client
sudo apt install libcups2-dev redis-server mariadb-client-10.6
sudo apt install libcups2-dev redis-server mariadb-client
pip install frappe-bench
@@ -51,13 +51,9 @@ fi
install_whktml() {
if [ "$(lsb_release -rs)" = "22.04" ]; then
wget -O /tmp/wkhtmltox.deb https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb
sudo apt install /tmp/wkhtmltox.deb
else
echo "Please update this script to support wkhtmltopdf for $(lsb_release -ds)"
exit 1
fi
wget -O /tmp/wkhtmltox.deb https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb
sudo apt install /tmp/wkhtmltox.deb
}
install_whktml &
wkpid=$!

View File

@@ -133,7 +133,7 @@ jobs:
run: cat ~/frappe-bench/bench_start.log || true
- name: Upload coverage data
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: github.event_name != 'pull_request'
with:
name: coverage-${{ matrix.container }}
@@ -149,7 +149,7 @@ jobs:
uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
- name: Upload coverage data
uses: codecov/codecov-action@v4

164
README.md
View File

@@ -1,57 +1,100 @@
<div align="center">
<a href="https://erpnext.com">
<img src="https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/public/images/erpnext-logo.png" height="128">
<img src="./erpnext/public/images/v16/erpnext.svg" alt="ERPNext Logo" height="80px" width="80xp"/>
</a>
<h2>ERPNext</h2>
<p align="center">
<p>ERP made simple</p>
<p>Powerful, Intuitive and Open-Source ERP</p>
</p>
[![CI](https://github.com/frappe/erpnext/actions/workflows/server-tests-mariadb.yml/badge.svg?event=schedule)](https://github.com/frappe/erpnext/actions/workflows/server-tests-mariadb.yml)
[![Open Source Helpers](https://www.codetriage.com/frappe/erpnext/badges/users.svg)](https://www.codetriage.com/frappe/erpnext)
[![codecov](https://codecov.io/gh/frappe/erpnext/branch/develop/graph/badge.svg?token=0TwvyUg3I5)](https://codecov.io/gh/frappe/erpnext)
[![docker pulls](https://img.shields.io/docker/pulls/frappe/erpnext-worker.svg)](https://hub.docker.com/r/frappe/erpnext-worker)
[https://erpnext.com](https://erpnext.com)
</div>
ERPNext as a monolith includes the following areas for managing businesses:
1. [Accounting](https://erpnext.com/open-source-accounting)
1. [Warehouse Management](https://erpnext.com/distribution/warehouse-management-system)
1. [CRM](https://erpnext.com/open-source-crm)
1. [Sales](https://erpnext.com/open-source-sales-purchase)
1. [Purchase](https://erpnext.com/open-source-sales-purchase)
1. [HRMS](https://erpnext.com/open-source-hrms)
1. [Project Management](https://erpnext.com/open-source-projects)
1. [Support](https://erpnext.com/open-source-help-desk-software)
1. [Asset Management](https://erpnext.com/open-source-asset-management-software)
1. [Quality Management](https://erpnext.com/docs/user/manual/en/quality-management)
1. [Manufacturing](https://erpnext.com/open-source-manufacturing-erp-software)
1. [Website Management](https://erpnext.com/open-source-website-builder-software)
1. [Customize ERPNext](https://erpnext.com/docs/user/manual/en/customize-erpnext)
1. [And More](https://erpnext.com/docs/user/manual/en/)
ERPNext is built on the [Frappe Framework](https://github.com/frappe/frappe), a full-stack web app framework built with Python & JavaScript.
## Installation
<div align="center" style="max-height: 40px;">
<a href="https://frappecloud.com/erpnext/signup">
<img src=".github/try-on-f-cloud-button.svg" height="40">
</a>
<a href="https://labs.play-with-docker.com/?stack=https://raw.githubusercontent.com/frappe/frappe_docker/main/pwd.yml">
<img src="https://raw.githubusercontent.com/play-with-docker/stacks/master/assets/images/button.png" alt="Try in PWD" height="37"/>
</a>
<div align="center">
<img src="./erpnext/public/images/v16/hero_image.png"/>
</div>
> Login for the PWD site: (username: Administrator, password: admin)
<div align="center">
<a href="https://erpnext-demo.frappe.cloud/app/home">Live Demo</a>
-
<a href="https://erpnext.com">Website</a>
-
<a href="https://docs.erpnext.com">Documentation</a>
</div>
### Containerized Installation
## ERPNext
Use docker to deploy ERPNext in production or for development of [Frappe](https://github.com/frappe/frappe) apps. See https://github.com/frappe/frappe_docker for more details.
100% Open-Source ERP system to help you run your business.
### Motivation
Running a business is a complex task - handling invoices, tracking stock, managing personnel and even more ad-hoc activities. In a market where software is sold separately to manage each of these tasks, ERPNext does all of the above and more, for free.
### Key Features
- **Accounting**: All the tools you need to manage cash flow in one place, right from recording transactions to summarizing and analyzing financial reports.
- **Order Management**: Track inventory levels, replenish stock, and manage sales orders, customers, suppliers, shipments, deliverables, and order fulfillment.
- **Manufacturing**: Simplifies the production cycle, helps track material consumption, exhibits capacity planning, handles subcontracting, and more!
- **Asset Management**: From purchase to perishment, IT infrastructure to equipment. Cover every branch of your organization, all in one centralized system.
- **Projects**: Delivery both internal and external Projects on time, budget and Profitability. Track tasks, timesheets, and issues by project.
<details open>
<summary>More</summary>
<img src="https://erpnext.com/files/v16_bom.png"/>
<img src="https://erpnext.com/files/v16_stock_summary.png"/>
<img src="https://erpnext.com/files/v16_job_card.png"/>
<img src="https://erpnext.com/files/v16_tasks.png"/>
</details>
### Under the Hood
- [**Frappe Framework**](https://github.com/frappe/frappe): A full-stack web application framework written in Python and Javascript. The framework provides a robust foundation for building web applications, including a database abstraction layer, user authentication, and a REST API.
- [**Frappe UI**](https://github.com/frappe/frappe-ui): A Vue-based UI library, to provide a modern user interface. The Frappe UI library provides a variety of components that can be used to build single-page applications on top of the Frappe Framework.
## Production Setup
### Managed Hosting
You can try [Frappe Cloud](https://frappecloud.com), a simple, user-friendly and sophisticated [open-source](https://github.com/frappe/press) platform to host Frappe applications with peace of mind.
It takes care of installation, setup, upgrades, monitoring, maintenance and support of your Frappe deployments. It is a fully featured developer platform with an ability to manage and control multiple Frappe deployments.
<div>
<a href="https://erpnext-demo.frappe.cloud/app/home" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://frappe.io/files/try-on-fc-white.png">
<img src="https://frappe.io/files/try-on-fc-black.png" alt="Try on Frappe Cloud" height="28" />
</picture>
</a>
</div>
### Self-Hosted
#### Docker
Prerequisites: docker, docker-compose, git. Refer [Docker Documentation](https://docs.docker.com) for more details on Docker setup.
Run following commands:
```
git clone https://github.com/frappe/frappe_docker
cd frappe_docker
docker compose -f pwd.yml up -d
```
After a couple of minutes, site should be accessible on your localhost port: 8080. Use below default login credentials to access the site.
- Username: Administrator
- Password: admin
See [Frappe Docker](https://github.com/frappe/frappe_docker?tab=readme-ov-file#to-run-on-arm64-architecture-follow-this-instructions) for ARM based docker setup.
## Development Setup
### Manual Install
The Easy Way: our install script for bench will install all dependencies (e.g. MariaDB). See https://github.com/frappe/bench for more details.
@@ -59,6 +102,35 @@ The Easy Way: our install script for bench will install all dependencies (e.g. M
New passwords will be created for the ERPNext "Administrator" user, the MariaDB root user, and the frappe user (the script displays the passwords and saves them to ~/frappe_passwords.txt).
### Local
To setup the repository locally follow the steps mentioned below:
1. Setup bench by following the [Installation Steps](https://frappeframework.com/docs/user/en/installation) and start the server
```
bench start
```
2. In a separate terminal window, run the following commands:
```
# Create a new site
bench new-site erpnext.dev
# Map your site to localhost
bench --site erpnext.dev add-to-hosts
```
3. Get the ERPNext app and install it
```
# Get the ERPNext app
bench get-app https://github.com/frappe/erpnext
# Install the app
bench --site erpnext.dev install-app erpnext
```
4. Open the URL `http://erpnext.dev:8000/app` in your browser, you should see the app running
## Learning and community
1. [Frappe School](https://frappe.school) - Learn Frappe Framework and ERPNext from the various courses by the maintainers or from the community.
@@ -73,14 +145,18 @@ New passwords will be created for the ERPNext "Administrator" user, the MariaDB
1. [Report Security Vulnerabilities](https://erpnext.com/security)
1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Contribution-Guidelines)
## License
GNU/General Public License (see [license.txt](license.txt))
The ERPNext code is licensed as GNU General Public License (v3) and the Documentation is licensed as Creative Commons (CC-BY-SA-3.0) and the copyright is owned by Frappe Technologies Pvt Ltd (Frappe) and Contributors.
By contributing to ERPNext, you agree that your contributions will be licensed under its GNU General Public License (v3).
## Logo and Trademark Policy
Please read our [Logo and Trademark Policy](TRADEMARK_POLICY.md).
<br />
<br />
<div align="center" style="padding-top: 0.75rem;">
<a href="https://frappe.io" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://frappe.io/files/Frappe-white.png">
<img src="https://frappe.io/files/Frappe-black.png" alt="Frappe Technologies" height="28"/>
</picture>
</a>
</div>

View File

@@ -3,6 +3,7 @@
"allow_copy": 1,
"allow_import": 1,
"creation": "2013-01-30 12:49:46",
"default_view": "Tree",
"description": "Heads (or groups) against which Accounting Entries are made and balances are maintained.",
"doctype": "DocType",
"document_type": "Setup",
@@ -131,7 +132,7 @@
"description": "Rate at which this tax is applied",
"fieldname": "tax_rate",
"fieldtype": "Float",
"label": "Rate",
"label": "Tax Rate",
"oldfieldname": "tax_rate",
"oldfieldtype": "Currency"
},
@@ -194,7 +195,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2024-08-19 15:19:11.095045",
"modified": "2025-01-22 10:40:35.766017",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",

View File

@@ -10,6 +10,7 @@ frappe.treeview_settings["Account"] = {
fieldtype: "Select",
options: erpnext.utils.get_tree_options("company"),
label: __("Company"),
render_on_toolbar: true,
default: erpnext.utils.get_tree_default("company"),
on_change: function () {
var me = frappe.treeview_settings["Account"].treeview;
@@ -182,7 +183,9 @@ frappe.treeview_settings["Account"] = {
function () {
frappe.set_route("Tree", "Cost Center", { company: get_company() });
},
__("View")
__("View"),
"default",
true
);
treeview.page.add_inner_button(
@@ -190,31 +193,12 @@ frappe.treeview_settings["Account"] = {
function () {
frappe.set_route("Form", "Opening Invoice Creation Tool", { company: get_company() });
},
__("View")
__("View"),
"default",
true
);
treeview.page.add_inner_button(
__("Period Closing Voucher"),
function () {
frappe.set_route("List", "Period Closing Voucher", { company: get_company() });
},
__("View")
);
treeview.page.add_inner_button(
__("Journal Entry"),
function () {
frappe.new_doc("Journal Entry", { company: get_company() });
},
__("Create")
);
treeview.page.add_inner_button(
__("Company"),
function () {
frappe.new_doc("Company");
},
__("Create")
);
treeview.page.add_divider_to_button_group(__("View"));
// financial statements
for (let report of [
@@ -231,25 +215,28 @@ frappe.treeview_settings["Account"] = {
function () {
frappe.set_route("query-report", report, { company: get_company() });
},
__("Financial Statements")
__("View")
);
}
},
post_render: function (treeview) {
frappe.treeview_settings["Account"].treeview["tree"] = treeview.tree;
treeview.page.set_primary_action(
__("New"),
function () {
let root_company = treeview.page.fields_dict.root_company.get_value();
if (root_company) {
frappe.throw(__("Please add the account to root level Company - {0}"), [root_company]);
} else {
treeview.new_node();
}
},
"add"
);
if (treeview.can_create) {
treeview.page.set_primary_action(
__("New"),
function () {
let root_company = treeview.page.fields_dict.root_company.get_value();
if (root_company) {
frappe.throw(__("Please add the account to root level Company - {0}"), [
root_company,
]);
} else {
treeview.new_node();
}
},
"add"
);
}
},
toolbar: [
{

View File

@@ -0,0 +1,532 @@
{
"country_code": "ch",
"name": "240812 Schulkontenrahmen VEB - DE",
"tree": {
"Aktiven": {
"account_number": "1",
"is_group": 1,
"root_type": "Asset",
"Umlaufvermögen": {
"account_number": "10",
"is_group": 1,
"Flüssige Mittel": {
"account_number": "100",
"is_group": 1,
"Kasse": {
"account_number": "1000",
"account_type": "Cash"
},
"Bankguthaben": {
"account_number": "1020",
"account_type": "Bank"
}
},
"Kurzfristig gehaltene Aktiven mit Börsenkurs": {
"account_number": "106",
"is_group": 1,
"Wertschriften": {
"account_number": "1060"
},
"Wertberichtigungen Wertschriften": {
"account_number": "1069"
}
},
"Forderungen aus Lieferungen und Leistungen": {
"account_number": "110",
"is_group": 1,
"Forderungen aus Lieferungen und Leistungen (Debitoren)": {
"account_number": "1100"
},
"Delkredere": {
"account_number": "1109"
}
},
"Übrige kurzfristige Forderungen": {
"account_number": "114",
"is_group": 1,
"Vorschüsse und Darlehen": {
"account_number": "1140"
},
"Wertberichtigungen Vorschüsse und Darlehen": {
"account_number": "1149"
},
"Vorsteuer MWST Material, Waren, Dienstleistungen, Energie": {
"account_number": "1170"
},
"Vorsteuer MWST Investitionen, übriger Betriebsaufwand": {
"account_number": "1171"
},
"Verrechnungssteuer": {
"account_number": "1176"
},
"Forderungen gegenüber Sozialversicherungen und Vorsorgeeinrichtungen": {
"account_number": "1180"
},
"Quellensteuer": {
"account_number": "1189"
},
"Sonstige kurzfristige Forderungen": {
"account_number": "1190"
},
"Wertberichtigungen sonstige kurzfristige Forderungen": {
"account_number": "1199"
}
},
"Vorräte und nicht fakturierte Dienstleistungen": {
"account_number": "120",
"is_group": 1,
"Handelswaren": {
"account_number": "1200"
},
"Rohstoffe": {
"account_number": "1210"
},
"Werkstoffe": {
"account_number": "1220"
},
"Hilfs- und Verbrauchsmaterial": {
"account_number": "1230"
},
"Handelswaren in Konsignation": {
"account_number": "1250"
},
"Fertige Erzeugnisse": {
"account_number": "1260"
},
"Unfertige Erzeugnisse": {
"account_number": "1270"
},
"Nicht fakturierte Dienstleistungen": {
"account_number": "1280"
}
},
"Aktive Rechnungsabgrenzungen": {
"account_number": "130",
"is_group": 1,
"Bezahlter Aufwand des Folgejahres": {
"account_number": "1300"
},
"Noch nicht erhaltener Ertrag": {
"account_number": "1301"
}
}
},
"Anlagevermögen": {
"account_number": "14",
"is_group": 1,
"Finanzanlagen": {
"account_number": "140",
"is_group": 1,
"Wertschriften": {
"account_number": "1400"
},
"Wertberichtigungen Wertschriften": {
"account_number": "1409"
},
"Darlehen": {
"account_number": "1440"
},
"Hypotheken": {
"account_number": "1441"
},
"Wertberichtigungen langfristige Forderungen": {
"account_number": "1449"
}
},
"Beteiligungen": {
"account_number": "148",
"is_group": 1,
"Beteiligungen": {
"account_number": "1480"
},
"Wertberichtigungen Beteiligungen": {
"account_number": "1489"
}
},
"Mobile Sachanlagen": {
"account_number": "150",
"is_group": 1,
"Maschinen und Apparate": {
"account_number": "1500"
},
"Wertberichtigungen Maschinen und Apparate": {
"account_number": "1509"
},
"Mobiliar und Einrichtungen": {
"account_number": "1510"
},
"Wertberichtigungen Mobiliar und Einrichtungen": {
"account_number": "1519"
},
"Büromaschinen, Informatik, Kommunikationstechnologie": {
"account_number": "1520"
},
"Wertberichtigungen Büromaschinen, Informatik, Kommunikationstechnologie": {
"account_number": "1529"
},
"Fahrzeuge": {
"account_number": "1530"
},
"Wertberichtigungen Fahrzeuge": {
"account_number": "1539"
},
"Werkzeuge und Geräte": {
"account_number": "1540"
},
"Wertberichtigungen Werkzeuge und Geräte": {
"account_number": "1549"
}
},
"Immobile Sachanlagen": {
"account_number": "160",
"is_group": 1,
"Geschäftsliegenschaften": {
"account_number": "1600"
},
"Wertberichtigungen Geschäftsliegenschaften": {
"account_number": "1609"
}
},
"Immaterielle Werte": {
"account_number": "170",
"is_group": 1,
"Patente, Know-how, Lizenzen, Rechte, Entwicklungen": {
"account_number": "1700"
},
"Wertberichtigungen Patente, Know-how, Lizenzen, Rechte, Entwicklungen": {
"account_number": "1709"
},
"Goodwill": {
"account_number": "1770"
},
"Wertberichtigungen Goodwill": {
"account_number": "1779"
}
},
"Nicht einbezahltes Grund-, Gesellschafter- oder Stiftungskapital": {
"account_number": "180",
"is_group": 1,
"Nicht einbezahltes Aktien-, Stamm-, Anteilschein- oder Stiftungskapital": {
"account_number": "1850"
}
}
}
},
"Passiven": {
"account_number": "2",
"is_group": 1,
"root_type": "Liability",
"Kurzfristiges Fremdkapital": {
"account_number": "20",
"is_group": 1,
"Verbindlichkeiten aus Lieferungen und Leistungen": {
"account_number": "200",
"is_group": 1,
"Verbindlichkeiten aus Lieferungen und Leistungen (Kreditoren)": {
"account_number": "2000"
},
"Erhaltene Anzahlungen": {
"account_number": "2030"
}
},
"Kurzfristige verzinsliche Verbindlichkeiten": {
"account_number": "210",
"is_group": 1,
"Bankverbindlichkeiten": {
"account_number": "2100"
},
"Verbindlichkeiten aus Finanzierungsleasing": {
"account_number": "2120"
},
"Übrige verzinsliche Verbindlichkeiten": {
"account_number": "2140"
}
},
"Übrige kurzfristige Verbindlichkeiten": {
"account_number": "220",
"is_group": 1,
"Geschuldete MWST (Umsatzsteuer)": {
"account_number": "2200"
},
"Abrechnungskonto MWST": {
"account_number": "2201"
},
"Verrechnungssteuer": {
"account_number": "2206"
},
"Direkte Steuern": {
"account_number": "2208"
},
"Sonstige kurzfristige Verbindlichkeiten": {
"account_number": "2210"
},
"Beschlossene Ausschüttungen": {
"account_number": "2261"
},
"Sozialversicherungen und Vorsorgeeinrichtungen": {
"account_number": "2270"
},
"Quellensteuer": {
"account_number": "2279"
}
},
"Passive Rechnungsabgrenzungen und kurzfristige Rückstellungen": {
"account_number": "230",
"is_group": 1,
"Noch nicht bezahlter Aufwand": {
"account_number": "2300"
},
"Erhaltener Ertrag des Folgejahres": {
"account_number": "2301"
},
"Kurzfristige Rückstellungen": {
"account_number": "2330"
}
}
},
"Langfristiges Fremdkapital": {
"account_number": "24",
"is_group": 1,
"Langfristige verzinsliche Verbindlichkeiten": {
"account_number": "240",
"is_group": 1,
"Bankverbindlichkeiten": {
"account_number": "2400"
},
"Verbindlichkeiten aus Finanzierungsleasing": {
"account_number": "2420"
},
"Obligationenanleihen": {
"account_number": "2430"
},
"Darlehen": {
"account_number": "2450"
},
"Hypotheken": {
"account_number": "2451"
}
},
"Übrige langfristige Verbindlichkeiten": {
"account_number": "250",
"is_group": 1,
"Übrige langfristige Verbindlichkeiten (unverzinslich)": {
"account_number": "2500"
}
},
"Rückstellungen sowie vom Gesetz vorgesehene ähnliche Positionen": {
"account_number": "260",
"is_group": 1,
"Rückstellungen": {
"account_number": "2600"
}
}
},
"Eigenkapital (juristische Personen)": {
"account_number": "28",
"is_group": 1,
"Grund-, Gesellschafter- oder Stiftungskapital": {
"account_number": "280",
"is_group": 1,
"Aktien-, Stamm-, Anteilschein- oder Stiftungskapital": {
"account_number": "2800"
}
},
"Reserven und Jahresgewinn oder Jahresverlust": {
"account_number": "290",
"is_group": 1,
"Gesetzliche Kapitalreserve": {
"account_number": "2900"
},
"Reserve für eigene Kapitalanteile": {
"account_number": "2930"
},
"Aufwertungsreserve": {
"account_number": "2940"
},
"Gesetzliche Gewinnreserve": {
"account_number": "2950"
},
"Freiwillige Gewinnreserven": {
"account_number": "2960"
},
"Gewinnvortrag oder Verlustvortrag": {
"account_number": "2970"
},
"Jahresgewinn oder Jahresverlust": {
"account_number": "2979"
},
"Eigene Aktien, Stammanteile oder Anteilscheine (Minusposten)": {
"account_number": "2980"
}
}
}
},
"Betrieblicher Ertrag aus Lieferungen und Leistungen": {
"account_number": "3",
"is_group": 1,
"root_type": "Income",
"Produktionserlöse": {
"account_number": "3000"
},
"Handelserlöse": {
"account_number": "3200"
},
"Dienstleistungserlöse": {
"account_number": "3400"
},
"Übrige Erlöse aus Lieferungen und Leistungen": {
"account_number": "3600"
},
"Eigenleistungen": {
"account_number": "3700"
},
"Eigenverbrauch": {
"account_number": "3710"
},
"Erlösminderungen": {
"account_number": "3800"
},
"Verluste Forderungen (Debitoren), Veränderung Delkredere": {
"account_number": "3805"
},
"Bestandesänderungen unfertige Erzeugnisse": {
"account_number": "3900"
},
"Bestandesänderungen fertige Erzeugnisse": {
"account_number": "3901"
},
"Bestandesänderungen nicht fakturierte Dienstleistungen": {
"account_number": "3940"
}
},
"Aufwand für Material, Handelswaren, Dienstleistungen und Energie": {
"account_number": "4",
"is_group": 1,
"root_type": "Expense",
"Materialaufwand Produktion": {
"account_number": "4000"
},
"Handelswarenaufwand": {
"account_number": "4200"
},
"Aufwand für bezogene Dienstleistungen": {
"account_number": "4400"
},
"Energieaufwand zur Leistungserstellung": {
"account_number": "4500"
},
"Aufwandminderungen": {
"account_number": "4900"
}
},
"Personalaufwand": {
"account_number": "5",
"is_group": 1,
"root_type": "Expense",
"Lohnaufwand": {
"account_number": "5000"
},
"Sozialversicherungsaufwand": {
"account_number": "5700"
},
"Übriger Personalaufwand": {
"account_number": "5800"
},
"Leistungen Dritter": {
"account_number": "5900"
}
},
"Übriger betrieblicher Aufwand, Abschreibungen und Wertberichtigungen sowie Finanzergebnis": {
"account_number": "6",
"is_group": 1,
"root_type": "Expense",
"Raumaufwand": {
"account_number": "6000"
},
"Unterhalt, Reparaturen, Ersatz mobile Sachanlagen": {
"account_number": "6100"
},
"Leasingaufwand mobile Sachanlagen": {
"account_number": "6105"
},
"Fahrzeug- und Transportaufwand": {
"account_number": "6200"
},
"Fahrzeugleasing und -mieten": {
"account_number": "6260"
},
"Sachversicherungen, Abgaben, Gebühren, Bewilligungen": {
"account_number": "6300"
},
"Energie- und Entsorgungsaufwand": {
"account_number": "6400"
},
"Verwaltungsaufwand": {
"account_number": "6500"
},
"Informatikaufwand inkl. Leasing": {
"account_number": "6570"
},
"Werbeaufwand": {
"account_number": "6600"
},
"Sonstiger betrieblicher Aufwand": {
"account_number": "6700"
},
"Abschreibungen und Wertberichtigungen auf Positionen des Anlagevermögens": {
"account_number": "6800"
},
"Finanzaufwand": {
"account_number": "6900"
},
"Finanzertrag": {
"account_number": "6950"
}
},
"Betrieblicher Nebenerfolg": {
"account_number": "7",
"is_group": 1,
"root_type": "Income",
"Ertrag Nebenbetrieb": {
"account_number": "7000"
},
"Aufwand Nebenbetrieb": {
"account_number": "7010"
},
"Ertrag betriebliche Liegenschaft": {
"account_number": "7500"
},
"Aufwand betriebliche Liegenschaft": {
"account_number": "7510"
}
},
"Betriebsfremder, ausserordentlicher, einmaliger oder periodenfremder Aufwand und Ertrag": {
"account_number": "8",
"is_group": 1,
"root_type": "Expense",
"Betriebsfremder Aufwand": {
"account_number": "8000"
},
"Betriebsfremder Ertrag": {
"account_number": "8100"
},
"Ausserordentlicher, einmaliger oder periodenfremder Aufwand": {
"account_number": "8500"
},
"Ausserordentlicher, einmaliger oder periodenfremder Ertrag": {
"account_number": "8510"
},
"Direkte Steuern": {
"account_number": "8900"
}
},
"Abschluss": {
"account_number": "9",
"is_group": 1,
"root_type": "Equity",
"Jahresgewinn oder Jahresverlust": {
"account_number": "9200"
}
}
}
}

View File

@@ -31,7 +31,8 @@
"label": "Reference Document Type",
"options": "DocType",
"read_only_depends_on": "eval:!doc.__islocal",
"reqd": 1
"reqd": 1,
"search_index": 1
},
{
"default": "0",

View File

@@ -41,6 +41,11 @@ class AccountingDimension(Document):
self.set_fieldname_and_label()
def validate(self):
self.validate_doctype()
validate_column_name(self.fieldname)
self.validate_dimension_defaults()
def validate_doctype(self):
if self.document_type in (
*core_doctypes_list,
"Accounting Dimension",
@@ -49,6 +54,7 @@ class AccountingDimension(Document):
"Accounting Dimension Detail",
"Company",
"Account",
"Finance Book",
):
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
frappe.throw(msg)
@@ -61,9 +67,6 @@ class AccountingDimension(Document):
if not self.is_new():
self.validate_document_type_change()
validate_column_name(self.fieldname)
self.validate_dimension_defaults()
def validate_document_type_change(self):
doctype_before_save = frappe.db.get_value("Accounting Dimension", self.name, "document_type")
if doctype_before_save != self.document_type:
@@ -102,6 +105,7 @@ class AccountingDimension(Document):
def on_update(self):
frappe.flags.accounting_dimensions = None
frappe.flags.accounting_dimensions_details = None
def make_dimension_in_accounting_doctypes(doc, doclist=None):
@@ -262,7 +266,7 @@ def get_checks_for_pl_and_bs_accounts():
frappe.flags.accounting_dimensions_details = frappe.db.sql(
"""SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs
FROM `tabAccounting Dimension`p ,`tabAccounting Dimension Detail` c
WHERE p.name = c.parent""",
WHERE p.name = c.parent AND p.disabled = 0""",
as_dict=1,
)

View File

@@ -12,7 +12,7 @@ frappe.ui.form.on("Accounts Settings", {
msg += " ";
msg += __("Please enable only if the understand the effects of enabling this.");
msg += "<br>";
msg += "Do you still want to enable immutable ledger?";
msg += __("Do you still want to enable immutable ledger?");
frappe.confirm(
msg,

View File

@@ -40,9 +40,14 @@
"show_payment_schedule_in_print",
"currency_exchange_section",
"allow_stale",
"column_break_yuug",
"stale_days",
"section_break_jpd0",
"auto_reconcile_payments",
"stale_days",
"auto_reconciliation_job_trigger",
"reconciliation_queue_size",
"column_break_resa",
"exchange_gain_loss_posting_date",
"invoicing_settings_tab",
"accounts_transactions_settings_section",
"over_billing_allowance",
@@ -72,6 +77,7 @@
"reports_tab",
"remarks_section",
"general_ledger_remarks_length",
"ignore_is_opening_check_for_reporting",
"column_break_lvjk",
"receivable_payable_remarks_length",
"payment_request_settings",
@@ -384,7 +390,7 @@
{
"fieldname": "section_break_jpd0",
"fieldtype": "Section Break",
"label": "Payment Reconciliations"
"label": "Payment Reconciliation Settings"
},
{
"default": "0",
@@ -489,6 +495,43 @@
"fieldname": "create_pr_in_draft_status",
"fieldtype": "Check",
"label": "Create in Draft Status"
},
{
"fieldname": "column_break_yuug",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_resa",
"fieldtype": "Column Break"
},
{
"default": "15",
"description": "Interval should be between 1 to 59 MInutes",
"fieldname": "auto_reconciliation_job_trigger",
"fieldtype": "Int",
"label": "Auto Reconciliation Job Trigger"
},
{
"default": "5",
"description": "Documents Processed on each trigger. Queue Size should be between 5 and 100",
"fieldname": "reconciliation_queue_size",
"fieldtype": "Int",
"label": "Reconciliation Queue Size"
},
{
"default": "0",
"description": "Ignores legacy Is Opening field in GL Entry that allows adding opening balance post the system is in use while generating reports",
"fieldname": "ignore_is_opening_check_for_reporting",
"fieldtype": "Check",
"label": "Ignore Is Opening check for reporting"
},
{
"default": "Payment",
"description": "Only applies for Normal Payments",
"fieldname": "exchange_gain_loss_posting_date",
"fieldtype": "Select",
"label": "Posting Date Inheritance for Exchange Gain / Loss",
"options": "Invoice\nPayment\nReconciliation Date"
}
],
"icon": "icon-cog",
@@ -496,7 +539,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2024-07-26 06:48:52.714630",
"modified": "2025-01-23 13:15:44.077853",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -10,6 +10,7 @@ from frappe.custom.doctype.property_setter.property_setter import make_property_
from frappe.model.document import Document
from frappe.utils import cint
from erpnext.accounts.utils import sync_auto_reconcile_config
from erpnext.stock.utils import check_pending_reposting
@@ -27,6 +28,7 @@ class AccountsSettings(Document):
allow_multi_currency_invoices_against_single_party_account: DF.Check
allow_stale: DF.Check
auto_reconcile_payments: DF.Check
auto_reconciliation_job_trigger: DF.Int
automatically_fetch_payment_terms: DF.Check
automatically_process_deferred_accounting_entry: DF.Check
book_asset_depreciation_entry_automatically: DF.Check
@@ -43,14 +45,17 @@ class AccountsSettings(Document):
enable_fuzzy_matching: DF.Check
enable_immutable_ledger: DF.Check
enable_party_matching: DF.Check
exchange_gain_loss_posting_date: DF.Literal["Invoice", "Payment", "Reconciliation Date"]
frozen_accounts_modifier: DF.Link | None
general_ledger_remarks_length: DF.Int
ignore_account_closing_balance: DF.Check
ignore_is_opening_check_for_reporting: DF.Check
make_payment_via_journal_entry: DF.Check
merge_similar_account_heads: DF.Check
over_billing_allowance: DF.Currency
post_change_gl_entries: DF.Check
receivable_payable_remarks_length: DF.Int
reconciliation_queue_size: DF.Int
role_allowed_to_over_bill: DF.Link | None
round_row_wise_tax: DF.Check
show_balance_in_coa: DF.Check
@@ -90,6 +95,8 @@ class AccountsSettings(Document):
if clear_cache:
frappe.clear_cache()
self.validate_and_sync_auto_reconcile_config()
def validate_stale_days(self):
if not self.allow_stale and cint(self.stale_days) <= 0:
frappe.msgprint(
@@ -114,3 +121,17 @@ class AccountsSettings(Document):
def validate_pending_reposts(self):
if self.acc_frozen_upto:
check_pending_reposting(self.acc_frozen_upto)
def validate_and_sync_auto_reconcile_config(self):
if self.has_value_changed("auto_reconciliation_job_trigger"):
if (
cint(self.auto_reconciliation_job_trigger) > 0
and cint(self.auto_reconciliation_job_trigger) < 60
):
sync_auto_reconcile_config(self.auto_reconciliation_job_trigger)
else:
frappe.throw(_("Cron Interval should be between 1 and 59 Min"))
if self.has_value_changed("reconciliation_queue_size"):
if cint(self.reconciliation_queue_size) < 5 or cint(self.reconciliation_queue_size) > 100:
frappe.throw(_("Queue Size should be between 5 and 100"))

View File

@@ -104,7 +104,7 @@
"fieldname": "rate",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Rate",
"label": "Tax Rate",
"oldfieldname": "rate",
"oldfieldtype": "Currency"
},

View File

@@ -48,7 +48,7 @@ class BankAccount(Document):
self.name = self.account_name + " - " + self.bank
def on_trash(self):
delete_contact_and_address("BankAccount", self.name)
delete_contact_and_address("Bank Account", self.name)
def validate(self):
self.validate_company()

View File

@@ -6,7 +6,7 @@ import frappe
from frappe import _, msgprint
from frappe.model.document import Document
from frappe.query_builder.custom import ConstantColumn
from frappe.utils import flt, fmt_money, get_link_to_form, getdate
from frappe.utils import cint, flt, fmt_money, get_link_to_form, getdate
from pypika import Order
import erpnext
@@ -48,6 +48,7 @@ class BankClearance(Document):
entries = []
# get entries from all the apps
precision = cint(frappe.db.get_default("currency_precision")) or 2
for method_name in frappe.get_hooks("get_payment_entries_for_bank_clearance"):
entries += (
frappe.get_attr(method_name)(
@@ -77,7 +78,7 @@ class BankClearance(Document):
if not d.get("account_currency"):
d.account_currency = default_currency
formatted_amount = fmt_money(abs(amount), 2, d.account_currency)
formatted_amount = fmt_money(abs(amount), precision, d.account_currency)
d.amount = formatted_amount + " " + (_("Dr") if amount > 0 else _("Cr"))
d.posting_date = getdate(d.posting_date)
@@ -117,9 +118,9 @@ class BankClearance(Document):
)
else:
frappe.db.set_value(
d.payment_document, d.payment_entry, "clearance_date", d.clearance_date
)
# 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)
clearance_date_updated = True

View File

@@ -19,10 +19,15 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
},
onload: function (frm) {
if (!frm.doc.company) {
frm.set_value("company", frappe.defaults.get_default("company"));
}
// Set default filter dates
let today = frappe.datetime.get_today();
frm.doc.bank_statement_from_date = frappe.datetime.add_months(today, -1);
frm.doc.bank_statement_to_date = today;
frm.trigger("bank_account");
},
@@ -98,7 +103,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
make_reconciliation_tool(frm) {
frm.get_field("reconciliation_tool_cards").$wrapper.empty();
if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
if (frm.doc.company && frm.doc.bank_account && frm.doc.bank_statement_to_date) {
frm.trigger("get_cleared_balance").then(() => {
if (
frm.doc.bank_account &&
@@ -114,12 +119,13 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
},
get_account_opening_balance(frm) {
if (frm.doc.bank_account && frm.doc.bank_statement_from_date) {
if (frm.doc.company && frm.doc.bank_account && frm.doc.bank_statement_from_date) {
frappe.call({
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
args: {
bank_account: frm.doc.bank_account,
till_date: frappe.datetime.add_days(frm.doc.bank_statement_from_date, -1),
company: frm.doc.company,
},
callback: (response) => {
frm.set_value("account_opening_balance", response.message);
@@ -129,12 +135,13 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
},
get_cleared_balance(frm) {
if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
if (frm.doc.company && frm.doc.bank_account && frm.doc.bank_statement_to_date) {
return frappe.call({
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
args: {
bank_account: frm.doc.bank_account,
till_date: frm.doc.bank_statement_to_date,
company: frm.doc.company,
},
callback: (response) => {
frm.cleared_balance = response.message;

View File

@@ -12,6 +12,7 @@ from frappe.utils import cint, flt
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount
from erpnext.accounts.party import get_party_account
from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import (
get_amounts_not_reflected_in_system,
get_entries,
@@ -78,10 +79,17 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None):
@frappe.whitelist()
def get_account_balance(bank_account, till_date):
def get_account_balance(bank_account, till_date, company):
# returns account balance till the specified date
account = frappe.db.get_value("Bank Account", bank_account, "account")
filters = frappe._dict({"account": account, "report_date": till_date, "include_pos_transactions": 1})
filters = frappe._dict(
{
"account": account,
"report_date": till_date,
"include_pos_transactions": 1,
"company": company,
}
)
data = get_entries(filters)
balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
@@ -93,11 +101,7 @@ def get_account_balance(bank_account, till_date):
amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
bank_bal = (
flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) + amounts_not_reflected_in_system
)
return bank_bal
return flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) + amounts_not_reflected_in_system
@frappe.whitelist()
@@ -304,54 +308,56 @@ def create_payment_entry_bts(
bank_transaction = frappe.db.get_values(
"Bank Transaction",
bank_transaction_name,
fieldname=["name", "unallocated_amount", "deposit", "bank_account"],
fieldname=["name", "unallocated_amount", "deposit", "bank_account", "currency"],
as_dict=True,
)[0]
paid_amount = bank_transaction.unallocated_amount
payment_type = "Receive" if bank_transaction.deposit > 0.0 else "Pay"
company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
company = frappe.get_value("Account", company_account, "company")
payment_entry_dict = {
"company": company,
"payment_type": payment_type,
"reference_no": reference_number,
"reference_date": reference_date,
"party_type": party_type,
"party": party,
"posting_date": posting_date,
"paid_amount": paid_amount,
"received_amount": paid_amount,
}
payment_entry = frappe.new_doc("Payment Entry")
bank_account = frappe.get_cached_value("Bank Account", bank_transaction.bank_account, "account")
company = frappe.get_cached_value("Account", bank_account, "company")
party_account = get_party_account(party_type, party, company)
payment_entry.update(payment_entry_dict)
bank_currency = bank_transaction.currency
party_currency = frappe.get_cached_value("Account", party_account, "account_currency")
if mode_of_payment:
payment_entry.mode_of_payment = mode_of_payment
if project:
payment_entry.project = project
if cost_center:
payment_entry.cost_center = cost_center
if payment_type == "Receive":
payment_entry.paid_to = company_account
else:
payment_entry.paid_from = company_account
exc_rate = get_exchange_rate(bank_currency, party_currency, posting_date)
payment_entry.validate()
amt_in_bank_acc_currency = bank_transaction.unallocated_amount
amount_in_party_currency = bank_transaction.unallocated_amount * exc_rate
pe = frappe.new_doc("Payment Entry")
pe.payment_type = payment_type
pe.company = company
pe.reference_no = reference_number
pe.reference_date = reference_date
pe.party_type = party_type
pe.party = party
pe.posting_date = posting_date
pe.paid_from = party_account if payment_type == "Receive" else bank_account
pe.paid_to = party_account if payment_type == "Pay" else bank_account
pe.paid_from_account_currency = party_currency if payment_type == "Receive" else bank_currency
pe.paid_to_account_currency = party_currency if payment_type == "Pay" else bank_currency
pe.paid_amount = amount_in_party_currency if payment_type == "Receive" else amt_in_bank_acc_currency
pe.received_amount = amount_in_party_currency if payment_type == "Pay" else amt_in_bank_acc_currency
pe.mode_of_payment = mode_of_payment
pe.project = project
pe.cost_center = cost_center
pe.validate()
if allow_edit:
return payment_entry
return pe
payment_entry.insert()
pe.insert()
pe.submit()
payment_entry.submit()
vouchers = json.dumps(
[
{
"payment_doctype": "Payment Entry",
"payment_name": payment_entry.name,
"amount": paid_amount,
"payment_name": pe.name,
"amount": amt_in_bank_acc_currency,
}
]
)
@@ -480,8 +486,12 @@ def get_linked_payments(
def subtract_allocations(gl_account, vouchers):
"Look up & subtract any existing Bank Transaction allocations"
copied = []
voucher_docs = [(voucher.get("doctype"), voucher.get("name")) for voucher in vouchers]
voucher_allocated_amounts = get_total_allocated_amount(voucher_docs)
for voucher in vouchers:
rows = get_total_allocated_amount(voucher.get("doctype"), voucher.get("name"))
rows = voucher_allocated_amounts.get((voucher.get("doctype"), voucher.get("name"))) or []
filtered_row = list(filter(lambda row: row.get("gl_account") == gl_account, rows))
if amount := None if not filtered_row else filtered_row[0]["total"]:
@@ -719,7 +729,7 @@ def get_pe_matching_query(
(ref_rank + amount_rank + party_rank + 1).as_("rank"),
ConstantColumn("Payment Entry").as_("doctype"),
pe.name,
pe.paid_amount_after_tax.as_("paid_amount"),
pe.base_paid_amount_after_tax.as_("paid_amount"),
pe.reference_no,
pe.reference_date,
pe.party,
@@ -792,7 +802,6 @@ def get_je_matching_query(
.where(je.clearance_date.isnull())
.where(jea.account == common_filters.bank_account)
.where(amount_equality if exact_match else getattr(jea, amount_field) > 0.0)
.where(je.docstatus == 1)
.where(filter_by_date)
.orderby(je.cheque_date if cint(filter_by_reference_date) else je.posting_date)
)

View File

@@ -99,9 +99,9 @@ class BankStatementImport(DataImport):
template_options=self.template_options,
now=run_now,
)
return True
return job_id
return False
return None
@frappe.whitelist()
@@ -113,7 +113,8 @@ def get_preview_from_template(data_import, import_file=None, google_sheets_url=N
@frappe.whitelist()
def form_start_import(data_import):
return frappe.get_doc("Bank Statement Import", data_import).start_import()
job_id = frappe.get_doc("Bank Statement Import", data_import).start_import()
return job_id is not None
@frappe.whitelist()

View File

@@ -45,45 +45,41 @@ class AutoMatchbyAccountIBAN:
if not (self.bank_party_account_number or self.bank_party_iban):
return None
result = self.match_account_in_party()
return result
return self.match_account_in_party()
def match_account_in_party(self) -> tuple | None:
"""Check if there is a IBAN/Account No. match in Customer/Supplier/Employee"""
result = None
parties = get_parties_in_order(self.deposit)
or_filters = self.get_or_filters()
"""
Returns (Party Type, Party) if a matching account is found in Bank Account or Employee:
1. Get party from a matching (iban/account no) Bank Account
2. If not found, get party from Employee with matching bank account details (iban/account no)
"""
if not (self.bank_party_account_number or self.bank_party_iban):
# Nothing to match
return None
for party in parties:
party_result = frappe.db.get_all(
"Bank Account", or_filters=or_filters, pluck="party", limit_page_length=1
)
# Search for a matching Bank Account that has party set
party_result = frappe.db.get_all(
"Bank Account",
or_filters=self.get_or_filters(),
filters={"party_type": ("is", "set"), "party": ("is", "set")},
fields=["party", "party_type"],
limit_page_length=1,
)
if result := party_result[0] if party_result else None:
return (result["party_type"], result["party"])
if party == "Employee" and not party_result:
# Search in Bank Accounts first for Employee, and then Employee record
if "bank_account_no" in or_filters:
or_filters["bank_ac_no"] = or_filters.pop("bank_account_no")
# If no party is found, search in Employee (since it has bank account details)
if employee_result := frappe.db.get_all(
"Employee", or_filters=self.get_or_filters("Employee"), pluck="name", limit_page_length=1
):
return ("Employee", employee_result[0])
party_result = frappe.db.get_all(
party, or_filters=or_filters, pluck="name", limit_page_length=1
)
if "bank_ac_no" in or_filters:
or_filters["bank_account_no"] = or_filters.pop("bank_ac_no")
if party_result:
result = (
party,
party_result[0],
)
break
return result
def get_or_filters(self) -> dict:
def get_or_filters(self, party: str | None = None) -> dict:
"""Return OR filters for Bank Account and IBAN"""
or_filters = {}
if self.bank_party_account_number:
or_filters["bank_account_no"] = self.bank_party_account_number
bank_ac_field = "bank_ac_no" if party == "Employee" else "bank_account_no"
or_filters[bank_ac_field] = self.bank_party_account_number
if self.bank_party_iban:
or_filters["iban"] = self.bank_party_iban
@@ -103,8 +99,7 @@ class AutoMatchbyPartyNameDescription:
if not (self.bank_party_name or self.description):
return None
result = self.match_party_name_desc_in_party()
return result
return self.match_party_name_desc_in_party()
def match_party_name_desc_in_party(self) -> tuple | None:
"""Fuzzy search party name and/or description against parties in the system"""
@@ -113,7 +108,7 @@ class AutoMatchbyPartyNameDescription:
for party in parties:
filters = {"status": "Active"} if party == "Employee" else {"disabled": 0}
field = party.lower() + "_name"
field = f"{party.lower()}_name"
names = frappe.get_all(party, filters=filters, fields=[f"{field} as party_name", "name"])
for field in ["bank_party_name", "description"]:
@@ -140,13 +135,7 @@ class AutoMatchbyPartyNameDescription:
)
party_name, skip = self.process_fuzzy_result(result)
if not party_name:
return None, skip
return (
party,
party_name,
), skip
return ((party, party_name), skip) if party_name else (None, skip)
def process_fuzzy_result(self, result: list | None):
"""
@@ -164,8 +153,8 @@ class AutoMatchbyPartyNameDescription:
if len(result) == 1:
return (first_result[PARTY_ID] if first_result[SCORE] > CUTOFF else None), True
second_result = result[1]
if first_result[SCORE] > CUTOFF:
second_result = result[1]
# If multiple matches with the same score, return None but discontinue matching
# Matches were found but were too close to distinguish between
if first_result[SCORE] == second_result[SCORE]:
@@ -177,8 +166,8 @@ class AutoMatchbyPartyNameDescription:
def get_parties_in_order(deposit: float) -> list:
parties = ["Supplier", "Employee", "Customer"] # most -> least likely to receive
if flt(deposit) > 0:
parties = ["Customer", "Supplier", "Employee"] # most -> least likely to pay
return parties
return (
["Customer", "Supplier", "Employee"] # most -> least likely to pay us
if flt(deposit) > 0
else ["Supplier", "Employee", "Customer"] # most -> least likely to receive from us
)

View File

@@ -154,10 +154,16 @@ class BankTransaction(Document):
"""
remaining_amount = self.unallocated_amount
to_remove = []
payment_entry_docs = [(pe.payment_document, pe.payment_entry) for pe in self.payment_entries]
pe_bt_allocations = get_total_allocated_amount(payment_entry_docs)
for payment_entry in self.payment_entries:
if payment_entry.allocated_amount == 0.0:
unallocated_amount, should_clear, latest_transaction = get_clearance_details(
self, payment_entry
self,
payment_entry,
pe_bt_allocations.get((payment_entry.payment_document, payment_entry.payment_entry))
or [],
)
if 0.0 == unallocated_amount:
@@ -208,13 +214,17 @@ class BankTransaction(Document):
if self.party_type and self.party:
return
result = AutoMatchParty(
bank_party_account_number=self.bank_party_account_number,
bank_party_iban=self.bank_party_iban,
bank_party_name=self.bank_party_name,
description=self.description,
deposit=self.deposit,
).match()
result = None
try:
result = AutoMatchParty(
bank_party_account_number=self.bank_party_account_number,
bank_party_iban=self.bank_party_iban,
bank_party_name=self.bank_party_name,
description=self.description,
deposit=self.deposit,
).match()
except Exception:
frappe.log_error(title=_("Error in party matching for Bank Transaction {0}").format(self.name))
if not result:
return
@@ -228,7 +238,7 @@ def get_doctypes_for_bank_reconciliation():
return frappe.get_hooks("bank_reconciliation_doctypes")
def get_clearance_details(transaction, payment_entry):
def get_clearance_details(transaction, payment_entry, bt_allocations):
"""
There should only be one bank gle for a voucher.
Could be none for a Bank Transaction.
@@ -237,7 +247,6 @@ def get_clearance_details(transaction, payment_entry):
"""
gl_bank_account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
gles = get_related_bank_gl_entries(payment_entry.payment_document, payment_entry.payment_entry)
bt_allocations = get_total_allocated_amount(payment_entry.payment_document, payment_entry.payment_entry)
unallocated_amount = min(
transaction.unallocated_amount,
@@ -290,44 +299,52 @@ def get_related_bank_gl_entries(doctype, docname):
)
def get_total_allocated_amount(doctype, docname):
def get_total_allocated_amount(docs):
"""
Gets the sum of allocations for a voucher on each bank GL account
along with the latest bank transaction name & date
NOTE: query may also include just saved vouchers/payments but with zero allocated_amount
"""
if not docs:
return {}
# nosemgrep: frappe-semgrep-rules.rules.frappe-using-db-sql
result = frappe.db.sql(
"""
SELECT total, latest_name, latest_date, gl_account FROM (
SELECT total, latest_name, latest_date, gl_account, payment_document, payment_entry FROM (
SELECT
ROW_NUMBER() OVER w AS rownum,
SUM(btp.allocated_amount) OVER(PARTITION BY ba.account) AS total,
SUM(btp.allocated_amount) OVER(PARTITION BY ba.account, btp.payment_document, btp.payment_entry) AS total,
FIRST_VALUE(bt.name) OVER w AS latest_name,
FIRST_VALUE(bt.date) OVER w AS latest_date,
ba.account AS gl_account
ba.account AS gl_account,
btp.payment_document,
btp.payment_entry
FROM
`tabBank Transaction Payments` btp
LEFT JOIN `tabBank Transaction` bt ON bt.name=btp.parent
LEFT JOIN `tabBank Account` ba ON ba.name=bt.bank_account
WHERE
btp.payment_document = %(doctype)s
AND btp.payment_entry = %(docname)s
(btp.payment_document, btp.payment_entry) IN %(docs)s
AND bt.docstatus = 1
WINDOW w AS (PARTITION BY ba.account ORDER BY bt.date desc)
WINDOW w AS (PARTITION BY ba.account, btp.payment_document, btp.payment_entry ORDER BY bt.date DESC)
) temp
WHERE
rownum = 1
""",
dict(doctype=doctype, docname=docname),
dict(docs=docs),
as_dict=True,
)
payment_allocation_details = {}
for row in result:
# Why is this *sometimes* a byte string?
if isinstance(row["latest_name"], bytes):
row["latest_name"] = row["latest_name"].decode()
row["latest_date"] = frappe.utils.getdate(row["latest_date"])
return result
payment_allocation_details.setdefault((row["payment_document"], row["payment_entry"]), []).append(row)
return payment_allocation_details
def get_paid_amount(payment_entry, currency, gl_bank_account):

View File

@@ -490,13 +490,20 @@ def get_actual_expense(args):
def get_accumulated_monthly_budget(monthly_distribution, posting_date, fiscal_year, annual_budget):
distribution = {}
if monthly_distribution:
for d in frappe.db.sql(
"""select mdp.month, mdp.percentage_allocation
from `tabMonthly Distribution Percentage` mdp, `tabMonthly Distribution` md
where mdp.parent=md.name and md.fiscal_year=%s""",
fiscal_year,
as_dict=1,
):
mdp = frappe.qb.DocType("Monthly Distribution Percentage")
md = frappe.qb.DocType("Monthly Distribution")
res = (
frappe.qb.from_(mdp)
.join(md)
.on(mdp.parent == md.name)
.select(mdp.month, mdp.percentage_allocation)
.where(md.fiscal_year == fiscal_year)
.where(md.name == monthly_distribution)
.run(as_dict=True)
)
for d in res:
distribution.setdefault(d.month, d.percentage_allocation)
dt = frappe.get_cached_value("Fiscal Year", fiscal_year, "year_start_date")

View File

@@ -3,6 +3,7 @@
"allow_copy": 1,
"allow_import": 1,
"creation": "2013-01-23 19:57:17",
"default_view": "Tree",
"description": "Track separate Income and Expense for product verticals or divisions.",
"doctype": "DocType",
"document_type": "Setup",
@@ -125,7 +126,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2024-04-24 10:55:54.083042",
"modified": "2025-01-22 10:46:42.904001",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",

View File

@@ -13,7 +13,11 @@ import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_checks_for_pl_and_bs_accounts,
)
from erpnext.accounts.party import validate_party_frozen_disabled, validate_party_gle_currency
from erpnext.accounts.party import (
validate_account_party_type,
validate_party_frozen_disabled,
validate_party_gle_currency,
)
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
from erpnext.exceptions import InvalidAccountCurrency
@@ -125,7 +129,7 @@ class GLEntry(Document):
if not self.get(k):
frappe.throw(_("{0} is required").format(_(self.meta.get_label(k))))
if not (self.party_type and self.party):
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(
@@ -268,8 +272,12 @@ class GLEntry(Document):
def validate_party(self):
validate_party_frozen_disabled(self.party_type, self.party)
validate_account_party_type(self)
def validate_currency(self):
if self.is_cancelled:
return
company_currency = erpnext.get_company_currency(self.company)
account_currency = get_account_currency(self.account)

View File

@@ -78,3 +78,65 @@ class TestGLEntry(IntegrationTestCase):
"SELECT current from tabSeries where name = %s", naming_series
)[0][0]
self.assertEqual(old_naming_series_current_value + 2, new_naming_series_current_value)
def test_validate_account_party_type(self):
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC",
100,
"_Test Cost Center - _TC",
save=False,
submit=False,
)
for row in jv.accounts:
row.party_type = "Supplier"
break
jv.save()
try:
jv.submit()
except Exception as e:
self.assertEqual(
str(e),
"Party Type and Party can only be set for Receivable / Payable account_Test Account Cost for Goods Sold - _TC",
)
jv1 = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC",
100,
"_Test Cost Center - _TC",
save=False,
submit=False,
)
for row in jv.accounts:
row.party_type = "Customer"
break
jv1.save()
try:
jv1.submit()
except Exception as e:
self.assertEqual(
str(e),
"Party Type and Party can only be set for Receivable / Payable account_Test Account Cost for Goods Sold - _TC",
)
def test_validate_account_party_type_shareholder(self):
jv = make_journal_entry(
"Opening Balance Equity - _TC",
"Cash - _TC",
100,
"_Test Cost Center - _TC",
save=False,
submit=False,
)
for row in jv.accounts:
row.party_type = "Shareholder"
break
jv.save().submit()
self.assertEqual(1, jv.docstatus)

View File

@@ -430,12 +430,6 @@ frappe.ui.form.on("Journal Entry Account", {
});
}
},
cost_center: function (frm, dt, dn) {
// Don't reset for Gain/Loss type journals, as it will make Debit and Credit values '0'
if (frm.doc.voucher_type != "Exchange Gain Or Loss") {
erpnext.journal_entry.set_account_details(frm, dt, dn);
}
},
account: function (frm, dt, dn) {
erpnext.journal_entry.set_account_details(frm, dt, dn);

View File

@@ -154,10 +154,9 @@ class TestJournalEntry(IntegrationTestCase):
"credit_in_account_currency": 0 if diff > 0 else abs(diff),
},
)
jv.insert()
if account_bal == stock_bal:
self.assertRaises(StockAccountInvalidTransaction, jv.submit)
self.assertRaises(StockAccountInvalidTransaction, jv.save)
frappe.db.rollback()
else:
jv.submit()

View File

@@ -11,6 +11,7 @@ from frappe.utils.background_jobs import enqueue, is_job_enqueued
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
)
from erpnext.stock.utils import get_default_stock_uom
class OpeningInvoiceCreationTool(Document):
@@ -172,7 +173,7 @@ class OpeningInvoiceCreationTool(Document):
income_expense_account_field = (
"income_account" if row.party_type == "Customer" else "expense_account"
)
default_uom = frappe.db.get_single_value("Stock Settings", "stock_uom") or "Nos"
default_uom = get_default_stock_uom()
rate = flt(row.outstanding_amount) / flt(row.qty)
item_dict = frappe._dict(

View File

@@ -27,6 +27,18 @@ frappe.ui.form.on("Payment Entry", {
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
// project excluded in setup_dimension_filters
frm.set_query("project", function (doc) {
let filters = {
company: doc.company,
};
if (doc.party_type == "Customer") filters.customer = doc.party;
return {
query: "erpnext.controllers.queries.get_project_name",
filters,
};
});
if (frm.is_new()) {
set_default_party_type(frm);
}
@@ -362,7 +374,6 @@ frappe.ui.form.on("Payment Entry", {
frm.set_df_property("total_allocated_amount", "options", currency_field);
frm.set_df_property("unallocated_amount", "options", currency_field);
frm.set_df_property("total_taxes_and_charges", "options", currency_field);
frm.set_df_property("party_balance", "options", currency_field);
frm.set_currency_labels(
["total_amount", "outstanding_amount", "allocated_amount"],
@@ -410,15 +421,7 @@ frappe.ui.form.on("Payment Entry", {
if (frm.doc.payment_type == "Internal Transfer") {
$.each(
[
"party",
"party_type",
"party_balance",
"paid_from",
"paid_to",
"references",
"total_allocated_amount",
],
["party", "party_type", "paid_from", "paid_to", "references", "total_allocated_amount"],
function (i, field) {
frm.set_value(field, null);
}
@@ -466,13 +469,10 @@ frappe.ui.form.on("Payment Entry", {
$.each(
[
"party",
"party_balance",
"paid_from",
"paid_to",
"paid_from_account_currency",
"paid_from_account_balance",
"paid_to_account_currency",
"paid_to_account_balance",
"references",
"total_allocated_amount",
],
@@ -517,17 +517,14 @@ frappe.ui.form.on("Payment Entry", {
"paid_from_account_currency",
r.message.party_account_currency
);
frm.set_value("paid_from_account_balance", r.message.account_balance);
} else if (frm.doc.payment_type == "Pay") {
frm.set_value("paid_to", r.message.party_account);
frm.set_value(
"paid_to_account_currency",
r.message.party_account_currency
);
frm.set_value("paid_to_account_balance", r.message.account_balance);
}
},
() => frm.set_value("party_balance", r.message.party_balance),
() => frm.set_value("party_name", r.message.party_name),
() => frm.clear_table("references"),
() => frm.events.hide_unhide_fields(frm),
@@ -579,7 +576,6 @@ frappe.ui.form.on("Payment Entry", {
frm,
frm.doc.paid_from,
"paid_from_account_currency",
"paid_from_account_balance",
function (frm) {
if (frm.doc.payment_type == "Pay") {
frm.events.paid_amount(frm);
@@ -595,7 +591,6 @@ frappe.ui.form.on("Payment Entry", {
frm,
frm.doc.paid_to,
"paid_to_account_currency",
"paid_to_account_balance",
function (frm) {
if (frm.doc.payment_type == "Receive") {
if (frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
@@ -611,13 +606,7 @@ frappe.ui.form.on("Payment Entry", {
);
},
set_account_currency_and_balance: function (
frm,
account,
currency_field,
balance_field,
callback_function
) {
set_account_currency_and_balance: function (frm, account, currency_field, callback_function) {
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
if (frm.doc.posting_date && account) {
frappe.call({
@@ -632,8 +621,6 @@ frappe.ui.form.on("Payment Entry", {
frappe.run_serially([
() => frm.set_value(currency_field, r.message["account_currency"]),
() => {
frm.set_value(balance_field, r.message["account_balance"]);
if (
frm.doc.payment_type == "Receive" &&
currency_field == "paid_to_account_currency"
@@ -800,27 +787,41 @@ frappe.ui.form.on("Payment Entry", {
paid_amount: function (frm) {
frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate));
let company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
if (!frm.doc.received_amount) {
if (frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
frm.set_value("received_amount", frm.doc.paid_amount);
} else if (company_currency == frm.doc.paid_to_account_currency) {
frm.set_value("received_amount", frm.doc.base_paid_amount);
frm.set_value("base_received_amount", frm.doc.base_paid_amount);
}
}
frm.trigger("reset_received_amount");
frm.events.hide_unhide_fields(frm);
},
received_amount: function (frm) {
let company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
frm.set_paid_amount_based_on_received_amount = true;
if (!frm.doc.paid_amount && frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
frm.set_value("paid_amount", frm.doc.received_amount);
if (frm.doc.target_exchange_rate) {
frm.set_value("source_exchange_rate", frm.doc.target_exchange_rate);
}
frm.set_value("base_paid_amount", frm.doc.base_received_amount);
}
frm.set_value(
"base_received_amount",
flt(frm.doc.received_amount) * flt(frm.doc.target_exchange_rate)
);
if (!frm.doc.paid_amount) {
if (frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
frm.set_value("paid_amount", frm.doc.received_amount);
if (frm.doc.target_exchange_rate) {
frm.set_value("source_exchange_rate", frm.doc.target_exchange_rate);
}
frm.set_value("base_paid_amount", frm.doc.base_received_amount);
} else if (company_currency == frm.doc.paid_from_account_currency) {
frm.set_value("paid_amount", frm.doc.base_received_amount);
frm.set_value("base_paid_amount", frm.doc.base_received_amount);
}
}
if (frm.doc.payment_type == "Pay")
frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.received_amount, true);
else frm.events.set_unallocated_amount(frm);
@@ -1328,6 +1329,24 @@ frappe.ui.form.on("Payment Entry", {
if (r.message) {
if (!frm.doc.mode_of_payment) {
frm.set_value(field, r.message.account);
} else {
frappe.call({
method: "frappe.client.get_value",
args: {
doctype: "Mode of Payment Account",
filters: {
parent: frm.doc.mode_of_payment,
company: frm.doc.company,
},
fieldname: "default_account",
parent: "Mode of Payment",
},
callback: function (res) {
if (!res.message.default_account) {
frm.set_value(field, r.message.account);
}
},
});
}
frm.set_value("bank", r.message.bank);
frm.set_value("bank_account_no", r.message.bank_account_no);
@@ -1640,37 +1659,6 @@ frappe.ui.form.on("Payment Entry", {
return current_tax_amount;
},
cost_center: function (frm) {
if (frm.doc.posting_date && (frm.doc.paid_from || frm.doc.paid_to)) {
return frappe.call({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_party_and_account_balance",
args: {
company: frm.doc.company,
date: frm.doc.posting_date,
paid_from: frm.doc.paid_from,
paid_to: frm.doc.paid_to,
ptype: frm.doc.party_type,
pty: frm.doc.party,
cost_center: frm.doc.cost_center,
},
callback: function (r, rt) {
if (r.message) {
frappe.run_serially([
() => {
frm.set_value(
"paid_from_account_balance",
r.message.paid_from_account_balance
);
frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
frm.set_value("party_balance", r.message.party_balance);
},
]);
}
},
});
}
},
after_save: function (frm) {
const { matched_payment_requests } = frappe.last_response;
if (!matched_payment_requests) return;

View File

@@ -21,22 +21,20 @@
"party_name",
"book_advance_payments_in_separate_party_account",
"reconcile_on_advance_payment_date",
"advance_reconciliation_takes_effect_on",
"column_break_11",
"bank_account",
"party_bank_account",
"contact_person",
"contact_email",
"payment_accounts_section",
"party_balance",
"paid_from",
"paid_from_account_type",
"paid_from_account_currency",
"paid_from_account_balance",
"column_break_18",
"paid_to",
"paid_to_account_type",
"paid_to_account_currency",
"paid_to_account_balance",
"payment_amounts_section",
"paid_amount",
"paid_amount_after_tax",
@@ -222,15 +220,6 @@
"fieldtype": "Section Break",
"label": "Accounts"
},
{
"depends_on": "party",
"fieldname": "party_balance",
"fieldtype": "Currency",
"label": "Party Balance",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
},
{
"bold": 1,
"depends_on": "eval:(in_list([\"Internal Transfer\", \"Pay\"], doc.payment_type) || doc.party)",
@@ -252,15 +241,6 @@
"read_only": 1,
"reqd": 1
},
{
"depends_on": "paid_from",
"fieldname": "paid_from_account_balance",
"fieldtype": "Currency",
"label": "Account Balance (From)",
"options": "paid_from_account_currency",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "column_break_18",
"fieldtype": "Column Break"
@@ -285,15 +265,6 @@
"read_only": 1,
"reqd": 1
},
{
"depends_on": "paid_to",
"fieldname": "paid_to_account_balance",
"fieldtype": "Currency",
"label": "Account Balance (To)",
"options": "paid_to_account_currency",
"print_hide": 1,
"read_only": 1
},
{
"depends_on": "eval:(doc.paid_to && doc.paid_from)",
"fieldname": "payment_amounts_section",
@@ -783,6 +754,16 @@
"options": "No\nYes",
"print_hide": 1,
"search_index": 1
},
{
"default": "Oldest Of Invoice Or Advance",
"fetch_from": "company.reconciliation_takes_effect_on",
"fieldname": "advance_reconciliation_takes_effect_on",
"fieldtype": "Select",
"hidden": 1,
"label": "Advance Reconciliation Takes Effect On",
"no_copy": 1,
"options": "Advance Payment Date\nOldest Of Invoice Or Advance\nReconciliation Date"
}
],
"index_web_pages_for_search": 1,
@@ -796,7 +777,7 @@
"table_fieldname": "payment_entries"
}
],
"modified": "2024-11-07 11:19:19.320883",
"modified": "2025-01-31 11:24:58.076393",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
@@ -842,4 +823,4 @@
"states": [],
"title_field": "title",
"track_changes": 1
}
}

View File

@@ -25,6 +25,10 @@ from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import (
get_party_account_based_on_invoice_discounting,
)
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import (
validate_docs_for_deferred_accounting,
validate_docs_for_voucher_types,
)
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import (
get_party_tax_withholding_details,
)
@@ -71,12 +75,16 @@ class PaymentEntry(AccountsController):
PaymentEntryReference,
)
advance_reconciliation_takes_effect_on: DF.Literal[
"Advance Payment Date", "Oldest Of Invoice Or Advance", "Reconciliation Date"
]
amended_from: DF.Link | None
apply_tax_withholding_amount: DF.Check
auto_repeat: DF.Link | None
bank: DF.ReadOnly | None
bank_account: DF.Link | None
bank_account_no: DF.ReadOnly | None
base_in_words: DF.SmallText | None
base_paid_amount: DF.Currency
base_paid_amount_after_tax: DF.Currency
base_received_amount: DF.Currency
@@ -92,21 +100,20 @@ class PaymentEntry(AccountsController):
custom_remarks: DF.Check
deductions: DF.Table[PaymentEntryDeduction]
difference_amount: DF.Currency
in_words: DF.SmallText | None
is_opening: DF.Literal["No", "Yes"]
letter_head: DF.Link | None
mode_of_payment: DF.Link | None
naming_series: DF.Literal["ACC-PAY-.YYYY.-"]
paid_amount: DF.Currency
paid_amount_after_tax: DF.Currency
paid_from: DF.Link
paid_from_account_balance: DF.Currency
paid_from_account_currency: DF.Link
paid_from_account_type: DF.Data | None
paid_to: DF.Link
paid_to_account_balance: DF.Currency
paid_to_account_currency: DF.Link
paid_to_account_type: DF.Data | None
party: DF.DynamicLink | None
party_balance: DF.Currency
party_bank_account: DF.Link | None
party_name: DF.Data | None
party_type: DF.Link | None
@@ -119,6 +126,7 @@ class PaymentEntry(AccountsController):
purchase_taxes_and_charges_template: DF.Link | None
received_amount: DF.Currency
received_amount_after_tax: DF.Currency
reconcile_on_advance_payment_date: DF.Check
reference_date: DF.Date | None
reference_no: DF.Data | None
references: DF.Table[PaymentEntryReference]
@@ -196,6 +204,23 @@ class PaymentEntry(AccountsController):
self.update_advance_paid() # advance_paid_status depends on the payment request amount
self.set_status()
def validate_for_repost(self):
validate_docs_for_voucher_types(["Payment Entry"])
validate_docs_for_deferred_accounting([self.name], [])
def on_update_after_submit(self):
# Flag will be set on Reconciliation
# Reconciliation tool will anyways repost ledger entries. So, no need to check and do implicit repost.
if self.flags.get("ignore_reposting_on_reconciliation"):
return
self.needs_repost = self.check_if_fields_updated(
fields_to_check=[], child_tables={"references": [], "taxes": [], "deductions": []}
)
if self.needs_repost:
self.validate_for_repost()
self.repost_accounting_entries()
def set_liability_account(self):
# Auto setting liability account should only be done during 'draft' status
if self.docstatus > 0 or self.payment_type == "Internal Transfer":
@@ -478,7 +503,6 @@ class PaymentEntry(AccountsController):
if self.payment_type == "Internal Transfer":
for field in (
"party",
"party_balance",
"total_allocated_amount",
"base_total_allocated_amount",
"unallocated_amount",
@@ -506,25 +530,19 @@ class PaymentEntry(AccountsController):
)
else:
complete_contact_details(self)
if not self.party_balance:
self.party_balance = get_balance_on(
party_type=self.party_type, party=self.party, date=self.posting_date, company=self.company
)
if not self.party_account:
party_account = get_party_account(self.party_type, self.party, self.company)
self.set(self.party_account_field, party_account)
self.party_account = party_account
if self.paid_from and not self.paid_from_account_currency and not self.paid_from_account_balance:
if self.paid_from and not self.paid_from_account_currency:
acc = get_account_details(self.paid_from, self.posting_date, self.cost_center)
self.paid_from_account_currency = acc.account_currency
self.paid_from_account_balance = acc.account_balance
if self.paid_to and not self.paid_to_account_currency and not self.paid_to_account_balance:
if self.paid_to and not self.paid_to_account_currency:
acc = get_account_details(self.paid_to, self.posting_date, self.cost_center)
self.paid_to_account_currency = acc.account_currency
self.paid_to_account_balance = acc.account_balance
self.party_account_currency = (
self.paid_from_account_currency
@@ -635,7 +653,7 @@ class PaymentEntry(AccountsController):
if d.reference_doctype not in valid_reference_doctypes:
frappe.throw(
_("Reference Doctype must be one of {0}").format(
comma_or(_(d) for d in valid_reference_doctypes)
comma_or([_(d) for d in valid_reference_doctypes])
)
)
@@ -1500,16 +1518,26 @@ class PaymentEntry(AccountsController):
"voucher_detail_no": invoice.name,
}
if self.reconcile_on_advance_payment_date:
posting_date = self.posting_date
if invoice.reconcile_effect_on:
posting_date = invoice.reconcile_effect_on
else:
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):
# For backwards compatibility
# Supporting reposting on payment entries reconciled before select field introduction
if self.advance_reconciliation_takes_effect_on == "Advance Payment Date":
posting_date = self.posting_date
elif self.advance_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 self.advance_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)
args_dict["account"] = account
@@ -1665,6 +1693,14 @@ class PaymentEntry(AccountsController):
elif self.payment_type in ("Pay", "Internal Transfer"):
return self.paid_from
def get_value_in_transaction_currency(self, account_currency, gl_dict, field):
company_currency = erpnext.get_company_currency(self.company)
conversion_rate = self.target_exchange_rate
if self.paid_from_account_currency != company_currency:
conversion_rate = self.source_exchange_rate
return flt(gl_dict.get(field, 0) / (conversion_rate or 1))
def update_advance_paid(self):
if self.payment_type in ("Receive", "Pay") and self.party:
advance_payment_doctypes = frappe.get_hooks(
@@ -1882,7 +1918,7 @@ class PaymentEntry(AccountsController):
paid_amount -= sum(flt(d.amount, precision) for d in self.deductions)
for ref in self.references:
reference_outstanding_amount = ref.outstanding_amount
reference_outstanding_amount = flt(ref.outstanding_amount)
abs_outstanding_amount = abs(reference_outstanding_amount)
if reference_outstanding_amount > 0:
@@ -2327,10 +2363,17 @@ def get_outstanding_reference_documents(args, validate=False):
outstanding_invoices = []
negative_outstanding_invoices = []
party_account = args.get("party_account")
# get party account if advance account is set.
if args.get("book_advance_payments_in_separate_party_account"):
party_account = get_party_account(args.get("party_type"), args.get("party"), args.get("company"))
else:
party_account = args.get("party_account")
accounts = get_party_account(
args.get("party_type"), args.get("party"), args.get("company"), include_advance=True
)
advance_account = accounts[1] if len(accounts) >= 1 else None
if party_account == advance_account:
party_account = accounts[0]
if args.get("get_outstanding_invoices"):
outstanding_invoices = get_outstanding_invoices(
@@ -2668,9 +2711,7 @@ def get_party_details(company, party_type, party, date, cost_center=None):
account_balance = get_balance_on(party_account, date, cost_center=cost_center)
_party_name = "title" if party_type == "Shareholder" else party_type.lower() + "_name"
party_name = frappe.db.get_value(party_type, party, _party_name)
party_balance = get_balance_on(
party_type=party_type, party=party, company=company, cost_center=cost_center
)
if party_type in ["Customer", "Supplier"]:
party_bank_account = get_party_bank_account(party_type, party)
bank_account = get_default_company_bank_account(company, party_type, party)
@@ -2679,7 +2720,6 @@ def get_party_details(company, party_type, party, date, cost_center=None):
"party_account": party_account,
"party_name": party_name,
"party_account_currency": account_currency,
"party_balance": party_balance,
"account_balance": account_balance,
"party_bank_account": party_bank_account,
"bank_account": bank_account,
@@ -2910,6 +2950,7 @@ def get_payment_entry(
pe.paid_amount = paid_amount
pe.received_amount = received_amount
pe.letter_head = doc.get("letter_head")
pe.bank_account = frappe.db.get_value("Bank Account", {"is_company_account": 1, "is_default": 1}, "name")
if dt in ["Purchase Order", "Sales Order", "Sales Invoice", "Purchase Invoice"]:
pe.project = doc.get("project") or reduce(
@@ -2918,7 +2959,7 @@ def get_payment_entry(
if pe.party_type in ["Customer", "Supplier"]:
bank_account = get_party_bank_account(pe.party_type, pe.party)
pe.set("bank_account", bank_account)
pe.set("party_bank_account", bank_account)
pe.set_bank_account_data()
# only Purchase Invoice can be blocked individually
@@ -3396,13 +3437,14 @@ def add_income_discount_loss(pe, doc, total_discount_percent) -> float:
"""Add loss on income discount in base currency."""
precision = doc.precision("total")
base_loss_on_income = doc.get("base_total") * (total_discount_percent / 100)
positive_negative = -1 if pe.payment_type == "Pay" else 1
pe.append(
"deductions",
{
"account": frappe.get_cached_value("Company", pe.company, "default_discount_account"),
"cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": flt(base_loss_on_income, precision),
"amount": flt(base_loss_on_income, precision) * positive_negative,
},
)
@@ -3414,6 +3456,7 @@ def add_tax_discount_loss(pe, doc, total_discount_percentage) -> float:
tax_discount_loss = {}
base_total_tax_loss = 0
precision = doc.precision("tax_amount_after_discount_amount", "taxes")
positive_negative = -1 if pe.payment_type == "Pay" else 1
# The same account head could be used more than once
for tax in doc.get("taxes", []):
@@ -3436,7 +3479,7 @@ def add_tax_discount_loss(pe, doc, total_discount_percentage) -> float:
"account": account,
"cost_center": pe.cost_center
or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": flt(loss, precision),
"amount": flt(loss, precision) * positive_negative,
},
)
@@ -3504,19 +3547,6 @@ def get_paid_amount(dt, dn, party_type, party, account, due_date):
return paid_amount[0][0] if paid_amount else 0
@frappe.whitelist()
def get_party_and_account_balance(
company, date, paid_from=None, paid_to=None, ptype=None, pty=None, cost_center=None
):
return frappe._dict(
{
"party_balance": get_balance_on(party_type=ptype, party=pty, cost_center=cost_center),
"paid_from_account_balance": get_balance_on(paid_from, date, cost_center=cost_center),
"paid_to_account_balance": get_balance_on(paid_to, date=date, cost_center=cost_center),
}
)
@frappe.whitelist()
def make_payment_order(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc

View File

@@ -291,6 +291,48 @@ class TestPaymentEntry(IntegrationTestCase):
self.assertEqual(si.payment_schedule[0].paid_amount, 200.0)
self.assertEqual(si.payment_schedule[1].paid_amount, 36.0)
def test_payment_entry_against_payment_terms_with_discount_on_pi(self):
pi = make_purchase_invoice(do_not_save=1)
create_payment_terms_template_with_discount()
pi.payment_terms_template = "Test Discount Template"
frappe.db.set_value("Company", pi.company, "default_discount_account", "Write Off - _TC")
pi.append(
"taxes",
{
"charge_type": "On Net Total",
"account_head": "_Test Account Service Tax - _TC",
"cost_center": "_Test Cost Center - _TC",
"description": "Service Tax",
"rate": 18,
},
)
pi.save()
pi.submit()
frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 1)
pe_with_tax_loss = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Cash - _TC")
self.assertEqual(pe_with_tax_loss.references[0].payment_term, "30 Credit Days with 10% Discount")
self.assertEqual(pe_with_tax_loss.payment_type, "Pay")
self.assertEqual(pe_with_tax_loss.references[0].allocated_amount, 295.0)
self.assertEqual(pe_with_tax_loss.paid_amount, 265.5)
self.assertEqual(pe_with_tax_loss.difference_amount, 0)
self.assertEqual(pe_with_tax_loss.deductions[0].amount, -25.0) # Loss on Income
self.assertEqual(pe_with_tax_loss.deductions[1].amount, -4.5) # Loss on Tax
self.assertEqual(pe_with_tax_loss.deductions[1].account, "_Test Account Service Tax - _TC")
frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 0)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Cash - _TC")
self.assertEqual(pe.references[0].payment_term, "30 Credit Days with 10% Discount")
self.assertEqual(pe.payment_type, "Pay")
self.assertEqual(pe.references[0].allocated_amount, 295.0)
self.assertEqual(pe.paid_amount, 265.5)
self.assertEqual(pe.deductions[0].amount, -29.5)
self.assertEqual(pe.difference_amount, 0)
def test_payment_entry_against_payment_terms_with_discount(self):
si = create_sales_invoice(do_not_save=1, qty=1, rate=200)
create_payment_terms_template_with_discount()
@@ -1519,7 +1561,7 @@ class TestPaymentEntry(IntegrationTestCase):
parent_account="Current Liabilities - _TC",
account_name="Advances Paid",
company=company,
account_type="Liability",
account_type="Payable",
)
frappe.db.set_value(

View File

@@ -13,6 +13,7 @@
"payment_term_outstanding",
"account_type",
"payment_type",
"reconcile_effect_on",
"column_break_4",
"total_amount",
"outstanding_amount",
@@ -144,12 +145,18 @@
"is_virtual": 1,
"label": "Payment Request Outstanding",
"read_only": 1
},
{
"fieldname": "reconcile_effect_on",
"fieldtype": "Date",
"label": "Reconcile Effect On",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-09-16 18:11:50.019343",
"modified": "2025-01-13 15:56:18.895082",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Reference",

View File

@@ -30,6 +30,7 @@ class PaymentEntryReference(Document):
payment_term: DF.Link | None
payment_term_outstanding: DF.Float
payment_type: DF.Data | None
reconcile_effect_on: DF.Date | None
reference_doctype: DF.Link
reference_name: DF.DynamicLink
total_amount: DF.Float

View File

@@ -153,10 +153,7 @@ class PaymentReconciliation(Document):
self.add_payment_entries(non_reconciled_payments)
def get_payment_entries(self):
if self.default_advance_account:
party_account = [self.receivable_payable_account, self.default_advance_account]
else:
party_account = [self.receivable_payable_account]
party_account = [self.receivable_payable_account]
order_doctype = "Sales Order" if self.party_type == "Customer" else "Purchase Order"
condition = frappe._dict(
@@ -187,6 +184,7 @@ class PaymentReconciliation(Document):
self.party,
party_account,
order_doctype,
default_advance_account=self.default_advance_account,
against_all_orders=True,
limit=self.payment_limit,
condition=condition,
@@ -337,6 +335,7 @@ class PaymentReconciliation(Document):
for payment in non_reconciled_payments:
row = self.append("payments", {})
row.update(payment)
row.is_advance = payment.book_advance_payments_in_separate_party_account
def get_invoice_entries(self):
# Fetch JVs, Sales and Purchase Invoices for 'invoices' to reconcile against
@@ -426,6 +425,9 @@ class PaymentReconciliation(Document):
def allocate_entries(self, args):
self.validate_entries()
exc_gain_loss_posting_date = frappe.db.get_single_value(
"Accounts Settings", "exchange_gain_loss_posting_date", cache=True
)
invoice_exchange_map = self.get_invoice_exchange_map(args.get("invoices"), args.get("payments"))
default_exchange_gain_loss_account = frappe.get_cached_value(
"Company", self.company, "exchange_gain_loss_account"
@@ -452,6 +454,11 @@ class PaymentReconciliation(Document):
res.difference_account = default_exchange_gain_loss_account
res.exchange_rate = inv.get("exchange_rate")
res.update({"gain_loss_posting_date": pay.get("posting_date")})
if not pay.get("is_advance"):
if exc_gain_loss_posting_date == "Invoice":
res.update({"gain_loss_posting_date": inv.get("invoice_date")})
elif exc_gain_loss_posting_date == "Reconciliation Date":
res.update({"gain_loss_posting_date": nowdate()})
if pay.get("amount") == 0:
entries.append(res)

View File

@@ -6,6 +6,7 @@ import frappe
from frappe import qb
from frappe.tests import IntegrationTestCase, UnitTestCase
from frappe.utils import add_days, add_years, flt, getdate, nowdate, today
from frappe.utils.data import getdate as convert_to_date
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
@@ -1680,7 +1681,7 @@ class TestPaymentReconciliation(IntegrationTestCase):
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_paid_account": self.advance_payable_account,
"reconcile_on_advance_payment_date": 1,
"reconciliation_takes_effect_on": "Advance Payment Date",
},
)
@@ -1729,7 +1730,7 @@ class TestPaymentReconciliation(IntegrationTestCase):
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_received_account": self.advance_receivable_account,
"reconcile_on_advance_payment_date": 0,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
},
)
amount = 200.0
@@ -1838,7 +1839,7 @@ class TestPaymentReconciliation(IntegrationTestCase):
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_paid_account": self.advance_payable_account,
"reconcile_on_advance_payment_date": 0,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
},
)
amount = 200.0
@@ -2057,6 +2058,102 @@ class TestPaymentReconciliation(IntegrationTestCase):
self.assertEqual(pr.get("invoices"), [])
self.assertEqual(pr.get("payments"), [])
def test_advance_reconciliation_effect_on_same_date(self):
frappe.db.set_value(
"Company",
self.company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_received_account": self.advance_receivable_account,
"reconciliation_takes_effect_on": "Reconciliation Date",
},
)
inv_date = convert_to_date(add_days(nowdate(), -1))
adv_date = convert_to_date(add_days(nowdate(), -2))
si = self.create_sales_invoice(posting_date=inv_date, qty=1, rate=200)
pe = self.create_payment_entry(posting_date=adv_date, amount=80).save().submit()
pr = self.create_payment_reconciliation()
pr.from_invoice_date = add_days(nowdate(), -1)
pr.to_invoice_date = nowdate()
pr.from_payment_date = add_days(nowdate(), -2)
pr.to_payment_date = nowdate()
pr.default_advance_account = self.advance_receivable_account
# reconcile multiple payments against invoice
pr.get_unreconciled_entries()
invoices = [x.as_dict() for x in pr.get("invoices")]
payments = [x.as_dict() for x in pr.get("payments")]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
# Difference amount should not be calculated for base currency accounts
for row in pr.allocation:
self.assertEqual(flt(row.get("difference_amount")), 0.0)
pr.reconcile()
si.reload()
self.assertEqual(si.status, "Partly Paid")
# check PR tool output post reconciliation
self.assertEqual(len(pr.get("invoices")), 1)
self.assertEqual(pr.get("invoices")[0].get("outstanding_amount"), 120)
self.assertEqual(pr.get("payments"), [])
# Assert Ledger Entries
gl_entries = frappe.db.get_all(
"GL Entry",
filters={"voucher_no": pe.name},
fields=["account", "posting_date", "voucher_no", "against_voucher", "debit", "credit"],
order_by="account, against_voucher, debit",
)
expected_gl = [
{
"account": self.advance_receivable_account,
"posting_date": adv_date,
"voucher_no": pe.name,
"against_voucher": pe.name,
"debit": 0.0,
"credit": 80.0,
},
{
"account": self.advance_receivable_account,
"posting_date": convert_to_date(nowdate()),
"voucher_no": pe.name,
"against_voucher": pe.name,
"debit": 80.0,
"credit": 0.0,
},
{
"account": self.debit_to,
"posting_date": convert_to_date(nowdate()),
"voucher_no": pe.name,
"against_voucher": si.name,
"debit": 0.0,
"credit": 80.0,
},
{
"account": self.bank,
"posting_date": adv_date,
"voucher_no": pe.name,
"against_voucher": None,
"debit": 80.0,
"credit": 0.0,
},
]
self.assertEqual(expected_gl, gl_entries)
# cancel PE
pe.reload()
pe.cancel()
pr.get_unreconciled_entries()
# check PR tool output
self.assertEqual(len(pr.get("invoices")), 1)
self.assertEqual(len(pr.get("payments")), 0)
self.assertEqual(pr.get("invoices")[0].get("outstanding_amount"), 200)
def make_customer(customer_name, currency=None):
if not frappe.db.exists("Customer", customer_name):

View File

@@ -60,7 +60,9 @@
"payment_order",
"amended_from",
"column_break_pnyv",
"payment_url"
"payment_url",
"column_break_iiuv",
"phone_number"
],
"fields": [
{
@@ -378,6 +380,7 @@
"read_only": 1
},
{
"depends_on": "eval: doc.payment_channel==\"Phone\"",
"fetch_from": "payment_gateway_account.payment_channel",
"fieldname": "payment_channel",
"fieldtype": "Select",
@@ -444,13 +447,22 @@
"fieldtype": "Data",
"label": "Party Name",
"read_only": 1
},
{
"fieldname": "column_break_iiuv",
"fieldtype": "Column Break"
},
{
"fieldname": "phone_number",
"fieldtype": "Data",
"label": "Phone Number"
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2024-10-23 12:23:40.117336",
"modified": "2025-01-04 05:39:32.448857",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",

View File

@@ -81,6 +81,7 @@ class PaymentRequest(Document):
payment_order: DF.Link | None
payment_request_type: DF.Literal["Outward", "Inward"]
payment_url: DF.Data | None
phone_number: DF.Data | None
print_format: DF.Literal[None]
project: DF.Link | None
reference_doctype: DF.Link | None
@@ -221,6 +222,7 @@ class PaymentRequest(Document):
sender=self.email_to,
currency=self.currency,
payment_gateway=self.payment_gateway,
phone_number=self.phone_number,
)
controller.validate_transaction_currency(self.currency)
@@ -298,6 +300,7 @@ class PaymentRequest(Document):
"payer_name": data.customer_name,
"order_id": self.name,
"currency": self.currency,
"payment_gateway": self.payment_gateway,
}
)
@@ -643,6 +646,7 @@ def make_payment_request(**args):
or args.order_type == "Shopping Cart" # compat for webshop app
or gateway_account.get("payment_channel", "Email") != "Email"
),
"phone_number": args.get("phone_number") if args.get("phone_number") else None,
}
)
@@ -777,7 +781,10 @@ def get_existing_paid_amount(doctype, name):
frappe.qb.from_(PL)
.left_join(PER)
.on(
(PER.reference_doctype == PL.against_voucher_type) & (PER.reference_name == PL.against_voucher_no)
(PL.against_voucher_type == PER.reference_doctype)
& (PL.against_voucher_no == PER.reference_name)
& (PL.voucher_type == PER.parenttype)
& (PL.voucher_no == PER.parent)
)
.select(Abs(Sum(PL.amount)).as_("total_paid_amount"))
.where(PL.against_voucher_type.eq(doctype))

View File

@@ -1,7 +1,7 @@
const INDICATORS = {
"Partially Paid": "orange",
Cancelled: "red",
Draft: "gray",
Draft: "red",
Failed: "red",
Initiated: "green",
Paid: "blue",

View File

@@ -709,6 +709,45 @@ class TestPaymentRequest(IntegrationTestCase):
self.assertEqual(pr.grand_total, si.outstanding_amount)
def test_partial_paid_invoice_with_more_payment_entry(self):
pi = make_purchase_invoice(currency="INR", qty=1, rate=500)
pi.submit()
pi_1 = make_purchase_invoice(currency="INR", qty=1, rate=300)
pi_1.submit()
pr = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1, submit_doc=0, return_doc=1)
pr.grand_total = 200
pr.submit()
pr.create_payment_entry()
pr_1 = make_payment_request(
dt="Purchase Invoice", dn=pi.name, mute_email=1, submit_doc=0, return_doc=1
)
pr_1.grand_total = 200
pr_1.submit()
pr_1.create_payment_entry()
pe = get_payment_entry(dt="Purchase Invoice", dn=pi.name)
pe.paid_amount = 200
pe.references[0].reference_doctype = pi.doctype
pe.references[0].reference_name = pi.name
pe.references[0].grand_total = pi.grand_total
pe.references[0].outstanding_amount = pi.outstanding_amount
pe.references[0].allocated_amount = 100
pe.append(
"references",
{
"reference_doctype": pi_1.doctype,
"reference_name": pi_1.name,
"grand_total": pi_1.grand_total,
"outstanding_amount": pi_1.outstanding_amount,
"allocated_amount": 100,
},
)
pr_2 = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1)
pi.load_from_db()
self.assertEqual(pr_2.grand_total, pi.outstanding_amount)
def test_partial_paid_invoice_with_submitted_payment_entry(self):
pi = make_purchase_invoice(currency="INR", qty=1, rate=5000)

View File

@@ -12,15 +12,15 @@
</thead>
<tbody>
<tr>
<td class="text-left font-bold">{{ _('Grand Total') }}</td>
<td class="text-left font-bold">{{ _("Grand Total") }}</td>
<td class='text-right'> {{ frappe.utils.fmt_money(data.grand_total or '', currency=currency) }}</td>
</tr>
<tr>
<td class="text-left font-bold">{{ _('Net Total') }}</td>
<td class="text-left font-bold">{{ _("Net Total") }}</td>
<td class='text-right'> {{ frappe.utils.fmt_money(data.net_total or '', currency=currency) }}</td>
</tr>
<tr>
<td class="text-left font-bold">{{ _('Total Quantity') }}</td>
<td class="text-left font-bold">{{ _("Total Quantity") }}</td>
<td class='text-right'>{{ data.total_quantity or '' }}</td>
</tr>
@@ -44,7 +44,7 @@
<tbody>
{% for d in data.payment_reconciliation %}
<tr>
<td class="text-left">{{ d.mode_of_payment }}</td>
<td class="text-left">{{ _(d.mode_of_payment) }}</td>
<td class='text-right'> {{ frappe.utils.fmt_money(d.expected_amount - d.opening_amount, currency=currency) }}</td>
</tr>
{% endfor %}
@@ -63,7 +63,7 @@
<thead>
<tr>
<th class="text-left">{{ _("Account") }}</th>
<th class="text-left">{{ _("Rate") }}</th>
<th class="text-left">{{ _("Tax Rate") }}</th>
<th class="text-right">{{ _("Amount") }}</th>
</tr>
</thead>

View File

@@ -39,10 +39,12 @@ class TestPOSClosingEntry(IntegrationTestCase):
pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
pos_inv1.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3500})
pos_inv1.save()
pos_inv1.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.save()
pos_inv2.submit()
pcv_doc = make_closing_entry_from_opening(opening_entry)
@@ -68,6 +70,7 @@ class TestPOSClosingEntry(IntegrationTestCase):
pos_inv = create_pos_invoice(rate=3500, do_not_submit=1, item_name="Test Item", without_item_code=1)
pos_inv.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3500})
pos_inv.save()
pos_inv.submit()
pcv_doc = make_closing_entry_from_opening(opening_entry)
@@ -86,10 +89,12 @@ class TestPOSClosingEntry(IntegrationTestCase):
pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
pos_inv1.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3500})
pos_inv1.save()
pos_inv1.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.save()
pos_inv2.submit()
# make return entry of pos_inv2
@@ -111,10 +116,12 @@ class TestPOSClosingEntry(IntegrationTestCase):
pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
pos_inv1.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3500})
pos_inv1.save()
pos_inv1.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.save()
pos_inv2.submit()
pcv_doc = make_closing_entry_from_opening(opening_entry)
@@ -165,6 +172,7 @@ class TestPOSClosingEntry(IntegrationTestCase):
opening_entry = create_opening_entry(pos_profile, test_user.name)
pos_inv1 = create_pos_invoice(rate=350, do_not_submit=1, pos_profile=pos_profile.name)
pos_inv1.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3500})
pos_inv1.save()
pos_inv1.submit()
# if in between a mandatory accounting dimension is added to the POS Profile then
@@ -226,6 +234,7 @@ class TestPOSClosingEntry(IntegrationTestCase):
do_not_submit=True,
)
pos_inv.payments[0].amount = pos_inv.grand_total
pos_inv.save()
pos_inv.submit()
pos_inv2 = create_pos_invoice(
item_code=item_code,
@@ -236,11 +245,9 @@ class TestPOSClosingEntry(IntegrationTestCase):
do_not_submit=True,
)
pos_inv2.payments[0].amount = pos_inv2.grand_total
pos_inv2.save()
pos_inv2.submit()
batch_qty = frappe.db.get_value("Batch", batch_no, "batch_qty")
self.assertEqual(batch_qty, 10)
batch_qty_with_pos = get_batch_qty(batch_no, "_Test Warehouse - _TC", item_code)
self.assertEqual(batch_qty_with_pos, 0.0)
@@ -270,9 +277,6 @@ class TestPOSClosingEntry(IntegrationTestCase):
pcv_doc.reload()
pcv_doc.cancel()
batch_qty = frappe.db.get_value("Batch", batch_no, "batch_qty")
self.assertEqual(batch_qty, 10)
batch_qty_with_pos = get_batch_qty(batch_no, "_Test Warehouse - _TC", item_code)
self.assertEqual(batch_qty_with_pos, 0.0)

View File

@@ -14,7 +14,7 @@
"fieldname": "rate",
"fieldtype": "Percent",
"in_list_view": 1,
"label": "Rate",
"label": "Tax Rate",
"read_only": 1
},
{

View File

@@ -8,7 +8,6 @@
"engine": "InnoDB",
"field_order": [
"customer_section",
"title",
"naming_series",
"customer",
"customer_name",
@@ -192,16 +191,6 @@
"fieldtype": "Section Break",
"options": "fa fa-user"
},
{
"allow_on_submit": 1,
"default": "{customer_name}",
"fieldname": "title",
"fieldtype": "Data",
"hidden": 1,
"label": "Title",
"no_copy": 1,
"print_hide": 1
},
{
"bold": 1,
"fieldname": "naming_series",
@@ -1584,7 +1573,7 @@
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
"modified": "2024-11-26 13:10:50.309570",
"modified": "2025-01-06 15:03:19.957277",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
@@ -1635,7 +1624,7 @@
"sort_order": "DESC",
"states": [],
"timeline_field": "customer",
"title_field": "title",
"title_field": "customer_name",
"track_changes": 1,
"track_seen": 1
}

View File

@@ -20,6 +20,10 @@ from erpnext.controllers.queries import item_query as _item_query
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
class PartialPaymentValidationError(frappe.ValidationError):
pass
class POSInvoice(SalesInvoice):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
@@ -161,7 +165,6 @@ class POSInvoice(SalesInvoice):
terms: DF.TextEditor | None
territory: DF.Link | None
timesheets: DF.Table[SalesInvoiceTimesheet]
title: DF.Data | None
to_date: DF.Date | None
total: DF.Currency
total_advance: DF.Currency
@@ -211,6 +214,7 @@ class POSInvoice(SalesInvoice):
self.validate_payment_amount()
self.validate_loyalty_transaction()
self.validate_company_with_pos_company()
self.validate_full_payment()
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
@@ -485,6 +489,20 @@ class POSInvoice(SalesInvoice):
if self.redeem_loyalty_points and self.loyalty_program and self.loyalty_points:
validate_loyalty_points(self, self.loyalty_points)
def validate_full_payment(self):
invoice_total = flt(self.rounded_total) or flt(self.grand_total)
if self.docstatus == 1:
if self.is_return and self.paid_amount != invoice_total:
frappe.throw(
msg=_("Partial Payment in POS Invoice is not allowed."), exc=PartialPaymentValidationError
)
if self.paid_amount < invoice_total:
frappe.throw(
msg=_("Partial Payment in POS Invoice is not allowed."), exc=PartialPaymentValidationError
)
def set_status(self, update=False, status=None, update_modified=True):
if self.is_new():
if self.get("amended_from"):

View File

@@ -7,7 +7,7 @@ import frappe
from frappe import _
from frappe.tests import IntegrationTestCase
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
from erpnext.accounts.doctype.pos_invoice.pos_invoice import PartialPaymentValidationError, make_sales_return
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.stock.doctype.item.test_item import make_item
@@ -317,7 +317,7 @@ class TestPOSInvoice(IntegrationTestCase):
)
pos.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 1000, "default": 1}
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2000, "default": 1}
)
pos.insert()
@@ -328,6 +328,11 @@ class TestPOSInvoice(IntegrationTestCase):
# partial return 1
pos_return1.get("items")[0].qty = -1
pos_return1.set("payments", [])
pos_return1.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": -1000, "default": 1}
)
pos_return1.paid_amount = -1000
pos_return1.submit()
pos_return1.reload()
@@ -342,6 +347,11 @@ class TestPOSInvoice(IntegrationTestCase):
# partial return 2
pos_return2 = make_sales_return(pos.name)
pos_return2.set("payments", [])
pos_return2.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": -1000, "default": 1}
)
pos_return2.paid_amount = -1000
pos_return2.submit()
self.assertEqual(pos_return2.get("items")[0].qty, -1)
@@ -377,6 +387,15 @@ class TestPOSInvoice(IntegrationTestCase):
inv.payments = []
self.assertRaises(frappe.ValidationError, inv.insert)
def test_partial_payment(self):
pos_inv = create_pos_invoice(rate=10000, do_not_save=1)
pos_inv.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 9000},
)
pos_inv.insert()
self.assertRaises(PartialPaymentValidationError, pos_inv.submit)
def test_serialized_item_transaction(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
@@ -589,7 +608,13 @@ class TestPOSInvoice(IntegrationTestCase):
"Test Loyalty Customer", company="_Test Company", loyalty_program="Test Single Loyalty"
)
inv = create_pos_invoice(customer="Test Loyalty Customer", rate=10000)
inv = create_pos_invoice(customer="Test Loyalty Customer", rate=10000, do_not_save=1)
inv.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 10000},
)
inv.insert()
inv.submit()
lpe = frappe.get_doc(
"Loyalty Point Entry",
@@ -615,7 +640,13 @@ class TestPOSInvoice(IntegrationTestCase):
)
# add 10 loyalty points
create_pos_invoice(customer="Test Loyalty Customer", rate=10000)
pos_inv = create_pos_invoice(customer="Test Loyalty Customer", rate=10000, do_not_save=1)
pos_inv.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 10000},
)
pos_inv.paid_amount = 10000
pos_inv.submit()
before_lp_details = get_loyalty_program_details_with_points(
"Test Loyalty Customer", company="_Test Company", loyalty_program="Test Single Loyalty"
@@ -649,10 +680,12 @@ class TestPOSInvoice(IntegrationTestCase):
test_user, pos_profile = init_user_and_profile()
pos_inv = create_pos_invoice(rate=300, additional_discount_percentage=10, do_not_submit=1)
pos_inv.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 270})
pos_inv.save()
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.save()
pos_inv2.submit()
consolidate_pos_invoices()
@@ -684,6 +717,7 @@ class TestPOSInvoice(IntegrationTestCase):
"included_in_print_rate": 1,
},
)
pos_inv.save()
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=300, qty=2, do_not_submit=1)
@@ -700,6 +734,7 @@ class TestPOSInvoice(IntegrationTestCase):
"included_in_print_rate": 1,
},
)
pos_inv2.save()
pos_inv2.submit()
consolidate_pos_invoices()
@@ -752,6 +787,7 @@ class TestPOSInvoice(IntegrationTestCase):
"included_in_print_rate": 1,
},
)
pos_inv2.save()
pos_inv2.submit()
consolidate_pos_invoices()
@@ -782,7 +818,10 @@ class TestPOSInvoice(IntegrationTestCase):
# POS Invoice 1, for the batch without bundle
pos_inv1 = create_pos_invoice(item="_BATCH ITEM Test For Reserve", rate=300, qty=15, do_not_save=1)
pos_inv1.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 4500},
)
pos_inv1.items[0].batch_no = batch_no
pos_inv1.save()
pos_inv1.submit()
@@ -798,8 +837,14 @@ class TestPOSInvoice(IntegrationTestCase):
# POS Invoice 2, for the batch with bundle
pos_inv2 = create_pos_invoice(
item="_BATCH ITEM Test For Reserve", rate=300, qty=10, batch_no=batch_no
item="_BATCH ITEM Test For Reserve", rate=300, qty=10, batch_no=batch_no, do_not_save=1
)
pos_inv2.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3000},
)
pos_inv2.save()
pos_inv2.submit()
pos_inv2.reload()
self.assertTrue(pos_inv2.items[0].serial_and_batch_bundle)
@@ -834,6 +879,10 @@ class TestPOSInvoice(IntegrationTestCase):
pos_inv1 = create_pos_invoice(
item=item.name, rate=300, qty=1, do_not_submit=1, batch_no="TestBatch 01"
)
pos_inv1.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 300},
)
pos_inv1.save()
pos_inv1.submit()
@@ -843,7 +892,8 @@ class TestPOSInvoice(IntegrationTestCase):
{
"item_code": item.name,
"warehouse": pos_inv2.items[0].warehouse,
"voucher_type": "Delivery Note",
"voucher_type": "POS Invoice",
"voucher_no": pos_inv2.name,
"qty": 2,
"avg_rate": 300,
"batches": frappe._dict({"TestBatch 01": 2}),

View File

@@ -12,7 +12,9 @@ from frappe.utils import cint, flt, get_time, getdate, nowdate, nowtime
from frappe.utils.background_jobs import enqueue, is_job_enqueued
from frappe.utils.scheduler import is_scheduler_inactive
from erpnext.accounts.doctype.pos_profile.pos_profile import required_accounting_dimensions
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_checks_for_pl_and_bs_accounts,
)
from erpnext.controllers.taxes_and_totals import ItemWiseTaxDetail
@@ -118,11 +120,13 @@ class POSInvoiceMergeLog(Document):
sales = [d for d in pos_invoice_docs if d.get("is_return") == 0]
sales_invoice, credit_note = "", ""
if returns:
credit_note = self.process_merging_into_credit_note(returns)
sales_invoice_doc = None
if sales:
sales_invoice = self.process_merging_into_sales_invoice(sales)
sales_invoice_doc = self.process_merging_into_sales_invoice(sales)
sales_invoice = sales_invoice_doc.name
if returns:
credit_note = self.process_merging_into_credit_note(returns, sales_invoice_doc)
self.save() # save consolidated_sales_invoice & consolidated_credit_note ref in merge log
self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
@@ -133,6 +137,7 @@ class POSInvoiceMergeLog(Document):
self.update_pos_invoices(pos_invoice_docs)
self.serial_and_batch_bundle_reference_for_pos_invoice()
self.cancel_linked_invoices()
self.delink_serial_and_batch_bundle()
def process_merging_into_sales_invoice(self, data):
sales_invoice = self.get_new_sales_invoice()
@@ -140,20 +145,35 @@ class POSInvoiceMergeLog(Document):
sales_invoice.is_consolidated = 1
sales_invoice.set_posting_time = 1
sales_invoice.posting_date = getdate(self.posting_date)
sales_invoice.posting_time = get_time(self.posting_time)
if not sales_invoice.posting_date:
sales_invoice.posting_date = getdate(self.posting_date)
if not sales_invoice.posting_time:
sales_invoice.posting_time = get_time(self.posting_time)
sales_invoice.save()
sales_invoice.submit()
self.consolidated_invoice = sales_invoice.name
return sales_invoice.name
return sales_invoice
def process_merging_into_credit_note(self, data):
def process_merging_into_credit_note(self, data, sales_invoice_doc=None):
credit_note = self.get_new_sales_invoice()
credit_note.is_return = 1
credit_note = self.merge_pos_invoice_into(credit_note, data)
referenes = {}
if sales_invoice_doc:
credit_note.return_against = sales_invoice_doc.name
for d in sales_invoice_doc.items:
referenes[d.item_code] = d.name
for d in credit_note.items:
d.sales_invoice_item = referenes.get(d.item_code)
credit_note.is_consolidated = 1
credit_note.set_posting_time = 1
@@ -181,6 +201,10 @@ class POSInvoiceMergeLog(Document):
for doc in data:
map_doc(doc, invoice, table_map={"doctype": invoice.doctype})
if doc.get("posting_date"):
invoice.posting_date = getdate(doc.posting_date)
invoice.posting_time = get_time(doc.posting_time)
if doc.redeem_loyalty_points:
invoice.loyalty_redemption_account = doc.loyalty_redemption_account
invoice.loyalty_redemption_cost_center = doc.loyalty_redemption_cost_center
@@ -271,22 +295,23 @@ class POSInvoiceMergeLog(Document):
invoice.disable_rounded_total = cint(
frappe.db.get_value("POS Profile", invoice.pos_profile, "disable_rounded_total")
)
accounting_dimensions = required_accounting_dimensions()
accounting_dimensions = get_checks_for_pl_and_bs_accounts()
accounting_dimensions_fields = [d.fieldname for d in accounting_dimensions]
dimension_values = frappe.db.get_value(
"POS Profile", {"name": invoice.pos_profile}, accounting_dimensions, as_dict=1
"POS Profile", {"name": invoice.pos_profile}, accounting_dimensions_fields, as_dict=1
)
for dimension in accounting_dimensions:
dimension_value = dimension_values.get(dimension)
dimension_value = dimension_values.get(dimension.fieldname)
if not dimension_value:
if not dimension_value and (dimension.mandatory_for_pl or dimension.mandatory_for_bs):
frappe.throw(
_("Please set Accounting Dimension {} in {}").format(
frappe.bold(frappe.unscrub(dimension)),
frappe.bold(dimension.label),
frappe.get_desk_link("POS Profile", invoice.pos_profile),
)
)
invoice.set(dimension, dimension_value)
invoice.set(dimension.fieldname, dimension_value)
if self.merge_invoices_based_on == "Customer Group":
invoice.flags.ignore_pos_profile = True
@@ -298,6 +323,8 @@ class POSInvoiceMergeLog(Document):
sales_invoice = frappe.new_doc("Sales Invoice")
sales_invoice.customer = self.customer
sales_invoice.is_pos = 1
sales_invoice.posting_date = None
sales_invoice.posting_time = None
return sales_invoice
@@ -320,8 +347,45 @@ class POSInvoiceMergeLog(Document):
for table_name in ["items", "packed_items"]:
pos_invoice.set_serial_and_batch_bundle(table_name)
def delink_serial_and_batch_bundle(self):
bundles = self.get_serial_and_batch_bundles()
if not bundles:
return
sle_table = frappe.qb.DocType("Stock Ledger Entry")
query = (
frappe.qb.update(sle_table)
.set(sle_table.serial_and_batch_bundle, None)
.where(sle_table.serial_and_batch_bundle.isin(bundles) & sle_table.is_cancelled == 1)
)
query.run()
def get_serial_and_batch_bundles(self):
pos_invoices = []
for d in self.pos_invoices:
pos_invoices.append(d.pos_invoice)
if pos_invoices:
return frappe.get_all(
"POS Invoice Item",
filters={
"docstatus": 1,
"parent": ["in", pos_invoices],
"serial_and_batch_bundle": ["is", "set"],
},
pluck="serial_and_batch_bundle",
)
return []
def cancel_linked_invoices(self):
for si_name in [self.consolidated_invoice, self.consolidated_credit_note]:
invoices = [self.consolidated_invoice, self.consolidated_credit_note]
if not invoices:
return
invoices.reverse()
for si_name in invoices:
if not si_name:
continue
si = frappe.get_doc("Sales Invoice", si_name)
@@ -503,6 +567,9 @@ def cancel_merge_logs(merge_logs, closing_entry=None):
try:
for log in merge_logs:
merge_log = frappe.get_doc("POS Invoice Merge Log", log)
if merge_log.docstatus == 2:
continue
merge_log.flags.ignore_permissions = True
merge_log.cancel()

View File

@@ -40,14 +40,17 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
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()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.save()
pos_inv2.submit()
pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
pos_inv3.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300})
pos_inv3.save()
pos_inv3.submit()
consolidate_pos_invoices()
@@ -73,14 +76,17 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
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()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.save()
pos_inv2.submit()
pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
pos_inv3.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300})
pos_inv3.save()
pos_inv3.submit()
pos_inv_cn = make_sales_return(pos_inv.name)
@@ -135,6 +141,7 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
)
inv.insert()
inv.payments[0].amount = inv.grand_total
inv.save()
inv.submit()
inv2 = create_pos_invoice(qty=1, rate=100, do_not_save=True)
@@ -152,6 +159,7 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
)
inv2.insert()
inv2.payments[0].amount = inv.grand_total
inv2.save()
inv2.submit()
consolidate_pos_invoices()
@@ -291,7 +299,7 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
inv2.submit()
inv3 = create_pos_invoice(qty=3, rate=600, do_not_save=True)
inv3.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 1000})
inv3.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 1800})
inv3.insert()
inv3.submit()
@@ -299,8 +307,8 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
inv.load_from_db()
consolidated_invoice = frappe.get_doc("Sales Invoice", inv.consolidated_invoice)
self.assertEqual(consolidated_invoice.outstanding_amount, 800)
self.assertNotEqual(consolidated_invoice.status, "Paid")
self.assertNotEqual(consolidated_invoice.outstanding_amount, 800)
self.assertEqual(consolidated_invoice.status, "Paid")
finally:
frappe.set_user("Administrator")
@@ -435,6 +443,7 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
do_not_submit=1,
)
pos_inv.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 100})
pos_inv.save()
pos_inv.submit()
pos_inv_cn = make_sales_return(pos_inv.name)
@@ -449,6 +458,7 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
do_not_submit=1,
)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 100})
pos_inv2.save()
pos_inv2.submit()
consolidate_pos_invoices()

View File

@@ -25,11 +25,13 @@
"hide_unavailable_items",
"auto_add_item_to_cart",
"validate_stock_on_save",
"print_receipt_on_order_complete",
"column_break_16",
"update_stock",
"ignore_pricing_rule",
"allow_rate_change",
"allow_discount_change",
"disable_grand_total_to_default_mop",
"section_break_23",
"item_groups",
"column_break_25",
@@ -374,24 +376,36 @@
},
{
"fieldname": "utm_campaign",
"print_hide": 1,
"fieldtype": "Link",
"label": "Campaign",
"options": "UTM Campaign"
"options": "UTM Campaign",
"print_hide": 1
},
{
"fieldname": "utm_source",
"print_hide": 1,
"fieldtype": "Link",
"label": "Source",
"options": "UTM Source"
"options": "UTM Source",
"print_hide": 1
},
{
"fieldname": "utm_medium",
"print_hide": 1,
"fieldtype": "Link",
"label": "Medium",
"options": "UTM Campaign"
"options": "UTM Campaign",
"print_hide": 1
},
{
"default": "0",
"fieldname": "print_receipt_on_order_complete",
"fieldtype": "Check",
"label": "Print Receipt on Order Complete"
},
{
"default": "0",
"fieldname": "disable_grand_total_to_default_mop",
"fieldtype": "Check",
"label": "Disable auto setting Grand Total to default Payment Mode"
}
],
"icon": "icon-cog",
@@ -419,7 +433,7 @@
"link_fieldname": "pos_profile"
}
],
"modified": "2024-06-28 10:51:48.543766",
"modified": "2025-01-29 13:12:30.796630",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",
@@ -448,4 +462,4 @@
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -7,6 +7,10 @@ from frappe import _, msgprint, scrub, unscrub
from frappe.model.document import Document
from frappe.utils import get_link_to_form, now
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_checks_for_pl_and_bs_accounts,
)
class POSProfile(Document):
# begin: auto-generated types
@@ -35,6 +39,7 @@ class POSProfile(Document):
currency: DF.Link
customer: DF.Link | None
customer_groups: DF.Table[POSCustomerGroup]
disable_grand_total_to_default_mop: DF.Check
disable_rounded_total: DF.Check
disabled: DF.Check
expense_account: DF.Link | None
@@ -46,6 +51,7 @@ class POSProfile(Document):
letter_head: DF.Link | None
payments: DF.Table[POSPaymentMethod]
print_format: DF.Link | None
print_receipt_on_order_complete: DF.Check
select_print_heading: DF.Link | None
selling_price_list: DF.Link | None
tax_category: DF.Link | None
@@ -70,15 +76,19 @@ class POSProfile(Document):
self.validate_accounting_dimensions()
def validate_accounting_dimensions(self):
acc_dim_names = required_accounting_dimensions()
for acc_dim in acc_dim_names:
if not self.get(acc_dim):
acc_dims = get_checks_for_pl_and_bs_accounts()
for acc_dim in acc_dims:
if (
self.company == acc_dim.company
and not self.get(acc_dim.fieldname)
and (acc_dim.mandatory_for_pl or acc_dim.mandatory_for_bs)
):
frappe.throw(
_(
"{0} is a mandatory Accounting Dimension. <br>"
"Please set a value for {0} in Accounting Dimensions section."
).format(
unscrub(frappe.bold(acc_dim)),
frappe.bold(acc_dim.label),
),
title=_("Mandatory Accounting Dimension"),
)
@@ -216,23 +226,6 @@ def get_child_nodes(group_type, root):
)
def required_accounting_dimensions():
p = frappe.qb.DocType("Accounting Dimension")
c = frappe.qb.DocType("Accounting Dimension Detail")
acc_dim_doc = (
frappe.qb.from_(p)
.inner_join(c)
.on(p.name == c.parent)
.select(c.parent)
.where((c.mandatory_for_bs == 1) | (c.mandatory_for_pl == 1))
.where(p.disabled == 0)
).run(as_dict=1)
acc_dim_names = [scrub(d.parent) for d in acc_dim_doc]
return acc_dim_names
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def pos_profile_query(doctype, txt, searchfield, start, page_len, filters):

View File

@@ -1,7 +1,10 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from collections import Counter
import frappe
from frappe import _
from frappe.model.document import Document
@@ -22,4 +25,14 @@ class POSSettings(Document):
# end: auto-generated types
def validate(self):
pass
self.validate_invoice_fields()
def validate_invoice_fields(self):
invoice_fields = [field.fieldname for field in self.invoice_fields]
duplicate_invoice_fields = {key for key, value in Counter(invoice_fields).items() if value > 1}
if len(duplicate_invoice_fields):
for field in duplicate_invoice_fields:
frappe.throw(
title=_("Duplicate POS Fields"), msg=_("'{0}' has been already added.").format(field)
)

View File

@@ -53,6 +53,7 @@
"column_break_42",
"free_item_uom",
"round_free_qty",
"dont_enforce_free_item_qty",
"is_recursive",
"recurse_for",
"apply_recursion_over",
@@ -643,12 +644,19 @@
"fieldname": "has_priority",
"fieldtype": "Check",
"label": "Has Priority"
},
{
"default": "0",
"depends_on": "eval:doc.price_or_product_discount == 'Product'",
"fieldname": "dont_enforce_free_item_qty",
"fieldtype": "Check",
"label": "Don't Enforce Free Item Qty"
}
],
"icon": "fa fa-gift",
"idx": 1,
"links": [],
"modified": "2024-09-16 18:14:51.314765",
"modified": "2025-02-17 18:15:39.824639",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",

View File

@@ -60,6 +60,7 @@ class PricingRule(Document):
disable: DF.Check
discount_amount: DF.Currency
discount_percentage: DF.Float
dont_enforce_free_item_qty: DF.Check
for_price_list: DF.Link | None
free_item: DF.Link | None
free_item_rate: DF.Currency
@@ -645,7 +646,7 @@ def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None, ra
if pricing_rule.margin_type in ["Percentage", "Amount"]:
item_details.margin_rate_or_amount = 0.0
item_details.margin_type = None
elif pricing_rule.get("free_item"):
elif pricing_rule.get("free_item") and not pricing_rule.get("dont_enforce_free_item_qty"):
item_details.remove_free_item = (
item_code if pricing_rule.get("same_item") else pricing_rule.get("free_item")
)

View File

@@ -438,6 +438,54 @@ class TestPricingRule(IntegrationTestCase):
self.assertEqual(so.items[1].is_free_item, 1)
self.assertEqual(so.items[1].item_code, "_Test Item 2")
def test_dont_enforce_free_item_qty(self):
# this test is only for testing non-enforcement as all other tests in this file already test with enforcement
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule",
"apply_on": "Item Code",
"currency": "USD",
"items": [
{
"item_code": "_Test Item",
}
],
"selling": 1,
"rate_or_discount": "Discount Percentage",
"rate": 0,
"min_qty": 0,
"max_qty": 7,
"discount_percentage": 17.5,
"price_or_product_discount": "Product",
"same_item": 0,
"free_item": "_Test Item 2",
"free_qty": 1,
"company": "_Test Company",
}
pricing_rule = frappe.get_doc(test_record.copy()).insert()
# With enforcement
so = make_sales_order(item_code="_Test Item", qty=1, do_not_submit=True)
self.assertEqual(so.items[1].is_free_item, 1)
self.assertEqual(so.items[1].item_code, "_Test Item 2")
# Test 1 : Saving a document with an item with pricing list without it's corresponding free item will cause it the free item to be refetched on save
so.items.pop(1)
so.save()
so.reload()
self.assertEqual(len(so.items), 2)
# Without enforcement
pricing_rule.dont_enforce_free_item_qty = 1
pricing_rule.save()
# Test 2 : Deleted free item will not be fetched again on save without enforcement
so.items.pop(1)
so.save()
so.reload()
self.assertEqual(len(so.items), 1)
def test_cumulative_pricing_rule(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Cumulative Pricing Rule")
test_record = {
@@ -1461,6 +1509,7 @@ def make_pricing_rule(**args):
"discount_amount": args.discount_amount or 0.0,
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0,
"has_priority": args.has_priority or 0,
"enforce_free_item_qty": args.dont_enforce_free_item_qty or 0,
}
)

View File

@@ -651,8 +651,17 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
qty = pricing_rule.free_qty or 1
if pricing_rule.is_recursive:
transaction_qty = (args.get("qty") if args else doc.total_qty) - pricing_rule.apply_recursion_over
if transaction_qty:
transaction_qty = sum(
[
row.qty
for row in doc.items
if not row.is_free_item
and row.item_code == args.item_code
and row.pricing_rules == args.pricing_rules
]
)
transaction_qty = transaction_qty - pricing_rule.apply_recursion_over
if transaction_qty and transaction_qty > 0:
qty = flt(transaction_qty) * qty / pricing_rule.recurse_for
if pricing_rule.round_free_qty:
qty = (flt(transaction_qty) // pricing_rule.recurse_for) * (pricing_rule.free_qty or 1)
@@ -704,7 +713,10 @@ def apply_pricing_rule_for_free_items(doc, pricing_rule_args):
args.pop((item.item_code, item.pricing_rules))
for free_item in args.values():
doc.append("items", free_item)
if doc.is_new() or not frappe.get_value(
"Pricing Rule", free_item["pricing_rules"], "dont_enforce_free_item_qty"
):
doc.append("items", free_item)
def get_pricing_rule_items(pr_doc, other_items=False) -> list:

View File

@@ -1,7 +1,6 @@
{
"actions": [],
"autoname": "format:ACC-PPR-{#####}",
"beta": 1,
"creation": "2023-03-30 21:28:39.793927",
"default_view": "List",
"doctype": "DocType",
@@ -158,7 +157,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2024-08-27 14:48:56.715320",
"modified": "2025-01-08 08:22:14.798085",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Payment Reconciliation",
@@ -192,4 +191,4 @@
"sort_order": "DESC",
"states": [],
"title_field": "company"
}
}

View File

@@ -210,9 +210,9 @@ def trigger_reconciliation_for_queued_docs():
docs_to_trigger = []
unique_filters = set()
queue_size = 5
queue_size = frappe.db.get_single_value("Accounts Settings", "reconciliation_queue_size") or 5
fields = ["company", "party_type", "party", "receivable_payable_account"]
fields = ["company", "party_type", "party", "receivable_payable_account", "default_advance_account"]
def get_filters_as_tuple(fields, doc):
filters = ()

View File

@@ -1,7 +1,6 @@
{
"actions": [],
"autoname": "format:PPR-LOG-{##}",
"beta": 1,
"creation": "2023-03-13 15:00:09.149681",
"default_view": "List",
"doctype": "DocType",
@@ -110,7 +109,7 @@
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-03-27 13:10:18.769659",
"modified": "2025-01-08 08:22:19.104975",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Payment Reconciliation Log",

View File

@@ -20,6 +20,7 @@
"is_advance",
"section_break_5",
"difference_amount",
"gain_loss_posting_date",
"column_break_7",
"difference_account",
"exchange_rate",
@@ -153,11 +154,16 @@
"fieldtype": "Check",
"in_list_view": 1,
"label": "Reconciled"
},
{
"fieldname": "gain_loss_posting_date",
"fieldtype": "Date",
"label": "Difference Posting Date"
}
],
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:18.933928",
"modified": "2025-01-23 16:09:01.058574",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Payment Reconciliation Log Allocations",

View File

@@ -20,6 +20,7 @@ class ProcessPaymentReconciliationLogAllocations(Document):
difference_account: DF.Link | None
difference_amount: DF.Currency
exchange_rate: DF.Float
gain_loss_posting_date: DF.Date | None
invoice_number: DF.DynamicLink
invoice_type: DF.Link
is_advance: DF.Data | None

View File

@@ -244,9 +244,9 @@
},
{
"fieldname": "cc_to",
"fieldtype": "Link",
"fieldtype": "Table MultiSelect",
"label": "CC To",
"options": "User"
"options": "Process Statement Of Accounts CC"
},
{
"default": "1",
@@ -400,7 +400,7 @@
}
],
"links": [],
"modified": "2024-10-18 17:51:39.108481",
"modified": "2024-12-11 12:11:13.543134",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",

View File

@@ -31,6 +31,9 @@ class ProcessStatementOfAccounts(Document):
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.process_statement_of_accounts_cc.process_statement_of_accounts_cc import (
ProcessStatementOfAccountsCC,
)
from erpnext.accounts.doctype.process_statement_of_accounts_customer.process_statement_of_accounts_customer import (
ProcessStatementOfAccountsCustomer,
)
@@ -41,7 +44,7 @@ class ProcessStatementOfAccounts(Document):
ageing_based_on: DF.Literal["Due Date", "Posting Date"]
based_on_payment_terms: DF.Check
body: DF.TextEditor | None
cc_to: DF.Link | None
cc_to: DF.TableMultiSelect[ProcessStatementOfAccountsCC]
collection_name: DF.DynamicLink | None
company: DF.Link
cost_center: DF.TableMultiSelect[PSOACostCenter]
@@ -233,17 +236,21 @@ def get_ar_filters(doc, entry):
def get_html(doc, filters, entry, col, res, ageing):
base_template_path = "frappe/www/printview.html"
template_path = (
"erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html"
if doc.report == "General Ledger"
else "erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html"
)
template_path = "erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html"
if doc.report == "General Ledger":
template_path = (
"erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html"
)
process_soa_html = frappe.get_hooks("process_soa_html")
# fetching custom print format for Process Statement of Accounts
if process_soa_html and process_soa_html.get(doc.report):
template_path = process_soa_html[doc.report][-1]
if doc.letter_head:
from frappe.www.printview import get_letter_head
letter_head = get_letter_head(doc, 0)
html = frappe.render_template(
template_path,
{
@@ -259,7 +266,6 @@ def get_html(doc, filters, entry, col, res, ageing):
else None,
},
)
html = frappe.render_template(
base_template_path,
{"body": html, "css": get_print_style(), "title": "Statement For " + entry.customer},
@@ -318,13 +324,16 @@ def get_recipients_and_cc(customer, doc):
recipients = []
for clist in doc.customers:
if clist.customer == customer:
recipients.append(clist.billing_email)
if clist.billing_email:
for email in clist.billing_email.split(","):
recipients.append(email.strip())
if doc.primary_mandatory and clist.primary_email:
recipients.append(clist.primary_email)
for email in clist.primary_email.split(","):
recipients.append(email.strip())
cc = []
if doc.cc_to != "":
try:
cc = [frappe.get_value("User", doc.cc_to, "email")]
cc = [frappe.get_value("User", user.cc, "email") for user in doc.cc_to]
except Exception:
pass

View File

@@ -0,0 +1,32 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2024-12-11 12:10:04.654593",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"cc"
],
"fields": [
{
"fieldname": "cc",
"fieldtype": "Link",
"in_list_view": 1,
"label": "CC",
"options": "User"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-12-11 12:10:39.772598",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts CC",
"owner": "Administrator",
"permissions": [],
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,23 @@
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class ProcessStatementOfAccountsCC(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
cc: DF.Link | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -336,6 +336,8 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
if (this.frm.doc.__onload && this.frm.doc.__onload.load_after_mapping) return;
let payment_terms_template = this.frm.doc.payment_terms_template;
erpnext.utils.get_party_details(
this.frm,
"erpnext.accounts.party.get_party_details",
@@ -356,6 +358,12 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
me.frm.doc.tax_withholding_category = me.frm.supplier_tds;
me.frm.set_df_property("apply_tds", "read_only", me.frm.supplier_tds ? 0 : 1);
me.frm.set_df_property("tax_withholding_category", "hidden", me.frm.supplier_tds ? 0 : 1);
// while duplicating, don't change payment terms
if (me.frm.doc.__run_link_triggers === false) {
me.frm.set_value("payment_terms_template", payment_terms_template);
me.frm.refresh_field("payment_terms_template");
}
}
);
}
@@ -372,6 +380,18 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
}
}
tax_withholding_category(frm) {
var me = this;
let filtered_taxes = (me.frm.doc.taxes || []).filter((row) => !row.is_tax_withholding_account);
me.frm.clear_table("taxes");
filtered_taxes.forEach((row) => {
me.frm.add_child("taxes", row);
});
me.frm.refresh_field("taxes");
}
credit_to() {
var me = this;
if (this.frm.doc.credit_to) {
@@ -403,6 +423,8 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
hide_fields(this.frm.doc);
if (cint(this.frm.doc.is_paid)) {
this.frm.set_value("allocate_advances_automatically", 0);
this.frm.set_value("payment_terms_template", "");
this.frm.set_value("payment_schedule", []);
if (!this.frm.doc.company) {
this.frm.set_value("is_paid", 0);
frappe.msgprint(__("Please specify Company to proceed"));

View File

@@ -1625,7 +1625,7 @@
{
"default": "1",
"depends_on": "eval: doc.is_return && doc.return_against",
"description": "Debit Note will update it's own outstanding amount, even if \"Return Against\" is specified.",
"description": "Debit Note will update it's own outstanding amount, even if 'Return Against' is specified.",
"fieldname": "update_outstanding_for_self",
"fieldtype": "Check",
"label": "Update Outstanding for Self"
@@ -1641,7 +1641,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2024-10-25 18:13:01.944477",
"modified": "2025-01-14 11:39:04.564610",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -10,7 +10,6 @@ from frappe.utils import cint, cstr, flt, formatdate, get_link_to_form, getdate,
import erpnext
from erpnext.accounts.deferred_revenue import validate_service_stop_date
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import (
validate_docs_for_deferred_accounting,
validate_docs_for_voucher_types,
@@ -33,7 +32,7 @@ from erpnext.accounts.general_ledger import (
merge_similar_entries,
)
from erpnext.accounts.party import get_due_date, get_party_account
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
from erpnext.accounts.utils import get_account_currency, get_fiscal_year, update_voucher_outstanding
from erpnext.assets.doctype.asset.asset import is_cwip_accounting_enabled
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.buying.utils import check_on_hold_or_closed_status
@@ -840,12 +839,12 @@ class PurchaseInvoice(BuyingController):
def update_supplier_outstanding(self, update_outstanding):
if update_outstanding == "No":
update_outstanding_amt(
self.credit_to,
"Supplier",
self.supplier,
self.doctype,
self.return_against if cint(self.is_return) and self.return_against else self.name,
update_voucher_outstanding(
voucher_type=self.doctype,
voucher_no=self.return_against if cint(self.is_return) and self.return_against else self.name,
account=self.credit_to,
party_type="Supplier",
party=self.supplier,
)
def get_gl_entries(self, warehouse_account=None):
@@ -1128,6 +1127,7 @@ class PurchaseInvoice(BuyingController):
exchange_rate_map[item.purchase_receipt]
and self.conversion_rate != exchange_rate_map[item.purchase_receipt]
and item.net_rate == net_rate_map[item.pr_detail]
and item.item_code in stock_items
):
discrepancy_caused_by_exchange_rate_difference = (
item.qty * item.net_rate
@@ -1683,7 +1683,12 @@ class PurchaseInvoice(BuyingController):
if pi:
pi = pi[0][0]
frappe.throw(_("Supplier Invoice No exists in Purchase Invoice {0}").format(pi))
frappe.throw(
_("Supplier Invoice No exists in Purchase Invoice {0}").format(
get_link_to_form("Purchase Invoice", pi)
)
)
def update_billing_status_in_pr(self, update_modified=True):
if self.is_return and not self.update_billed_amount_in_purchase_receipt:
@@ -1797,13 +1802,13 @@ class PurchaseInvoice(BuyingController):
self.remove(d)
## Add pending vouchers on which tax was withheld
for voucher_no, voucher_details in voucher_wise_amount.items():
for row in voucher_wise_amount:
self.append(
"tax_withheld_vouchers",
{
"voucher_name": voucher_no,
"voucher_type": voucher_details.get("voucher_type"),
"taxable_amount": voucher_details.get("amount"),
"voucher_name": row.voucher_name,
"voucher_type": row.voucher_type,
"taxable_amount": row.taxable_amount,
},
)

View File

@@ -45,12 +45,16 @@ frappe.listview_settings["Purchase Invoice"] = {
},
onload: function (listview) {
listview.page.add_action_item(__("Purchase Receipt"), () => {
erpnext.bulk_transaction_processing.create(listview, "Purchase Invoice", "Purchase Receipt");
});
if (frappe.model.can_create("Purchase Receipt")) {
listview.page.add_action_item(__("Purchase Receipt"), () => {
erpnext.bulk_transaction_processing.create(listview, "Purchase Invoice", "Purchase Receipt");
});
}
listview.page.add_action_item(__("Payment"), () => {
erpnext.bulk_transaction_processing.create(listview, "Purchase Invoice", "Payment Entry");
});
if (frappe.model.can_create("Payment Entry")) {
listview.page.add_action_item(__("Payment"), () => {
erpnext.bulk_transaction_processing.create(listview, "Purchase Invoice", "Payment Entry");
});
}
},
};

View File

@@ -383,6 +383,53 @@ class TestPurchaseInvoice(IntegrationTestCase, StockTestMixin):
self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)
def test_purchase_invoice_with_exchange_rate_difference_for_non_stock_item(self):
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
make_purchase_invoice as create_purchase_invoice,
)
# Creating Purchase Invoice with USD currency
pr = frappe.new_doc("Purchase Receipt")
pr.currency = "USD"
pr.company = "_Test Company with perpetual inventory"
pr.conversion_rate = (70,)
pr.supplier = "_Test Supplier USD"
pr.append(
"items",
{
"item_code": "_Test Non Stock Item",
"qty": 1,
"rate": 100,
},
)
pr.append(
"items",
{"item_code": "_Test Item", "qty": 1, "rate": 5, "warehouse": "Stores - TCP1"},
)
pr.insert()
pr.submit()
# Createing purchase invoice against Purchase Receipt
pi = create_purchase_invoice(pr.name)
pi.conversion_rate = 80
pi.credit_to = "_Test Payable USD - TCP1"
pi.insert()
pi.submit()
# Get exchnage gain and loss account
exchange_gain_loss_account = frappe.db.get_value("Company", pi.company, "exchange_gain_loss_account")
# fetching the latest GL Entry with exchange gain and loss account account
amount = frappe.db.get_value(
"GL Entry", {"account": exchange_gain_loss_account, "voucher_no": pi.name}, "debit"
)
discrepancy_caused_by_exchange_rate_diff = abs(
pi.items[1].base_net_amount - pr.items[1].base_net_amount
)
self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)
def test_purchase_invoice_change_naming_series(self):
pi = frappe.copy_doc(self.globalTestRecords["Purchase Invoice"][1])
pi.insert()
@@ -1845,6 +1892,52 @@ class TestPurchaseInvoice(IntegrationTestCase, StockTestMixin):
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1)
def test_adjust_incoming_rate_for_rejected_item(self):
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0)
frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 1)
# Cost of Item is zero in Purchase Receipt
pr = make_purchase_receipt(qty=1, rejected_qty=1, rate=0)
stock_value_difference = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
"stock_value_difference",
)
self.assertEqual(stock_value_difference, 0)
pi = create_purchase_invoice_from_receipt(pr.name)
for row in pi.items:
row.qty = 1
row.rate = 150
pi.save()
pi.submit()
stock_value_difference = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name, "warehouse": pi.items[0].warehouse},
"stock_value_difference",
)
self.assertEqual(stock_value_difference, 150)
stock_value_difference = frappe.db.get_value(
"Stock Ledger Entry",
{
"voucher_type": "Purchase Receipt",
"voucher_no": pr.name,
"warehouse": pi.items[0].rejected_warehouse,
},
"stock_value_difference",
)
self.assertFalse(stock_value_difference)
frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0)
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1)
def test_item_less_defaults(self):
pi = frappe.new_doc("Purchase Invoice")
pi.supplier = "_Test Supplier"
@@ -2465,6 +2558,34 @@ class TestPurchaseInvoice(IntegrationTestCase, StockTestMixin):
item.reload()
self.assertEqual(item.last_purchase_rate, 0)
def test_invoice_against_returned_pr(self):
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
make_purchase_invoice as make_purchase_invoice_from_pr,
)
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
make_purchase_return_against_rejected_warehouse,
)
item = make_item("_Test Item For Invoice Against Returned PR", properties={"is_stock_item": 1}).name
original_value = frappe.db.get_single_value(
"Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice"
)
frappe.db.set_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice", 0)
pr = make_purchase_receipt(item_code=item, qty=5, rejected_qty=5, rate=100)
pr_return = make_purchase_return_against_rejected_warehouse(pr.name)
pr_return.submit()
pi = make_purchase_invoice_from_pr(pr.name)
pi.save()
self.assertEqual(pi.items[0].qty, 5.0)
frappe.db.set_single_value(
"Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice", original_value
)
def set_advance_flag(company, flag, default_account):
frappe.db.set_value(

View File

@@ -14,7 +14,8 @@
"advance_amount",
"allocated_amount",
"exchange_gain_loss",
"ref_exchange_rate"
"ref_exchange_rate",
"difference_posting_date"
],
"fields": [
{
@@ -30,7 +31,7 @@
"width": "180px"
},
{
"columns": 3,
"columns": 2,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
@@ -40,7 +41,7 @@
"read_only": 1
},
{
"columns": 3,
"columns": 2,
"fieldname": "remarks",
"fieldtype": "Text",
"in_list_view": 1,
@@ -111,13 +112,20 @@
"label": "Reference Exchange Rate",
"non_negative": 1,
"read_only": 1
},
{
"columns": 2,
"fieldname": "difference_posting_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Difference Posting Date"
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:24.072896",
"modified": "2024-12-20 12:04:46.729972",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Advance",

View File

@@ -16,6 +16,7 @@ class PurchaseInvoiceAdvance(Document):
advance_amount: DF.Currency
allocated_amount: DF.Currency
difference_posting_date: DF.Date | None
exchange_gain_loss: DF.Currency
parent: DF.Data
parentfield: DF.Data

View File

@@ -181,7 +181,7 @@ def start_repost(account_repost_doc=str) -> None:
if not repost_doc.delete_cancelled_entries:
doc.make_gl_entries(1)
doc.make_gl_entries()
else:
elif doc.doctype in frappe.get_hooks("repost_allowed_doctypes"):
if hasattr(doc, "make_gl_entries") and callable(doc.make_gl_entries):
if not repost_doc.delete_cancelled_entries:
if "cancel" in inspect.getfullargspec(doc.make_gl_entries):

View File

@@ -16,6 +16,10 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
setup(doc) {
this.setup_posting_date_time_check();
super.setup(doc);
this.frm.make_methods = {
Dunning: this.make_dunning.bind(this),
"Invoice Discounting": this.make_invoice_discounting.bind(this),
};
}
company() {
super.company();
@@ -61,7 +65,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
refresh(doc, dt, dn) {
const me = this;
super.refresh();
if (this.frm.msgbox && this.frm.msgbox.$wrapper.is(":visible")) {
if (this.frm?.msgbox && this.frm.msgbox.$wrapper.is(":visible")) {
// hide new msgbox
this.frm.msgbox.hide();
}
@@ -125,12 +129,9 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
},
__("Create")
);
this.frm.add_custom_button(
__("Invoice Discounting"),
function () {
this.frm.events.create_invoice_discounting(this.frm);
},
this.make_invoice_discounting.bind(this),
__("Create")
);
@@ -139,22 +140,14 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
.reduce((prev, current) => prev || current, false);
if (payment_is_overdue) {
this.frm.add_custom_button(
__("Dunning"),
() => {
this.frm.events.create_dunning(this.frm);
},
__("Create")
);
this.frm.add_custom_button(__("Dunning"), this.make_dunning.bind(this), __("Create"));
}
}
if (doc.docstatus === 1) {
this.frm.add_custom_button(
__("Maintenance Schedule"),
function () {
this.frm.cscript.make_maintenance_schedule();
},
this.make_maintenance_schedule.bind(this),
__("Create")
);
}
@@ -189,6 +182,20 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
erpnext.accounts.unreconcile_payment.add_unreconcile_btn(me.frm);
}
make_invoice_discounting() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.create_invoice_discounting",
frm: this.frm,
});
}
make_dunning() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.create_dunning",
frm: this.frm,
});
}
make_maintenance_schedule() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_maintenance_schedule",
@@ -993,67 +1000,57 @@ frappe.ui.form.on("Sales Invoice", {
refresh: function (frm) {
if (frm.doc.docstatus === 0 && !frm.doc.is_return) {
frm.add_custom_button(__("Fetch Timesheet"), function () {
let d = new frappe.ui.Dialog({
title: __("Fetch Timesheet"),
fields: [
{
label: __("From"),
fieldname: "from_time",
fieldtype: "Date",
reqd: 1,
frm.add_custom_button(
__("Timesheet"),
function () {
let d = new frappe.ui.Dialog({
title: __("Fetch Timesheet"),
fields: [
{
label: __("From"),
fieldname: "from_time",
fieldtype: "Date",
reqd: 1,
},
{
fieldtype: "Column Break",
fieldname: "col_break_1",
},
{
label: __("To"),
fieldname: "to_time",
fieldtype: "Date",
reqd: 1,
},
{
label: __("Project"),
fieldname: "project",
fieldtype: "Link",
options: "Project",
default: frm.doc.project,
},
],
primary_action: function () {
const data = d.get_values();
frm.events.add_timesheet_data(frm, {
from_time: data.from_time,
to_time: data.to_time,
project: data.project,
});
d.hide();
},
{
fieldtype: "Column Break",
fieldname: "col_break_1",
},
{
label: __("To"),
fieldname: "to_time",
fieldtype: "Date",
reqd: 1,
},
{
label: __("Project"),
fieldname: "project",
fieldtype: "Link",
options: "Project",
default: frm.doc.project,
},
],
primary_action: function () {
const data = d.get_values();
frm.events.add_timesheet_data(frm, {
from_time: data.from_time,
to_time: data.to_time,
project: data.project,
});
d.hide();
},
primary_action_label: __("Get Timesheets"),
});
d.show();
});
primary_action_label: __("Get Timesheets"),
});
d.show();
},
__("Get Items From")
);
}
if (frm.doc.is_debit_note) {
frm.set_df_property("return_against", "label", __("Adjustment Against"));
}
},
create_invoice_discounting: function (frm) {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.create_invoice_discounting",
frm: frm,
});
},
create_dunning: function (frm) {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.create_dunning",
frm: frm,
});
},
});
frappe.ui.form.on("Sales Invoice Timesheet", {

View File

@@ -7,7 +7,6 @@
"engine": "InnoDB",
"field_order": [
"customer_section",
"title",
"naming_series",
"customer",
"customer_name",
@@ -229,18 +228,6 @@
"hide_seconds": 1,
"options": "fa fa-user"
},
{
"allow_on_submit": 1,
"default": "{customer_name}",
"fieldname": "title",
"fieldtype": "Data",
"hidden": 1,
"hide_days": 1,
"hide_seconds": 1,
"label": "Title",
"no_copy": 1,
"print_hide": 1
},
{
"bold": 1,
"fieldname": "naming_series",
@@ -304,7 +291,8 @@
"oldfieldname": "project_name",
"oldfieldtype": "Link",
"options": "Project",
"print_hide": 1
"print_hide": 1,
"search_index": 1
},
{
"default": "0",
@@ -2159,7 +2147,7 @@
{
"default": "1",
"depends_on": "eval: doc.is_return && doc.return_against",
"description": "Credit Note will update it's own outstanding amount, even if \"Return Against\" is specified.",
"description": "Credit Note will update it's own outstanding amount, even if 'Return Against' is specified.",
"fieldname": "update_outstanding_for_self",
"fieldtype": "Check",
"label": "Update Outstanding for Self",
@@ -2223,7 +2211,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2024-11-26 12:34:09.110690",
"modified": "2025-02-06 15:59:54.636202",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
@@ -2275,7 +2263,7 @@
"sort_order": "DESC",
"states": [],
"timeline_field": "customer",
"title_field": "title",
"title_field": "customer_name",
"track_changes": 1,
"track_seen": 1
}

View File

@@ -29,7 +29,11 @@ from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category
)
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
from erpnext.accounts.party import get_due_date, get_party_account, get_party_details
from erpnext.accounts.utils import cancel_exchange_gain_loss_journal, get_account_currency
from erpnext.accounts.utils import (
cancel_exchange_gain_loss_journal,
get_account_currency,
update_voucher_outstanding,
)
from erpnext.assets.doctype.asset.depreciation import (
depreciate_asset,
get_gl_entries_on_asset_disposal,
@@ -206,7 +210,6 @@ class SalesInvoice(SellingController):
terms: DF.TextEditor | None
territory: DF.Link | None
timesheets: DF.Table[SalesInvoiceTimesheet]
title: DF.Data | None
to_date: DF.Date | None
total: DF.Currency
total_advance: DF.Currency
@@ -323,9 +326,7 @@ class SalesInvoice(SellingController):
self.set_against_income_account()
self.validate_time_sheets_are_submitted()
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount")
if not self.is_return:
self.validate_serial_numbers()
else:
if self.is_return:
self.timesheets = []
self.update_packing_list()
self.set_billing_hours_and_amount()
@@ -364,7 +365,7 @@ class SalesInvoice(SellingController):
if self.update_stock:
frappe.throw(_("'Update Stock' cannot be checked for fixed asset sale"))
elif asset.status in ("Scrapped", "Cancelled", "Capitalized", "Decapitalized") or (
elif asset.status in ("Scrapped", "Cancelled", "Capitalized") or (
asset.status == "Sold" and not self.is_return
):
frappe.throw(
@@ -449,6 +450,8 @@ class SalesInvoice(SellingController):
self.make_bundle_for_sales_purchase_return(table_name)
self.make_bundle_using_old_serial_batch_fields(table_name)
self.update_stock_reservation_entries()
self.update_stock_ledger()
# this sequence because outstanding may get -ve
@@ -506,7 +509,7 @@ class SalesInvoice(SellingController):
frappe.throw(_("Total payments amount can't be greater than {}").format(-invoice_total))
def validate_pos_paid_amount(self):
if len(self.payments) == 0 and self.is_pos:
if len(self.payments) == 0 and self.is_pos and flt(self.grand_total) > 0:
frappe.throw(_("At least one mode of payment is required for POS invoice."))
def check_if_consolidated_invoice(self):
@@ -558,6 +561,7 @@ class SalesInvoice(SellingController):
self.make_gl_entries_on_cancel()
if self.update_stock == 1:
self.update_stock_reservation_entries()
self.repost_future_sle_and_gle()
self.db_set("status", "Cancelled")
@@ -1010,9 +1014,9 @@ class SalesInvoice(SellingController):
def validate_pos(self):
if self.is_return:
invoice_total = self.rounded_total or self.grand_total
if flt(self.paid_amount) + flt(self.write_off_amount) - flt(invoice_total) > 1.0 / (
10.0 ** (self.precision("grand_total") + 1.0)
):
if abs(flt(self.paid_amount)) + abs(flt(self.write_off_amount)) - abs(
flt(invoice_total)
) > 1.0 / (10.0 ** (self.precision("grand_total") + 1.0)):
frappe.throw(_("Paid amount + Write Off Amount can not be greater than Grand Total"))
def validate_warehouse(self):
@@ -1092,13 +1096,16 @@ class SalesInvoice(SellingController):
timesheet.billing_amount = ts_doc.total_billable_amount
def update_timesheet_billing_for_project(self):
if not self.timesheets and self.project:
self.add_timesheet_data()
else:
if self.timesheets:
self.calculate_billing_amount_for_timesheet()
@frappe.whitelist()
@frappe.whitelist(methods=["PUT"])
def add_timesheet_data(self):
if not self.timesheets and self.project:
self._add_timesheet_data()
self.save()
def _add_timesheet_data(self):
self.set("timesheets", [])
if self.project:
for data in get_projectwise_timesheet_data(self.project):
@@ -1192,14 +1199,14 @@ class SalesInvoice(SellingController):
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
if update_outstanding == "No":
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
update_outstanding_amt(
self.debit_to,
"Customer",
self.customer,
self.doctype,
self.return_against if cint(self.is_return) and self.return_against else self.name,
update_voucher_outstanding(
voucher_type=self.doctype,
voucher_no=self.return_against
if cint(self.is_return) and self.return_against
else self.name,
account=self.debit_to,
party_type="Customer",
party=self.customer,
)
elif self.docstatus == 2 and cint(self.update_stock) and cint(auto_accounting_for_stock):
@@ -1703,14 +1710,6 @@ class SalesInvoice(SellingController):
self.set("write_off_amount", reference_doc.get("write_off_amount"))
self.due_date = None
def validate_serial_numbers(self):
"""
validate serial number agains Delivery Note and Sales Invoice
"""
for item in self.items:
item.set_serial_no_against_delivery_note()
item.validate_serial_against_delivery_note()
def update_project(self):
unique_projects = list(set([d.project for d in self.get("items") if d.project]))
if self.project and self.project not in unique_projects:

View File

@@ -15,7 +15,7 @@ frappe.listview_settings["Sales Invoice"] = {
],
get_indicator: function (doc) {
const status_colors = {
Draft: "grey",
Draft: "red",
Unpaid: "orange",
Paid: "green",
Return: "gray",
@@ -32,12 +32,16 @@ frappe.listview_settings["Sales Invoice"] = {
right_column: "grand_total",
onload: function (listview) {
listview.page.add_action_item(__("Delivery Note"), () => {
erpnext.bulk_transaction_processing.create(listview, "Sales Invoice", "Delivery Note");
});
if (frappe.model.can_create("Delivery Note")) {
listview.page.add_action_item(__("Delivery Note"), () => {
erpnext.bulk_transaction_processing.create(listview, "Sales Invoice", "Delivery Note");
});
}
listview.page.add_action_item(__("Payment"), () => {
erpnext.bulk_transaction_processing.create(listview, "Sales Invoice", "Payment Entry");
});
if (frappe.model.can_create("Payment Entry")) {
listview.page.add_action_item(__("Payment"), () => {
erpnext.bulk_transaction_processing.create(listview, "Sales Invoice", "Payment Entry");
});
}
},
};

View File

@@ -43,6 +43,7 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import (
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
create_stock_reconciliation,
)
from erpnext.stock.get_item_details import get_item_tax_map
from erpnext.stock.utils import get_incoming_rate, get_stock_balance
@@ -2871,13 +2872,26 @@ class TestSalesInvoice(IntegrationTestCase):
item.save()
sales_invoice = create_sales_invoice(item="T Shirt", rate=700, do_not_submit=True)
item_tax_map = get_item_tax_map(
doc=sales_invoice,
tax_template=sales_invoice.items[0].item_tax_template,
)
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC")
self.assertEqual(sales_invoice.items[0].item_tax_rate, item_tax_map)
# Apply discount
sales_invoice.apply_discount_on = "Net Total"
sales_invoice.discount_amount = 300
sales_invoice.save()
item_tax_map = get_item_tax_map(
doc=sales_invoice,
tax_template=sales_invoice.items[0].item_tax_template,
)
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC")
self.assertEqual(sales_invoice.items[0].item_tax_rate, item_tax_map)
@IntegrationTestCase.change_settings("Selling Settings", {"enable_discount_accounting": 1})
def test_sales_invoice_with_discount_accounting_enabled(self):
@@ -4280,6 +4294,7 @@ class TestSalesInvoice(IntegrationTestCase):
si = create_sales_invoice(do_not_submit=True)
project = frappe.new_doc("Project")
project.company = "_Test Company"
project.project_name = "Test Total Billed Amount"
project.save()
@@ -4290,6 +4305,30 @@ class TestSalesInvoice(IntegrationTestCase):
doc = frappe.get_doc("Project", project.name)
self.assertEqual(doc.total_billed_amount, si.grand_total)
def test_pos_returns_with_party_account_currency(self):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_sales_return
pos_profile = make_pos_profile()
pos_profile.payments = []
pos_profile.append("payments", {"default": 1, "mode_of_payment": "Cash"})
pos_profile.save()
pos = create_sales_invoice(
customer="_Test Customer USD",
currency="USD",
conversion_rate=86.595000000,
qty=2,
do_not_save=True,
)
pos.is_pos = 1
pos.pos_profile = pos_profile.name
pos.debit_to = "_Test Receivable USD - _TC"
pos.append("payments", {"mode_of_payment": "Cash", "account": "_Test Bank - _TC", "amount": 20.35})
pos.save().submit()
pos_return = make_sales_return(pos.name)
self.assertEqual(abs(pos_return.payments[0].amount), pos.payments[0].amount)
def set_advance_flag(company, flag, default_account):
frappe.db.set_value(

View File

@@ -14,7 +14,8 @@
"advance_amount",
"allocated_amount",
"exchange_gain_loss",
"ref_exchange_rate"
"ref_exchange_rate",
"difference_posting_date"
],
"fields": [
{
@@ -30,7 +31,7 @@
"width": "250px"
},
{
"columns": 3,
"columns": 2,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
@@ -41,7 +42,7 @@
"read_only": 1
},
{
"columns": 3,
"columns": 2,
"fieldname": "remarks",
"fieldtype": "Text",
"in_list_view": 1,
@@ -112,13 +113,20 @@
"label": "Reference Exchange Rate",
"non_negative": 1,
"read_only": 1
},
{
"columns": 2,
"fieldname": "difference_posting_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Difference Posting Date"
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:36.003704",
"modified": "2024-12-20 11:58:28.962370",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Advance",

View File

@@ -16,6 +16,7 @@ class SalesInvoiceAdvance(Document):
advance_amount: DF.Currency
allocated_amount: DF.Currency
difference_posting_date: DF.Date | None
exchange_gain_loss: DF.Currency
parent: DF.Data
parentfield: DF.Data

View File

@@ -8,7 +8,7 @@ from frappe.model.document import Document
from frappe.utils.data import cint
from erpnext.assets.doctype.asset.depreciation import get_disposal_account_and_cost_center
from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no, get_serial_nos
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
class SalesInvoiceItem(Document):
@@ -128,39 +128,3 @@ class SalesInvoiceItem(Document):
self.income_account = disposal_account
if not self.cost_center:
self.cost_center = depreciation_cost_center
def set_serial_no_against_delivery_note(self):
"""Set serial no based on delivery note."""
if self.serial_no and self.delivery_note and self.qty != len(get_serial_nos(self.serial_no)):
self.serial_no = get_delivery_note_serial_no(self.item_code, self.qty, self.delivery_note)
def validate_serial_against_delivery_note(self):
"""Ensure the serial numbers in this Sales Invoice Item are same as in the linked Delivery Note."""
if not self.delivery_note or not self.dn_detail:
return
serial_nos = frappe.db.get_value("Delivery Note Item", self.dn_detail, "serial_no") or ""
dn_serial_nos = set(get_serial_nos(serial_nos))
serial_nos = self.serial_no or ""
si_serial_nos = set(get_serial_nos(serial_nos))
serial_no_diff = si_serial_nos - dn_serial_nos
if serial_no_diff:
dn_link = frappe.utils.get_link_to_form("Delivery Note", self.delivery_note)
msg = (
_("Row #{0}: The following serial numbers are not present in Delivery Note {1}:").format(
self.idx, dn_link
)
+ " "
+ ", ".join(frappe.bold(d) for d in serial_no_diff)
)
frappe.throw(msg=msg, title=_("Serial Nos Mismatch"))
if self.serial_no and cint(self.qty) != len(si_serial_nos):
frappe.throw(
_(
"Row #{0}: {1} serial numbers are required for Item {2}. You have provided {3} serial numbers."
).format(self.idx, self.qty, self.item_code, len(si_serial_nos))
)

View File

@@ -114,10 +114,10 @@ class Subscription(Document):
if self.trial_period_end and getdate(self.trial_period_end) > getdate(self.start_date):
_current_invoice_start = add_days(self.trial_period_end, 1)
elif self.trial_period_start and self.is_trialling():
_current_invoice_start = self.trial_period_start
elif date:
_current_invoice_start = date
elif self.trial_period_start and self.is_trialling():
_current_invoice_start = self.trial_period_start
else:
_current_invoice_start = nowdate()
@@ -414,8 +414,8 @@ class Subscription(Document):
if frappe.db.get_value("Supplier", self.party, "tax_withholding_category"):
invoice.apply_tds = 1
# Add party currency to invoice
invoice.currency = get_party_account_currency(self.party_type, self.party, self.company)
# Add currency to invoice
invoice.currency = frappe.db.get_value("Subscription Plan", {"name": self.plans[0].plan}, "currency")
# Add dimensions in invoice for subscription:
accounting_dimensions = get_accounting_dimensions()
@@ -634,9 +634,7 @@ class Subscription(Document):
"""
invoice = frappe.get_all(
self.invoice_document_type,
{
"subscription": self.name,
},
{"subscription": self.name, "docstatus": ("<", 2)},
limit=1,
order_by="to_date desc",
pluck="name",
@@ -675,6 +673,7 @@ class Subscription(Document):
self.invoice_document_type,
{
"subscription": self.name,
"docstatus": 1,
"status": ["!=", "Paid"],
},
)
@@ -697,7 +696,7 @@ class Subscription(Document):
self.status = "Cancelled"
self.cancelation_date = nowdate()
if to_generate_invoice:
if to_generate_invoice and self.cancelation_date >= self.current_invoice_start:
self.generate_invoice(self.current_invoice_start, self.cancelation_date)
self.save()

View File

@@ -479,6 +479,28 @@ class TestSubscription(IntegrationTestCase):
currency = frappe.db.get_value("Sales Invoice", subscription.invoices[0].name, "currency")
self.assertEqual(currency, "USD")
@IntegrationTestCase.change_settings(
"Accounts Settings",
{"allow_multi_currency_invoices_against_single_party_account": 1},
)
def test_multi_currency_subscription_with_default_company_currency(self):
party = "Test Subscription Customer Multi Currency"
frappe.db.set_value("Customer", party, "default_currency", "USD")
subscription = create_subscription(
start_date="2018-01-01",
generate_invoice_at="Beginning of the current subscription period",
plans=[{"plan": "_Test Plan Multicurrency", "qty": 1, "currency": "USD"}],
party=party,
)
subscription.process(posting_date="2018-01-01")
self.assertEqual(len(subscription.invoices), 1)
self.assertEqual(subscription.status, "Unpaid")
# Check the currency of the created invoice
currency = frappe.db.get_value("Sales Invoice", subscription.invoices[0].name, "currency")
self.assertEqual(currency, "USD")
def test_subscription_recovery(self):
"""Test if Subscription recovers when start/end date run out of sync with created invoices."""
subscription = create_subscription(
@@ -590,6 +612,12 @@ def create_parties():
customer.append("accounts", {"company": "_Test Company", "account": "_Test Receivable USD - _TC"})
customer.insert()
if not frappe.db.exists("Customer", "_Test Subscription Customer Multi Currency"):
customer = frappe.new_doc("Customer")
customer.customer_name = "Test Subscription Customer Multi Currency"
customer.default_currency = "USD"
customer.insert()
if not frappe.db.exists("Customer", "_Test Subscription Customer John Doe"):
customer = frappe.new_doc("Customer")
customer.customer_name = "_Test Subscription Customer John Doe"

View File

@@ -87,6 +87,7 @@ def get_party_details(inv):
def get_party_tax_withholding_details(inv, tax_withholding_category=None):
if inv.doctype == "Payment Entry":
inv.tax_withholding_net_total = inv.net_total
inv.base_tax_withholding_net_total = inv.net_total
pan_no = ""
parties = []
@@ -156,6 +157,9 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None):
}
)
if cint(tax_details.round_off_tax_amount):
inv.round_off_applicable_accounts_for_tax_withholding = tax_details.account_head
if inv.doctype == "Purchase Invoice":
return tax_row, tax_deducted_on_advances, voucher_wise_amount
else:
@@ -247,14 +251,14 @@ def get_tax_row_for_tds(tax_details, tax_amount):
}
def get_lower_deduction_certificate(company, tax_details, pan_no):
def get_lower_deduction_certificate(company, posting_date, tax_details, pan_no):
ldc_name = frappe.db.get_value(
"Lower Deduction Certificate",
{
"pan_no": pan_no,
"tax_withholding_category": tax_details.tax_withholding_category,
"valid_from": (">=", tax_details.from_date),
"valid_upto": ("<=", tax_details.to_date),
"valid_from": ("<=", posting_date),
"valid_upto": (">=", posting_date),
"company": company,
},
"name",
@@ -266,7 +270,10 @@ def get_lower_deduction_certificate(company, tax_details, pan_no):
def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=None):
vouchers, voucher_wise_amount = get_invoice_vouchers(
parties, tax_details, inv.company, party_type=party_type
parties,
tax_details,
inv.company,
party_type=party_type,
)
payment_entry_vouchers = get_payment_entry_vouchers(
@@ -302,7 +309,11 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
tax_amount = 0
if party_type == "Supplier":
ldc = get_lower_deduction_certificate(inv.company, tax_details, pan_no)
# if tds account is changed.
if not tax_deducted:
tax_deducted = is_tax_deducted_on_the_basis_of_inv(vouchers)
ldc = get_lower_deduction_certificate(inv.company, posting_date, tax_details, pan_no)
if tax_deducted:
net_total = inv.tax_withholding_net_total
if ldc:
@@ -319,7 +330,7 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
# once tds is deducted, not need to add vouchers in the invoice
voucher_wise_amount = {}
else:
tax_amount = get_tds_amount(ldc, parties, inv, tax_details, vouchers)
tax_amount = get_tds_amount(ldc, parties, inv, tax_details, voucher_wise_amount)
elif party_type == "Customer":
if tax_deducted:
@@ -336,14 +347,41 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
return tax_amount, tax_deducted, tax_deducted_on_advances, voucher_wise_amount
def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
doctype = "Purchase Invoice" if party_type == "Supplier" else "Sales Invoice"
field = (
"base_tax_withholding_net_total as base_net_total" if party_type == "Supplier" else "base_net_total"
def is_tax_deducted_on_the_basis_of_inv(vouchers):
return frappe.db.exists(
"Purchase Taxes and Charges",
{
"parent": ["in", vouchers],
"is_tax_withholding_account": 1,
"parenttype": "Purchase Invoice",
"base_tax_amount_after_discount_amount": [">", 0],
},
)
voucher_wise_amount = {}
def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
voucher_wise_amount = []
vouchers = []
ldcs = frappe.db.get_all(
"Lower Deduction Certificate",
filters={
"valid_from": [">=", tax_details.from_date],
"valid_upto": ["<=", tax_details.to_date],
"company": company,
"supplier": ["in", parties],
},
fields=["supplier", "valid_from", "valid_upto", "rate"],
)
doctype = "Purchase Invoice" if party_type == "Supplier" else "Sales Invoice"
field = [
"base_tax_withholding_net_total as base_net_total" if party_type == "Supplier" else "base_net_total",
"name",
"grand_total",
"posting_date",
]
filters = {
"company": company,
frappe.scrub(party_type): ["in", parties],
@@ -357,15 +395,29 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
{"apply_tds": 1, "tax_withholding_category": tax_details.get("tax_withholding_category")}
)
invoices_details = frappe.get_all(doctype, filters=filters, fields=["name", field])
invoices_details = frappe.get_all(doctype, filters=filters, fields=field)
for d in invoices_details:
vouchers.append(d.name)
voucher_wise_amount.update({d.name: {"amount": d.base_net_total, "voucher_type": doctype}})
d = frappe._dict(
{
"voucher_name": d.name,
"voucher_type": doctype,
"taxable_amount": d.base_net_total,
"grand_total": d.grand_total,
"posting_date": d.posting_date,
}
)
if ldc := [x for x in ldcs if d.posting_date >= x.valid_from and d.posting_date <= x.valid_upto]:
if ldc[0].supplier in parties and ldc[0].rate == 0:
d.update({"taxable_amount": 0})
vouchers.append(d.voucher_name)
voucher_wise_amount.append(d)
journal_entries_details = frappe.db.sql(
"""
SELECT j.name, ja.credit - ja.debit AS amount
SELECT j.name, ja.credit - ja.debit AS amount, ja.reference_type
FROM `tabJournal Entry` j, `tabJournal Entry Account` ja
WHERE
j.name = ja.parent
@@ -384,13 +436,20 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
tax_details.get("tax_withholding_category"),
company,
),
as_dict=1,
)
if journal_entries_details:
for d in journal_entries_details:
vouchers.append(d.name)
voucher_wise_amount.update({d.name: {"amount": d.amount, "voucher_type": "Journal Entry"}})
for d in journal_entries_details:
vouchers.append(d.name)
voucher_wise_amount.append(
frappe._dict(
{
"voucher_name": d.name,
"voucher_type": "Journal Entry",
"taxable_amount": d.amount,
"reference_type": d.reference_type,
}
)
)
return vouchers, voucher_wise_amount
@@ -489,12 +548,24 @@ def get_advance_tax_across_fiscal_year(tax_deducted_on_advances, tax_details):
return advance_tax_from_across_fiscal_year
def get_tds_amount(ldc, parties, inv, tax_details, vouchers):
def get_tds_amount(ldc, parties, inv, tax_details, voucher_wise_amount):
tds_amount = 0
invoice_filters = {"name": ("in", vouchers), "docstatus": 1, "apply_tds": 1}
pi_grand_total = 0
pi_base_net_total = 0
jv_credit_amt = 0
pe_credit_amt = 0
for row in voucher_wise_amount:
if row.voucher_type == "Purchase Invoice":
pi_grand_total += row.get("grand_total", 0)
pi_base_net_total += row.get("taxable_amount", 0)
if row.voucher_type == "Journal Entry" and row.reference_type != "Purchase Invoice":
jv_credit_amt += row.get("taxable_amount", 0)
## for TDS to be deducted on advances
payment_entry_filters = {
pe_filters = {
"party_type": "Supplier",
"party": ("in", parties),
"docstatus": 1,
@@ -505,70 +576,49 @@ def get_tds_amount(ldc, parties, inv, tax_details, vouchers):
"company": inv.company,
}
field = "sum(tax_withholding_net_total)"
consider_party_ledger_amt = cint(tax_details.consider_party_ledger_amount)
if cint(tax_details.consider_party_ledger_amount):
invoice_filters.pop("apply_tds", None)
field = "sum(grand_total)"
payment_entry_filters.pop("apply_tax_withholding_amount", None)
payment_entry_filters.pop("tax_withholding_category", None)
supp_inv_credit_amt = frappe.db.get_value("Purchase Invoice", invoice_filters, field) or 0.0
supp_jv_credit_amt = (
frappe.db.get_value(
"Journal Entry Account",
{
"parent": ("in", vouchers),
"docstatus": 1,
"party": ("in", parties),
"reference_type": ("!=", "Purchase Invoice"),
},
"sum(credit_in_account_currency - debit_in_account_currency)",
)
or 0.0
)
if consider_party_ledger_amt:
pe_filters.pop("apply_tax_withholding_amount", None)
pe_filters.pop("tax_withholding_category", None)
# Get Amount via payment entry
payment_entry_amounts = frappe.db.get_all(
payment_entries = frappe.db.get_all(
"Payment Entry",
filters=payment_entry_filters,
fields=["sum(unallocated_amount) as amount", "payment_type"],
group_by="payment_type",
filters=pe_filters,
fields=["name", "unallocated_amount as taxable_amount", "payment_type"],
)
supp_credit_amt = supp_jv_credit_amt
supp_credit_amt += inv.tax_withholding_net_total
for type in payment_entry_amounts:
if type.payment_type == "Pay":
supp_credit_amt += type.amount
else:
supp_credit_amt -= type.amount
for row in payment_entries:
value = row.taxable_amount if row.payment_type == "Pay" else -1 * row.taxable_amount
pe_credit_amt += value
voucher_wise_amount.append(
frappe._dict(
{
"voucher_name": row.name,
"voucher_type": "Payment Entry",
"taxable_amount": value,
}
)
)
threshold = tax_details.get("threshold", 0)
cumulative_threshold = tax_details.get("cumulative_threshold", 0)
supp_credit_amt = jv_credit_amt + pe_credit_amt + inv.get("tax_withholding_net_total", 0)
tax_withholding_net_total = inv.get("base_tax_withholding_net_total", 0)
if inv.doctype != "Payment Entry":
tax_withholding_net_total = inv.base_tax_withholding_net_total
else:
tax_withholding_net_total = inv.tax_withholding_net_total
# if consider_party_ledger_amount is checked, then threshold will be based on grand total
amt_for_threshold = pi_grand_total if consider_party_ledger_amt else pi_base_net_total
if (threshold and tax_withholding_net_total >= threshold) or (
cumulative_threshold and (supp_credit_amt + supp_inv_credit_amt) >= cumulative_threshold
):
# Get net total again as TDS is calculated on net total
# Grand is used to just check for threshold breach
net_total = (
frappe.db.get_value("Purchase Invoice", invoice_filters, "sum(tax_withholding_net_total)") or 0.0
)
supp_credit_amt += net_total
cumulative_threshold_breached = (
cumulative_threshold and (supp_credit_amt + amt_for_threshold) >= cumulative_threshold
)
if (cumulative_threshold and supp_credit_amt >= cumulative_threshold) and cint(
tax_details.tax_on_excess_amount
):
supp_credit_amt = net_total + tax_withholding_net_total - cumulative_threshold
if (threshold and tax_withholding_net_total >= threshold) or (cumulative_threshold_breached):
supp_credit_amt += pi_base_net_total
if cumulative_threshold_breached and cint(tax_details.tax_on_excess_amount):
supp_credit_amt = pi_base_net_total + tax_withholding_net_total - cumulative_threshold
if ldc and is_valid_certificate(ldc, inv.get("posting_date") or inv.get("transaction_date"), 0):
tds_amount = get_lower_deduction_amount(

View File

@@ -7,7 +7,7 @@ import unittest
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.tests import IntegrationTestCase, UnitTestCase
from frappe.utils import add_days, today
from frappe.utils import add_days, add_months, today
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.utils import get_fiscal_year
@@ -71,6 +71,49 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
for d in reversed(invoices):
d.cancel()
def test_tds_with_account_changed(self):
frappe.db.set_value(
"Supplier", "Test TDS Supplier", "tax_withholding_category", "Multi Account TDS Category"
)
invoices = []
# create invoices for lower than single threshold tax rate
for _ in range(2):
pi = create_purchase_invoice(supplier="Test TDS Supplier")
pi.submit()
invoices.append(pi)
# create another invoice whose total when added to previously created invoice,
# surpasses cumulative threshhold
pi = create_purchase_invoice(supplier="Test TDS Supplier")
pi.submit()
# assert equal tax deduction on total invoice amount until now
self.assertEqual(pi.taxes_and_charges_deducted, 3000)
self.assertEqual(pi.grand_total, 7000)
invoices.append(pi)
# account changed
frappe.db.set_value(
"Tax Withholding Account",
{"parent": "Multi Account TDS Category"},
"account",
"_Test Account VAT - _TC",
)
# TDS should be on invoice only even though account is changed
pi = create_purchase_invoice(supplier="Test TDS Supplier", rate=5000)
pi.submit()
# assert equal tax deduction on total invoice amount until now
self.assertEqual(pi.taxes_and_charges_deducted, 500)
invoices.append(pi)
# delete invoices to avoid clashing
for d in reversed(invoices):
d.cancel()
def test_single_threshold_tds(self):
invoices = []
frappe.db.set_value(
@@ -536,6 +579,15 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
pi1.submit()
invoices.append(pi1)
pe = create_payment_entry(
payment_type="Pay", party_type="Supplier", party="Test TDS Supplier6", paid_amount=1000
)
pe.apply_tax_withholding_amount = 1
pe.tax_withholding_category = "Test Multi Invoice Category"
pe.save()
pe.submit()
invoices.append(pe)
pi2 = create_purchase_invoice(supplier="Test TDS Supplier6", rate=9000, do_not_save=True)
pi2.apply_tds = 1
pi2.tax_withholding_category = "Test Multi Invoice Category"
@@ -551,6 +603,8 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
self.assertTrue(pi2.tax_withheld_vouchers[0].taxable_amount == pi1.net_total)
self.assertTrue(pi2.tax_withheld_vouchers[1].voucher_name == pi.name)
self.assertTrue(pi2.tax_withheld_vouchers[1].taxable_amount == pi.net_total)
self.assertTrue(pi2.tax_withheld_vouchers[2].voucher_name == pe.name)
self.assertTrue(pi2.tax_withheld_vouchers[2].taxable_amount == pe.paid_amount)
# cancel invoices to avoid clashing
for d in reversed(invoices):
@@ -622,6 +676,49 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
pi2.cancel()
pi3.cancel()
def test_ldc_at_0_rate(self):
frappe.db.set_value(
"Supplier",
"Test LDC Supplier",
{
"tax_withholding_category": "Test Service Category",
"pan": "ABCTY1234D",
},
)
fiscal_year = get_fiscal_year(today(), company="_Test Company")
valid_from = fiscal_year[1]
valid_upto = add_months(valid_from, 1)
create_lower_deduction_certificate(
supplier="Test LDC Supplier",
certificate_no="1AE0423AAJ",
tax_withholding_category="Test Service Category",
tax_rate=0,
limit=50000,
valid_from=valid_from,
valid_upto=valid_upto,
)
pi1 = create_purchase_invoice(
supplier="Test LDC Supplier", rate=35000, posting_date=valid_from, set_posting_time=True
)
pi1.submit()
self.assertEqual(pi1.taxes, [])
pi2 = create_purchase_invoice(
supplier="Test LDC Supplier",
rate=35000,
posting_date=add_days(valid_upto, 1),
set_posting_time=True,
)
pi2.submit()
self.assertEqual(len(pi2.taxes), 1)
# pi1 net total shouldn't be included as it lies within LDC at rate of '0'
self.assertEqual(pi2.taxes[0].tax_amount, 3500)
pi1.cancel()
pi2.cancel()
def set_previous_fy_and_tax_category(self):
test_company = "_Test Company"
category = "Cumulative Threshold TDS"
@@ -779,7 +876,8 @@ def create_purchase_invoice(**args):
pi = frappe.get_doc(
{
"doctype": "Purchase Invoice",
"posting_date": today(),
"set_posting_time": args.set_posting_time or False,
"posting_date": args.posting_date or today(),
"apply_tds": 0 if args.do_not_apply_tds else 1,
"supplier": args.supplier,
"company": "_Test Company",
@@ -1071,6 +1169,16 @@ def create_tax_withholding_category_records():
consider_party_ledger_amount=1,
)
create_tax_withholding_category(
category_name="Multi Account TDS Category",
rate=10,
from_date=from_date,
to_date=to_date,
account="TDS - _TC",
single_threshold=0,
cumulative_threshold=30000,
)
def create_tax_withholding_category(
category_name,
@@ -1107,7 +1215,9 @@ def create_tax_withholding_category(
).insert()
def create_lower_deduction_certificate(supplier, tax_withholding_category, tax_rate, certificate_no, limit):
def create_lower_deduction_certificate(
supplier, tax_withholding_category, tax_rate, certificate_no, limit, valid_from=None, valid_upto=None
):
fiscal_year = get_fiscal_year(today(), company="_Test Company")
if not frappe.db.exists("Lower Deduction Certificate", certificate_no):
frappe.get_doc(
@@ -1118,8 +1228,8 @@ def create_lower_deduction_certificate(supplier, tax_withholding_category, tax_r
"certificate_no": certificate_no,
"tax_withholding_category": tax_withholding_category,
"fiscal_year": fiscal_year[0],
"valid_from": fiscal_year[1],
"valid_upto": fiscal_year[2],
"valid_from": valid_from or fiscal_year[1],
"valid_upto": valid_upto or fiscal_year[2],
"rate": tax_rate,
"certificate_limit": limit,
}

View File

@@ -36,7 +36,7 @@ def make_gl_entries(
make_acc_dimensions_offsetting_entry(gl_map)
validate_accounting_period(gl_map)
validate_disabled_accounts(gl_map)
gl_map = process_gl_map(gl_map, merge_entries)
gl_map = process_gl_map(gl_map, merge_entries, from_repost=from_repost)
if gl_map and len(gl_map) > 1:
if gl_map[0].voucher_type != "Period Closing Voucher":
create_payment_ledger_entry(
@@ -164,12 +164,12 @@ def validate_accounting_period(gl_map):
)
def process_gl_map(gl_map, merge_entries=True, precision=None):
def process_gl_map(gl_map, merge_entries=True, precision=None, from_repost=False):
if not gl_map:
return []
if gl_map[0].voucher_type != "Period Closing Voucher":
gl_map = distribute_gl_based_on_cost_center_allocation(gl_map, precision)
gl_map = distribute_gl_based_on_cost_center_allocation(gl_map, precision, from_repost)
if merge_entries:
gl_map = merge_similar_entries(gl_map, precision)
@@ -179,13 +179,17 @@ def process_gl_map(gl_map, merge_entries=True, precision=None):
return gl_map
def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None):
def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None, from_repost=False):
new_gl_map = []
for d in gl_map:
cost_center = d.get("cost_center")
# Validate budget against main cost center
validate_expense_against_budget(d, expense_amount=flt(d.debit, precision) - flt(d.credit, precision))
if not from_repost:
validate_expense_against_budget(
d, expense_amount=flt(d.debit, precision) - flt(d.credit, precision)
)
cost_center_allocation = get_cost_center_allocation_data(
gl_map[0]["company"], gl_map[0]["posting_date"], cost_center
)
@@ -677,11 +681,15 @@ def make_reverse_gl_entries(
debit_in_account_currency = new_gle.get("debit_in_account_currency", 0)
credit_in_account_currency = new_gle.get("credit_in_account_currency", 0)
debit_in_transaction_currency = new_gle.get("debit_in_transaction_currency", 0)
credit_in_transaction_currency = new_gle.get("credit_in_transaction_currency", 0)
new_gle["debit"] = credit
new_gle["credit"] = debit
new_gle["debit_in_account_currency"] = credit_in_account_currency
new_gle["credit_in_account_currency"] = debit_in_account_currency
new_gle["debit_in_transaction_currency"] = credit_in_transaction_currency
new_gle["credit_in_transaction_currency"] = debit_in_transaction_currency
new_gle["remarks"] = "On cancellation of " + new_gle["voucher_no"]
new_gle["is_cancelled"] = 1

View File

@@ -5,13 +5,13 @@
"doctype": "Number Card",
"document_type": "Purchase Invoice",
"dynamic_filters_json": "[[\"Purchase Invoice\",\"company\",\"=\",\" frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
"filters_json": "[[\"Purchase Invoice\",\"docstatus\",\"=\",\"1\",false],[\"Purchase Invoice\",\"posting_date\",\"Timespan\",\"this year\",false]]",
"filters_json": "[[\"Purchase Invoice\",\"docstatus\",\"=\",\"1\"],[\"Purchase Invoice\",\"posting_date\",\"Timespan\",\"this year\"]]",
"function": "Sum",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"label": "Total Incoming Bills",
"modified": "2024-11-20 19:08:37.043777",
"modified": "2024-12-05 12:00:00.000000",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Total Incoming Bills",

View File

@@ -5,13 +5,13 @@
"doctype": "Number Card",
"document_type": "Payment Entry",
"dynamic_filters_json": "[[\"Payment Entry\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
"filters_json": "[[\"Payment Entry\",\"docstatus\",\"=\",\"1\",false],[\"Payment Entry\",\"posting_date\",\"Timespan\",\"this year\",false],[\"Payment Entry\",\"payment_type\",\"=\",\"Receive\",false]]",
"filters_json": "[[\"Payment Entry\",\"docstatus\",\"=\",\"1\"],[\"Payment Entry\",\"posting_date\",\"Timespan\",\"this year\"],[\"Payment Entry\",\"payment_type\",\"=\",\"Receive\"]]",
"function": "Sum",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"label": "Total Incoming Payment",
"modified": "2020-07-22 13:06:20.237689",
"modified": "2024-12-05 12:00:00.000000",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Total Incoming Payment",

View File

@@ -5,13 +5,13 @@
"doctype": "Number Card",
"document_type": "Sales Invoice",
"dynamic_filters_json": "[[\"Sales Invoice\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
"filters_json": "[[\"Sales Invoice\",\"docstatus\",\"=\",\"1\",false],[\"Sales Invoice\",\"posting_date\",\"Timespan\",\"this year\",false]]",
"filters_json": "[[\"Sales Invoice\",\"docstatus\",\"=\",\"1\"],[\"Sales Invoice\",\"posting_date\",\"Timespan\",\"this year\"]]",
"function": "Sum",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"label": "Total Outgoing Bills",
"modified": "2020-07-22 13:07:19.633101",
"modified": "2024-12-05 12:00:00.000000",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Total Outgoing Bills",

View File

@@ -5,13 +5,13 @@
"doctype": "Number Card",
"document_type": "Payment Entry",
"dynamic_filters_json": "[[\"Payment Entry\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
"filters_json": "[[\"Payment Entry\",\"docstatus\",\"=\",\"1\",false],[\"Payment Entry\",\"posting_date\",\"Timespan\",\"this year\",false],[\"Payment Entry\",\"payment_type\",\"=\",\"Pay\",false]]",
"filters_json": "[[\"Payment Entry\",\"docstatus\",\"=\",\"1\"],[\"Payment Entry\",\"posting_date\",\"Timespan\",\"this year\"],[\"Payment Entry\",\"payment_type\",\"=\",\"Pay\"]]",
"function": "Sum",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"label": "Total Outgoing Payment",
"modified": "2020-07-22 12:49:34.942896",
"modified": "2024-12-05 12:00:00.000000",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Total Outgoing Payment",

View File

@@ -621,34 +621,41 @@ def get_due_date_from_template(template_name, posting_date, bill_date):
return due_date
def validate_due_date(posting_date, due_date, bill_date=None, template_name=None):
def validate_due_date(posting_date, due_date, bill_date=None, template_name=None, doctype=None):
if getdate(due_date) < getdate(posting_date):
frappe.throw(_("Due Date cannot be before Posting / Supplier Invoice Date"))
doctype_date = "Date"
if doctype == "Purchase Invoice":
doctype_date = "Supplier Invoice Date"
if doctype == "Sales Invoice":
doctype_date = "Posting Date"
frappe.throw(_("Due Date cannot be before {0}").format(doctype_date))
else:
if not template_name:
return
validate_due_date_with_template(posting_date, due_date, bill_date, template_name)
default_due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime(
"%Y-%m-%d"
def validate_due_date_with_template(posting_date, due_date, bill_date, template_name):
if not template_name:
return
default_due_date = format(get_due_date_from_template(template_name, posting_date, bill_date))
if not default_due_date:
return
if default_due_date != posting_date and getdate(due_date) > getdate(default_due_date):
is_credit_controller = (
frappe.db.get_single_value("Accounts Settings", "credit_controller") in frappe.get_roles()
)
if not default_due_date:
return
if default_due_date != posting_date and getdate(due_date) > getdate(default_due_date):
is_credit_controller = (
frappe.db.get_single_value("Accounts Settings", "credit_controller") in frappe.get_roles()
if is_credit_controller:
msgprint(
_("Note: Due Date exceeds allowed customer credit days by {0} day(s)").format(
date_diff(due_date, default_due_date)
)
)
if is_credit_controller:
msgprint(
_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)").format(
date_diff(due_date, default_due_date)
)
)
else:
frappe.throw(
_("Due / Reference Date cannot be after {0}").format(formatdate(default_due_date))
)
else:
frappe.throw(_("Due Date cannot be after {0}").format(formatdate(default_due_date)))
@frappe.whitelist()
@@ -681,7 +688,7 @@ def set_taxes(
):
from erpnext.accounts.doctype.tax_rule.tax_rule import get_party_details, get_tax_template
args = {party_type.lower(): party, "company": company}
args = {frappe.scrub(party_type): party, "company": company}
if tax_category:
args["tax_category"] = tax_category
@@ -701,10 +708,10 @@ def set_taxes(
else:
args.update(get_party_details(party, party_type))
if party_type in ("Customer", "Lead", "Prospect"):
if party_type in ("Customer", "Lead", "Prospect", "CRM Deal"):
args.update({"tax_type": "Sales"})
if party_type in ["Lead", "Prospect"]:
if party_type in ["Lead", "Prospect", "CRM Deal"]:
args["customer"] = None
del args[frappe.scrub(party_type)]
else:
@@ -764,6 +771,20 @@ def validate_party_frozen_disabled(party_type, party_name):
frappe.msgprint(_("{0} {1} is not active").format(party_type, party_name), alert=True)
def validate_account_party_type(self):
if self.is_cancelled:
return
if self.party_type and self.party:
account_type = frappe.get_cached_value("Account", self.account, "account_type")
if account_type and (account_type not in ["Receivable", "Payable", "Equity"]):
frappe.throw(
_(
"Party Type and Party can only be set for Receivable / Payable account<br><br>" "{0}"
).format(self.account)
)
def get_dashboard_info(party_type, party, loyalty_program=None):
current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True)

View File

@@ -44,7 +44,7 @@
{% endfor %}
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
<td class="left" >{{ gl | sum(attribute='debit') | round(2) }}</td>
</tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
@@ -61,7 +61,7 @@
{% endfor %}
<tr>
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
<td class="left" >{{ gl | sum(attribute='credit') | round(2) }}</td>
</tr>
<tr>
<td class="top-bottom" colspan="5"><b>Narration: </b>{{ gl[0].remarks }}</td>

View File

@@ -89,6 +89,7 @@ frappe.query_reports["Accounts Payable"] = {
fieldname: "party",
label: __("Party"),
fieldtype: "MultiSelectList",
options: "party_type",
get_data: function (txt) {
if (!frappe.query_report.filters) return;

View File

@@ -66,6 +66,7 @@ frappe.query_reports["Accounts Payable Summary"] = {
fieldname: "party",
label: __("Party"),
fieldtype: "MultiSelectList",
options: "party_type",
get_data: function (txt) {
if (!frappe.query_report.filters) return;

View File

@@ -56,6 +56,7 @@ frappe.query_reports["Accounts Receivable"] = {
fieldname: "party",
label: __("Party"),
fieldtype: "MultiSelectList",
options: "party_type",
get_data: function (txt) {
if (!frappe.query_report.filters) return;

View File

@@ -134,7 +134,6 @@ class ReceivablePayableReport:
paid_in_account_currency=0.0,
credit_note_in_account_currency=0.0,
outstanding_in_account_currency=0.0,
cost_center=ple.cost_center,
)
def init_voucher_balance(self):
@@ -150,6 +149,9 @@ class ReceivablePayableReport:
if key not in self.voucher_balance:
self.voucher_balance[key] = self.build_voucher_dict(ple)
if ple.voucher_type == ple.against_voucher_type and ple.voucher_no == ple.against_voucher_no:
self.voucher_balance[key].cost_center = ple.cost_center
self.get_invoices(ple)
if self.filters.get("group_by_party"):
@@ -275,9 +277,6 @@ class ReceivablePayableReport:
row.paid -= amount
row.paid_in_account_currency -= amount_in_account_currency
if not row.cost_center and ple.cost_center:
row.cost_center = str(ple.cost_center)
def update_sub_total_row(self, row, party):
total_row = self.total_row_map.get(party)
@@ -551,9 +550,7 @@ class ReceivablePayableReport:
self.append_payment_term(row, d, term)
def append_payment_term(self, row, d, term):
if (
self.filters.get("customer") or self.filters.get("supplier")
) and d.currency == d.party_account_currency:
if d.currency == d.party_account_currency:
invoiced = d.payment_amount
else:
invoiced = d.base_payment_amount

View File

@@ -66,6 +66,7 @@ frappe.query_reports["Accounts Receivable Summary"] = {
fieldname: "party",
label: __("Party"),
fieldtype: "MultiSelectList",
options: "party_type",
get_data: function (txt) {
if (!frappe.query_report.filters) return;

View File

@@ -28,15 +28,14 @@ def get_group_by_asset_category_data(filters):
for asset_category in asset_categories:
row = frappe._dict()
# row.asset_category = asset_category
row.update(asset_category)
row.cost_as_on_to_date = (
flt(row.cost_as_on_from_date)
+ flt(row.cost_of_new_purchase)
- flt(row.cost_of_sold_asset)
- flt(row.cost_of_scrapped_asset)
- flt(row.cost_of_capitalized_asset)
row.value_as_on_to_date = (
flt(row.value_as_on_from_date)
+ flt(row.value_of_new_purchase)
- flt(row.value_of_sold_asset)
- flt(row.value_of_scrapped_asset)
- flt(row.value_of_capitalized_asset)
)
row.update(
@@ -53,11 +52,11 @@ def get_group_by_asset_category_data(filters):
- flt(row.depreciation_eliminated_during_the_period)
)
row.net_asset_value_as_on_from_date = flt(row.cost_as_on_from_date) - flt(
row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt(
row.accumulated_depreciation_as_on_from_date
)
row.net_asset_value_as_on_to_date = flt(row.cost_as_on_to_date) - flt(
row.net_asset_value_as_on_to_date = flt(row.value_as_on_to_date) - flt(
row.accumulated_depreciation_as_on_to_date
)
@@ -85,12 +84,12 @@ def get_asset_categories_for_grouped_by_category(filters):
end
else
0
end), 0) as cost_as_on_from_date,
end), 0) as value_as_on_from_date,
ifnull(sum(case when a.purchase_date >= %(from_date)s then
a.gross_purchase_amount
else
0
end), 0) as cost_of_new_purchase,
end), 0) as value_of_new_purchase,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
@@ -101,7 +100,7 @@ def get_asset_categories_for_grouped_by_category(filters):
end
else
0
end), 0) as cost_of_sold_asset,
end), 0) as value_of_sold_asset,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
@@ -112,7 +111,7 @@ def get_asset_categories_for_grouped_by_category(filters):
end
else
0
end), 0) as cost_of_scrapped_asset,
end), 0) as value_of_scrapped_asset,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
@@ -123,7 +122,7 @@ def get_asset_categories_for_grouped_by_category(filters):
end
else
0
end), 0) as cost_of_capitalized_asset
end), 0) as value_of_capitalized_asset
from `tabAsset` a
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
and not exists(
@@ -164,12 +163,12 @@ def get_asset_details_for_grouped_by_category(filters):
end
else
0
end), 0) as cost_as_on_from_date,
end), 0) as value_as_on_from_date,
ifnull(sum(case when a.purchase_date >= %(from_date)s then
a.gross_purchase_amount
else
0
end), 0) as cost_of_new_purchase,
end), 0) as value_of_new_purchase,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
@@ -180,7 +179,7 @@ def get_asset_details_for_grouped_by_category(filters):
end
else
0
end), 0) as cost_of_sold_asset,
end), 0) as value_of_sold_asset,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
@@ -191,7 +190,7 @@ def get_asset_details_for_grouped_by_category(filters):
end
else
0
end), 0) as cost_of_scrapped_asset,
end), 0) as value_of_scrapped_asset,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
@@ -202,7 +201,7 @@ def get_asset_details_for_grouped_by_category(filters):
end
else
0
end), 0) as cost_of_capitalized_asset
end), 0) as value_of_capitalized_asset
from `tabAsset` a
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
and not exists(
@@ -232,15 +231,14 @@ def get_group_by_asset_data(filters):
for asset_detail in asset_details:
row = frappe._dict()
# row.asset_category = asset_category
row.update(asset_detail)
row.cost_as_on_to_date = (
flt(row.cost_as_on_from_date)
+ flt(row.cost_of_new_purchase)
- flt(row.cost_of_sold_asset)
- flt(row.cost_of_scrapped_asset)
- flt(row.cost_of_capitalized_asset)
row.value_as_on_to_date = (
flt(row.value_as_on_from_date)
+ flt(row.value_of_new_purchase)
- flt(row.value_of_sold_asset)
- flt(row.value_of_scrapped_asset)
- flt(row.value_of_capitalized_asset)
)
row.update(next(asset for asset in assets if asset["asset"] == asset_detail.get("name", "")))
@@ -251,11 +249,11 @@ def get_group_by_asset_data(filters):
- flt(row.depreciation_eliminated_during_the_period)
)
row.net_asset_value_as_on_from_date = flt(row.cost_as_on_from_date) - flt(
row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt(
row.accumulated_depreciation_as_on_from_date
)
row.net_asset_value_as_on_to_date = flt(row.cost_as_on_to_date) - flt(
row.net_asset_value_as_on_to_date = flt(row.value_as_on_to_date) - flt(
row.accumulated_depreciation_as_on_to_date
)
@@ -446,38 +444,38 @@ def get_columns(filters):
columns += [
{
"label": _("Cost as on") + " " + formatdate(filters.day_before_from_date),
"fieldname": "cost_as_on_from_date",
"label": _("Value as on") + " " + formatdate(filters.day_before_from_date),
"fieldname": "value_as_on_from_date",
"fieldtype": "Currency",
"width": 140,
},
{
"label": _("Cost of New Purchase"),
"fieldname": "cost_of_new_purchase",
"label": _("Value of New Purchase"),
"fieldname": "value_of_new_purchase",
"fieldtype": "Currency",
"width": 140,
},
{
"label": _("Cost of Sold Asset"),
"fieldname": "cost_of_sold_asset",
"label": _("Value of Sold Asset"),
"fieldname": "value_of_sold_asset",
"fieldtype": "Currency",
"width": 140,
},
{
"label": _("Cost of Scrapped Asset"),
"fieldname": "cost_of_scrapped_asset",
"label": _("Value of Scrapped Asset"),
"fieldname": "value_of_scrapped_asset",
"fieldtype": "Currency",
"width": 140,
},
{
"label": _("Cost of New Capitalized Asset"),
"fieldname": "cost_of_capitalized_asset",
"label": _("Value of New Capitalized Asset"),
"fieldname": "value_of_capitalized_asset",
"fieldtype": "Currency",
"width": 140,
},
{
"label": _("Cost as on") + " " + formatdate(filters.to_date),
"fieldname": "cost_as_on_to_date",
"label": _("Value as on") + " " + formatdate(filters.to_date),
"fieldname": "value_as_on_to_date",
"fieldtype": "Currency",
"width": 140,
},

View File

@@ -142,7 +142,8 @@ def get_journal_entries(filters):
where jvd.parent = jv.name and jv.docstatus=1
and jvd.account = %(account)s and jv.posting_date <= %(report_date)s
and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No'""",
and ifnull(jv.is_opening, 'No') = 'No'
and jv.company = %(company)s """,
filters,
as_dict=1,
)
@@ -163,6 +164,7 @@ def get_payment_entries(filters):
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
and posting_date <= %(report_date)s
and ifnull(clearance_date, '4000-01-01') > %(report_date)s
and company = %(company)s
""",
filters,
as_dict=1,
@@ -181,6 +183,7 @@ def get_pos_entries(filters):
sip.account=%(account)s and si.docstatus=1 and sip.parent = si.name
and account.name = sip.account and si.posting_date <= %(report_date)s and
ifnull(sip.clearance_date, '4000-01-01') > %(report_date)s
and si.company = %(company)s
order by
si.posting_date ASC, si.name DESC
""",

View File

@@ -91,6 +91,7 @@ function get_filters() {
fieldname: "budget_against_filter",
label: __("Dimension Filter"),
fieldtype: "MultiSelectList",
options: "budget_against",
get_data: function (txt) {
if (!frappe.query_report.filters) return;

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