Compare commits

...

1015 Commits

Author SHA1 Message Date
David
a9ecd99049 chore: move older code into v1 gateway file 2024-09-06 00:45:52 +02:00
David
c0323890a8 chore: move older code into v1 gateway file 2024-09-06 00:41:21 +02:00
David
19c6bf2f92 fix: unhide payment url in pr 2024-09-06 00:35:17 +02:00
David Arnold
aa54516444 Merge pull request #41718 from blaggacao/fix/lp-on-si
fix: loyalty points application on si
2024-09-06 00:10:31 +02:00
David
74fb070959 test: loyalty points redemption from shopping cart 2024-09-05 23:53:30 +02:00
David Arnold
7ca9ec14a4 Merge pull request #42071 from blaggacao/fix/coupon-code-limits
fix: coupon code limits and add external plaftorm code
2024-09-05 23:42:30 +02:00
David (aider)
3413bad51d test: add test case for coupon without maximum use 2024-09-05 23:25:08 +02:00
David
70ed75a397 fix: coupon code limits and add external plaftorm code 2024-09-05 22:52:49 +02:00
David Arnold
873571272d Merge pull request #41719 from blaggacao/fix/lp-during-refdoc-save
fix: lp during ref_doc save event
2024-09-05 16:50:45 +02:00
David
48b5567af4 fix: loyalty points application on si 2024-09-05 16:39:52 +02:00
David
340e35f209 fix: lp during ref_doc save event 2024-09-05 16:32:56 +02:00
David Arnold
2ae1704d11 Merge pull request #41871 from blaggacao/perf/reduce-critical-path
perf: hot path in page load
2024-09-05 15:50:23 +02:00
David Arnold
e93ff9b267 Merge pull request #41564 from blaggacao/fix/loyalty
fix: tiered loyalty program
2024-09-05 15:02:04 +02:00
David (aider)
efd8f1e978 feat: Add validation to ensure lowest tier has min_spent of 0 in LoyaltyProgram 2024-09-05 14:30:40 +02:00
David
4bd26b845e fix: test ensures min spent respected 2024-09-05 14:29:10 +02:00
David
ad02e4112f fix: loyalty test case -> validate against actual database state 2024-09-05 14:08:29 +02:00
David
c914ea4adc test: add tests for loyalty tier selection 2024-09-05 14:08:22 +02:00
David
81dc5872c4 fix: tiered loyalty program 2024-09-05 14:08:22 +02:00
David
618e737b0b fix: add lp collection min to list 2024-09-05 14:08:21 +02:00
David Arnold
b38b8ded7b Merge pull request #43017 from blaggacao/fix/status-updater-notifications
fix: updater tigger notifications on status updates & perf
2024-09-05 13:54:35 +02:00
ruthra kumar
613830bfba Merge pull request #43070 from ruthra-kumar/handle_emp_advance_as_separate_unit
fix: AP filter to simulate employee advance as a ledger impacting voucher
2024-09-05 17:12:30 +05:30
David
d72d858efa fix: Update status field in parent transaction 2024-09-05 13:00:18 +02:00
David
00b70d7654 chore: calculate in python code 2024-09-05 13:00:17 +02:00
David
5b3e0c5543 chore: refactor set status into a getter & setter (future perf) 2024-09-05 12:58:51 +02:00
ruthra kumar
257e13c299 refactor: filter to toggle employee advance scenario in AP 2024-09-05 16:12:52 +05:30
ruthra kumar
eedf22b07a refactor: Handle Emp Advance as separate row in AP report 2024-09-05 16:01:26 +05:30
rohitwaghchaure
c13a147df1 fix: disabled batches showing in the list (#43024) 2024-09-05 15:39:15 +05:30
rohitwaghchaure
a8055a6da9 fix: auto reorder material request mail issue (#43066)
fix: auto reorder matreial request mail issue
2024-09-05 15:39:03 +05:30
David Arnold
5f25cde788 Merge pull request #41721 from blaggacao/fix/distributed-discounts
fix: distributed discounts on si
2024-09-05 12:07:18 +02:00
David (aider)
a464bd861b feat: add unit tests for distributed_discount_amount 2024-09-05 11:50:24 +02:00
David
0bab6f34c1 fix: distributed discounts on si 2024-09-05 11:49:24 +02:00
David Arnold
146ce59b87 Merge pull request #43036 from blaggacao/chore/ignore-aider-files
chore: ignore aider files
2024-09-05 11:43:32 +02:00
David
6fdb8659cc chore: ignore aider files 2024-09-05 11:26:26 +02:00
ruthra kumar
ef0682a216 Merge pull request #43065 from Ninad1306/merge_taxes_fix
fix: Reset Value Conditionally Based on Merge Taxes
2024-09-05 14:32:41 +05:30
Ninad1306
9d899f3c4a fix: reset value conditionally based on merge taxes 2024-09-05 13:29:22 +05:30
Smit Vora
5442487b6c Merge pull request #42925 from Ninad1306/mapping_docs_fix
fix: Replace `add_if_empty` with `reset_value` flag
2024-09-04 13:13:57 +05:30
Lakshit Jain
38f925b376 fix: adjust price insertion logic for internal suppliers/customers (#42988)
* fix: adjust price insertion logic for internal suppliers/customers

* refactor: correct indentation, specify conditions within function

* fix: typo

---------

Co-authored-by: Smit Vora <smitvora203@gmail.com>
2024-09-04 12:56:04 +05:30
Khushi Rawat
4da289ec61 Merge pull request #42926 from khushi8112/asset-value-through-landed-cost-voucher
fix: link Purchase Invoice and Receipt Items to Asset
2024-09-04 00:49:46 +05:30
ruthra kumar
b7525ca4e5 Merge pull request #43030 from ruthra-kumar/default_currency_typeerror_on_payment_entry
fix: typerror on default_currency
2024-09-03 16:40:08 +05:30
Nihantra C. Patel
890016695f Merge pull request #43029 from Nihantra-Patel/fix_company_filter
fix: move setup_queries to refresh event for company
2024-09-03 16:05:09 +05:30
Nihantra C. Patel
80ace72541 fix: company accounts setup_queries 2024-09-03 15:54:42 +05:30
ruthra kumar
4a7cc4da87 fix: typerror on default_currency 2024-09-03 15:54:39 +05:30
ruthra kumar
fb6b960806 Merge pull request #42974 from Vishnu7025/report_fix
fix: retain date filter when redirecting in Profit and Loss report
2024-09-03 15:43:01 +05:30
Khushi Rawat
2fdc56cebf Merge branch 'develop' of https://github.com/frappe/erpnext into asset-value-through-landed-cost-voucher 2024-09-03 10:15:29 +05:30
Khushi Rawat
07339e2ddf Merge pull request #43015 from khushi8112/test-case-fix-in-asset-capitalization
chore: test case failing issue
2024-09-03 03:38:29 +05:30
Khushi Rawat
418f7e97b9 chore: patch correction 2024-09-03 03:35:19 +05:30
Raffael Meyer
baff301e8a Merge pull request #43016 from frappe/l10n_develop 2024-09-02 20:09:43 +02:00
Frappe PR Bot
861edd3041 fix: Esperanto translations 2024-09-02 23:00:49 +05:30
Frappe PR Bot
77ac87494a fix: Swedish translations 2024-09-02 23:00:46 +05:30
Frappe PR Bot
0a5b21d002 fix: Spanish translations 2024-09-02 23:00:42 +05:30
Frappe PR Bot
c50aba8333 fix: Arabic translations 2024-09-02 23:00:39 +05:30
Frappe PR Bot
c595bf684c fix: Bosnian translations 2024-09-02 23:00:35 +05:30
Frappe PR Bot
f51e9df921 fix: Turkish translations 2024-09-02 23:00:32 +05:30
Frappe PR Bot
6ebd52bdfe fix: French translations 2024-09-02 23:00:29 +05:30
Frappe PR Bot
aa57a98872 fix: Persian translations 2024-09-02 23:00:25 +05:30
Frappe PR Bot
f9d1bdd9f9 fix: German translations 2024-09-02 23:00:21 +05:30
Khushi Rawat
0bdffdfa98 chore: test case failing issue 2024-09-02 16:50:28 +05:30
Khushi Rawat
f369b583b9 chore: resolved conflicts 2024-09-02 16:09:09 +05:30
rohitwaghchaure
f3b91d4d62 fix: validate component quantity according to BOM (#43011) 2024-09-02 16:05:43 +05:30
Khushi Rawat
a84a5b43e2 refactor: rename to in SLE query functions 2024-09-02 11:48:41 +05:30
Nihantra C. Patel
78be5fc276 Merge pull request #43008 from Nihantra-Patel/upd_develop_version
fix: update develop_version in hooks
2024-09-02 11:42:38 +05:30
Nihantra C. Patel
01b345e046 fix: update develop_version in hooks 2024-09-02 10:40:31 +05:30
Raffael Meyer
e21fcbae6a Merge pull request #42953 from frappe/l10n_develop 2024-09-01 22:48:59 +02:00
Raffael Meyer
a5314165c1 Merge pull request #43005 from frappe/pot_develop_2024-09-01 2024-09-01 22:47:44 +02:00
frappe-pr-bot
d45e6781c1 chore: update POT file 2024-09-01 09:35:05 +00:00
rahulgupta8848
d4fdada83c feat: account heads changed along with journal entry type and descrip… (#42845)
* feat: account heads changed along with journal entry type and description

* feat: added patch for difference_amount for asset value adjustment and refactor

---------

Co-authored-by: “rahulgupta8848” <“rahul.gupta@8848digital.com”>
2024-09-01 10:39:48 +05:30
Raffael Meyer
9b4bb30af2 Merge pull request #43003 from barredterra/toggle_naming 2024-08-31 19:21:16 +02:00
barredterra
ab2d7f7279 fix: show naming series only when needed 2024-08-31 19:14:45 +02:00
Shariq Ansari
9d4ad987e1 Merge pull request #42993 from shariquerik/apps-page-fix
fix: added app permission check for apps page
2024-08-30 17:34:30 +05:30
Shariq Ansari
1d9ed27a89 chore: linter fix 2024-08-30 16:57:17 +05:30
Shariq Ansari
e8f8fb8a8f fix: added app permission check for apps page 2024-08-30 16:51:26 +05:30
David Arnold
b01ac4d6fd Merge pull request #42975 from blaggacao/chore/fix-editorconfig-json
chore: fix editorconfig for json
2024-08-30 08:54:13 +02:00
Khushi Rawat
272f42eaf2 chore: linters/semgrep check 2024-08-30 00:40:01 +05:30
Khushi Rawat
3baffffd1b chore: resolved linter warnings with #nosemgrep 2024-08-30 00:30:47 +05:30
Khushi Rawat
83fe78bcda fix: improve asset item matching logic 2024-08-29 17:10:12 +05:30
ruthra kumar
4500f22671 Merge pull request #42983 from ruthra-kumar/link_utility_rpt_to_bank_reconciliation_statement
refactor: link utility report with bank reconciliation statement
2024-08-29 16:11:09 +05:30
ruthra kumar
00eac65712 refactor: link utility report with bank reconciliation statement 2024-08-29 16:01:54 +05:30
Khushi Rawat
5d99f17583 fix(capitalization): debit cwip account instead of fixed asset account (#42857)
* fix(capitalization): debit cwip account instead of fixed asset account

* fix: post entries for capitalized asset through background jobs

* chore: run pre-commit

* fix: correct GL entries posting for composite assets

* fix(minor): resolve failing check

* chore: update gl entry check logic

* chore: handle none values
2024-08-29 15:50:02 +05:30
ruthra kumar
ac01686ded Merge pull request #42664 from Nihantra-Patel/fix_payment_req_del
fix: add the company in payment request bcz delete company transactions
2024-08-29 15:15:59 +05:30
Nihantra C. Patel
e3008843d1 fix: link company when make payment request 2024-08-29 14:42:45 +05:30
ruthra kumar
735558d073 Merge pull request #42979 from ruthra-kumar/bank_clearance_with_better_transaction_model
refactor: better UX on Bank Clearance tool
2024-08-29 13:53:48 +05:30
ruthra kumar
6a06e26d04 refactor: better UX on Bank Clearance tool 2024-08-29 12:11:48 +05:30
Khushi Rawat
4e29654458 Merge pull request #42976 from khushi8112/capitalization-for-new-composite-asset
fix: don't allow capitalizing only service item for new composite asset
2024-08-29 02:12:13 +05:30
Khushi Rawat
f1d2138258 fix: don't allow capitalizing only service item for new composite asset 2024-08-29 01:51:45 +05:30
David
a07100d5b3 chore: fix editorconfig for json 2024-08-28 21:00:09 +02:00
Frappe PR Bot
d51f9ce815 fix: Swedish translations 2024-08-28 21:10:02 +05:30
Frappe PR Bot
c73ea6bad9 fix: Turkish translations 2024-08-28 21:09:58 +05:30
Frappe PR Bot
7c5b88a4b9 fix: German translations 2024-08-28 21:09:53 +05:30
vishnu
598e9c1390 fix: indentation 2024-08-28 15:12:22 +00:00
vishnu
bb29fc4c3d fix: retain date filter when redirecting in Profit and Loss report 2024-08-28 15:10:08 +00:00
ruthra kumar
df3267ad3c Merge pull request #42966 from ruthra-kumar/typeerror_on_PE
fix: typeerror on Payment Entry
2024-08-28 12:26:25 +05:30
ruthra kumar
e9cf8937cd fix: typeerror on Payment Entry 2024-08-28 12:21:22 +05:30
rohitwaghchaure
663a08e4cd feat: Disassembly Order (#42655) 2024-08-27 22:25:20 +05:30
Raffael Meyer
758d1606a9 Merge pull request #42955 from barredterra/fix-item-error 2024-08-27 17:44:09 +02:00
barredterra
c34737f4c6 fix(Item): error message on tax rate 2024-08-27 17:27:13 +02:00
Frappe PR Bot
193d13be0d fix: Turkish translations 2024-08-27 20:43:48 +05:30
Frappe PR Bot
5d0c25f5b5 fix: German translations 2024-08-27 20:43:44 +05:30
Raffael Meyer
1064d7636d Merge pull request #42681 from barredterra/psa-translatability 2024-08-27 16:55:51 +02:00
ruthra kumar
33e37cfbff Merge pull request #42951 from frappe/mergify/copy/develop/pr-42453
fix: Update get_amount to return currency precision grand total (copy #42453)
2024-08-27 17:38:59 +05:30
David Arnold
d3d0af3815 Merge pull request #41925 from blaggacao/fix/customer-mobile-email
fix: spec mobile and email fields for notifications
2024-08-27 13:42:40 +02:00
ruthra kumar
6310497403 chore: resolve conflict 2024-08-27 17:11:10 +05:30
Syed Mujeer Hashmi
f960aac639 fix: Update get_amount to return currency precision grand total
In case of multi-currency purchase invoice, we are getting the error "Total Payment Request amount cannot be greater than Purchase Invoice amount" because of rounding difference.

(cherry picked from commit 976abf7b3c)

# Conflicts:
#	erpnext/accounts/doctype/payment_request/payment_request.py
2024-08-27 11:39:32 +00:00
ruthra kumar
ab2b2dc5d4 Merge pull request #41949 from Nihantra-Patel/refactor_item_wise_purchase_history_v15
refactor: item-wise purchase history (query to script report)
2024-08-27 16:44:45 +05:30
ruthra kumar
f88d5dcf5c Merge pull request #42936 from ruthra-kumar/fix_incorrect_attribute_on_payment_entry
fix: remove unnecessary condition on 'voucher_no'
2024-08-27 16:35:02 +05:30
ruthra kumar
520db864b5 Merge pull request #42923 from aerele/bank_reconciliation_statement
fix: get amount with taxes and charges from payment entry
2024-08-27 16:30:28 +05:30
Khushi Rawat
62873309e5 Merge pull request #42939 from khushi8112/depreciation-and-balances-report
feat: added finance book filter in depreciation and balances report
2024-08-27 16:22:47 +05:30
rohitwaghchaure
86d3a9ab03 fix: Cannot read properties of null (reading 'doctype') (#42941) 2024-08-27 16:21:36 +05:30
ruthra kumar
d855a8ec1c Merge pull request #42921 from aerele/party_naming_sequance
fix: make party naming sequential when naming_by set as auto name
2024-08-27 15:36:30 +05:30
Khushi Rawat
adf1e487e1 chore: resolved linter warnings with #nosemgrep 2024-08-27 15:27:37 +05:30
Khushi Rawat
45804c68f0 feat: added finance book filter in depreciation and balances report 2024-08-27 15:02:01 +05:30
ruthra kumar
fb32d2cafb fix: use of incorrect attribute 2024-08-27 14:46:10 +05:30
rohitwaghchaure
ca2fde891e fix: timeout while submitting stock entry (#42929) 2024-08-27 10:00:06 +05:30
Raffael Meyer
a132ca1857 Merge pull request #42841 from frappe/l10n_develop 2024-08-26 21:12:25 +02:00
Khushi Rawat
a1aaffbebe fix: link Purchase Invoice and Receipt Items to Asset 2024-08-26 23:33:10 +05:30
Ninad1306
8dcb1ab63b fix: update child table from last source_doc 2024-08-26 22:32:16 +05:30
Frappe PR Bot
6b88777829 fix: Persian translations 2024-08-26 20:30:01 +05:30
venkat102
b3a901b631 fix: get amount with taxes and charges from payment entry 2024-08-26 20:04:51 +05:30
venkat102
c9015f7c04 fix: make party naming sequential when naming_by set as auto name 2024-08-26 19:30:30 +05:30
rohitwaghchaure
27364b7e6b fix: same posting date and time, creation causing incorrect balance qty (#42904)
fix: same posting date and time, creation causing incorrect balance quantity
2024-08-26 18:19:25 +05:30
rohitwaghchaure
10434742e9 fix: unsupported operand type(s) for *: 'float' and 'NoneType' (#42916) 2024-08-26 17:59:14 +05:30
ruthra kumar
c64deac4d3 Merge pull request #42887 from ljain112/fix-dimension
fix: update dimesions in exchange_gain_loss jv based on base document
2024-08-26 17:30:03 +05:30
rohitwaghchaure
92bde71ab1 fix: Column 'valuation_rate' cannot be null (#42909) 2024-08-26 16:48:55 +05:30
Rushabh Mehta
0aae621d0e Merge pull request #42524 from blaggacao/fix/financial-statement-linking
fix: link cash flow rows and fix summary linking
2024-08-26 15:54:32 +05:30
ruthra kumar
94629e0b1b Merge pull request #42910 from ruthra-kumar/tools_for_bank_statement_analysis
feat: utility report to better diagnose incorrectly cleared Cheques and Deposits
2024-08-26 15:40:14 +05:30
ruthra kumar
2144e0337d refactor: build dictionary for Journal
remove redundant filter
2024-08-26 14:57:38 +05:30
ruthra kumar
06e5a3fe23 Merge pull request #42905 from ruthra-kumar/better_err_msg_clearance_tool
refactor: better err msg on clearance tool
2024-08-26 14:23:40 +05:30
ruthra kumar
74b36db24e chore: remove redundant column 2024-08-26 14:16:32 +05:30
ruthra kumar
092411b54f refactor: better err msg on clearance tool 2024-08-26 14:05:19 +05:30
Frappe PR Bot
ef7d9004d5 fix: Swedish translations 2024-08-25 20:33:55 +05:30
Frappe PR Bot
8bdb8e71d4 fix: Spanish translations 2024-08-25 20:33:52 +05:30
Frappe PR Bot
66d7b18204 fix: Persian translations 2024-08-24 20:03:57 +05:30
ruthra kumar
784dec24c8 refactor: build dict for payment entry 2024-08-24 08:16:10 +05:30
ruthra kumar
4cd023444a refactor: working state with minimum functions 2024-08-24 08:16:10 +05:30
ruthra kumar
ceaa1be729 refactor: barebones functions 2024-08-24 08:16:10 +05:30
ruthra kumar
28890fa833 feat: report to identify incorrectly cleared cheques 2024-08-24 08:16:10 +05:30
rohitwaghchaure
6721ae76de fix: LCV based on purchase invoice amount with multi-currency (#42890) 2024-08-23 22:34:38 +05:30
Frappe PR Bot
0d57a7d4a4 fix: Turkish translations 2024-08-23 19:35:37 +05:30
Smit Vora
18bc1df6b7 Merge pull request #42848 from ljain112/fix-oppurtunity
fix: do not copy date fields in opportunity doctype
2024-08-23 14:17:19 +05:30
Raffael Meyer
13eb9ea421 Merge pull request #42877 from barredterra/sb-in-setup-wizard 2024-08-22 17:20:31 +02:00
barredterra
fd51dd8999 fix: remove ugly column break in setup wizard 2024-08-22 17:16:33 +02:00
Raffael Meyer
cc4afc53e3 Merge pull request #42803 from barredterra/pseudo-translate-in-setup-wizard 2024-08-22 17:03:18 +02:00
rohitwaghchaure
ce7f6ee71c fix: incorrect in and out qty in the Batch-Wise Balance History (#42866) 2024-08-22 19:33:30 +05:30
rohitwaghchaure
63ca1025bc fix: not able to make stock entry against MR (#42874) 2024-08-22 19:33:14 +05:30
Raffael Meyer
f6371f4a0d Merge branch 'develop' into pseudo-translate-in-setup-wizard 2024-08-22 16:01:17 +02:00
Frappe PR Bot
b64f70d95a fix: Swedish translations 2024-08-22 18:43:20 +05:30
Frappe PR Bot
e7350f18f6 fix: Turkish translations 2024-08-22 18:43:16 +05:30
ruthra kumar
2ca0f416a9 Merge pull request #42867 from ruthra-kumar/respect_db_transaction_model
fix: call 'process' directly instead of creating 'process_subscription'
2024-08-22 17:22:06 +05:30
ruthra kumar
1efdc04e46 Merge pull request #42851 from ruthra-kumar/allow_equity_type_for_shareholders
refactor: Allow equity type Account in Payment Entry for shareholders
2024-08-22 17:09:45 +05:30
ruthra kumar
b4d22c2936 fix: call 'process' directly instead of creating 'process_subscripti
reason: 'process' follows simple DB transaction model.
2024-08-22 16:58:39 +05:30
ljain112
96df19149d fix: update dimesions in exchange_gain_loss jv based on base document 2024-08-22 11:50:19 +05:30
Khushi Rawat
930286e105 Merge pull request #42861 from khushi8112/slm-depreciation
fix(minor): calculation correction for annual depreciation
2024-08-22 11:17:14 +05:30
Khushi Rawat
f440243b75 fix: calculation correction for annual depreciation 2024-08-22 02:22:51 +05:30
Frappe PR Bot
28df8aa9cf fix: Turkish translations 2024-08-21 18:36:37 +05:30
rohitwaghchaure
fb846ffa12 fix: incorrect Received Qty Amount in Purchase Order Analysis (#42852) 2024-08-21 15:22:19 +05:30
rohitwaghchaure
5b9309cf34 fix: last purchase rate not updated from purchase invoice (#42847) 2024-08-21 14:52:24 +05:30
ruthra kumar
63ad9f4f86 refactor: filter shareholder on company 2024-08-21 14:19:30 +05:30
ruthra kumar
6cbf98294a refactor: allow equity types on Payment Entry 2024-08-21 14:13:04 +05:30
rohitwaghchaure
9c82c2b5d3 fix: custom stock entry type issue (#42835) 2024-08-21 12:11:22 +05:30
Frappe PR Bot
ee9c3e12b4 fix: Turkish translations 2024-08-20 18:33:35 +05:30
Nihantra C. Patel
a1183f0165 refactor: brand js and allow quick entry (#42829)
* refactor: brand js and allow quick entry

* refactor: brand js and allow quick entry --prettier

* refactor: brand js and allow quick entry --prettier
2024-08-20 14:42:32 +05:30
ljain112
74afa57a9f fix: do not copy date fields in opportunity doctype 2024-08-20 13:45:57 +05:30
Khushi Rawat
85641fd21c Merge pull request #42824 from khushi8112/asset-creation-timeout-error
perf: asset creation from purchase receipt
2024-08-20 13:41:46 +05:30
ruthra kumar
c039cfd5c3 Merge pull request #42379 from Nihantra-Patel/fix_so_prospect_dev_v15
fix: Create Sales Order from Quotation for Prospect
2024-08-20 10:40:44 +05:30
Nabin Hait
f48b3c41de chore: Deleted all the form tours (#42773) 2024-08-20 10:37:50 +05:30
Nabin Hait
b7f5012f15 fix: Removed quick entry for Brand (#42822) 2024-08-20 10:37:19 +05:30
Nabin Hait
0b7657ecf1 chore: Remove module onboarding records (#42790) 2024-08-20 10:36:49 +05:30
ruthra kumar
5c5e2c3ac2 Merge pull request #42731 from creative-paramu/bank_reconcilation_filter
fix: bank reconcilation tool cost center company filter adding
2024-08-20 10:13:19 +05:30
Parameshwari Palanisamy
6d19aae423 refactor: update dialog_manager.js 2024-08-20 10:09:25 +05:30
Raffael Meyer
3ddb18de41 Merge pull request #42797 from frappe/l10n_develop 2024-08-19 15:26:43 +02:00
Frappe PR Bot
7ceb294aab fix: Swedish translations 2024-08-19 18:15:49 +05:30
Frappe PR Bot
fbfc5b4b1d fix: Spanish translations 2024-08-19 18:15:45 +05:30
Frappe PR Bot
0448ea3daa fix: Arabic translations 2024-08-19 18:15:40 +05:30
Frappe PR Bot
9cfbd8c8e3 fix: Turkish translations 2024-08-19 18:15:32 +05:30
Frappe PR Bot
2238ca55a5 fix: French translations 2024-08-19 18:15:28 +05:30
Khushi Rawat
6e84fc5143 perf: asset creation from purchase receipt 2024-08-19 17:24:31 +05:30
rohitwaghchaure
5404b21c7d fix: dropping index to improve performance (#42820)
fix: droping index to improve peformance
2024-08-19 16:58:25 +05:30
rohitwaghchaure
1511280464 perf: data import for stock entries (#42711) 2024-08-19 12:04:47 +05:30
Frappe PR Bot
949c0cab72 fix: Swedish translations 2024-08-18 18:07:18 +05:30
Frappe PR Bot
4d41e1538d fix: Esperanto translations 2024-08-18 18:07:15 +05:30
Frappe PR Bot
5e8700f0b4 fix: Spanish translations 2024-08-18 18:07:11 +05:30
Frappe PR Bot
73c4d8a8e6 fix: Arabic translations 2024-08-18 18:07:08 +05:30
Frappe PR Bot
5ae756a93b fix: Bosnian translations 2024-08-18 18:07:05 +05:30
Frappe PR Bot
c9d474bc87 fix: Turkish translations 2024-08-18 18:07:01 +05:30
Frappe PR Bot
226095c6b8 fix: French translations 2024-08-18 18:06:58 +05:30
Frappe PR Bot
200a43e41f fix: Persian translations 2024-08-18 18:06:55 +05:30
Frappe PR Bot
834d8c64c2 fix: German translations 2024-08-18 18:06:51 +05:30
Raffael Meyer
d32fdaaff5 Merge pull request #42808 from frappe/pot_develop_2024-08-18
chore: update POT file
2024-08-18 13:52:29 +02:00
frappe-pr-bot
63b772a7a3 chore: update POT file 2024-08-18 09:36:00 +00:00
Frappe PR Bot
2142f8b4a3 fix: Turkish translations 2024-08-17 17:44:21 +05:30
Frappe PR Bot
fa20320f39 fix: Persian translations 2024-08-17 17:44:18 +05:30
Frappe PR Bot
0e52ef4fd9 fix: German translations 2024-08-17 17:44:14 +05:30
Raffael Meyer
5f3963b3e6 Merge pull request #42800 from barredterra/translatability-fixes 2024-08-17 02:19:43 +02:00
Raffael Meyer
4db7054542 Merge pull request #42802 from barredterra/extract-setup-wizard-data 2024-08-17 02:14:23 +02:00
barredterra
97c2853497 feat: enable "Translate Link Fields" for fixture doctypes 2024-08-17 02:02:20 +02:00
barredterra
48513b1087 refactor: remove useless line 2024-08-17 02:01:35 +02:00
barredterra
505cd95150 fix: remove pseudo-translation for UOM Category variable
Has no effect and even if it had, it's not really needed.
2024-08-17 02:00:34 +02:00
barredterra
c08cd938bc fix: add pseudo-translation for Project Type 2024-08-17 01:58:48 +02:00
barredterra
11f6e570a5 fix: add pseudo-translation for Stock Entry Type 2024-08-17 01:58:27 +02:00
barredterra
77e5787036 fix: use pseudo-translation while creating fixtures 2024-08-17 01:57:44 +02:00
barredterra
60aaeefd70 feat: add extractor for setup wizard txt files 2024-08-17 01:50:55 +02:00
barredterra
af0ae930ca fix: translatability of boldened text 2024-08-16 21:38:56 +02:00
Frappe PR Bot
9d4165b9f9 fix: Turkish translations 2024-08-16 17:35:39 +05:30
ruthra kumar
1bdeddcb04 Merge pull request #42791 from ruthra-kumar/refactor_pos_return_patch
fix(patch): Use sql to update 'against_voucher' rather than reposting
2024-08-16 15:31:22 +05:30
rohitwaghchaure
48c3b0d094 fix: Auto Create Serial and Batch Bundle For Outward (#42778) 2024-08-16 15:10:22 +05:30
ruthra kumar
1721175a20 chore: update patches.txt 2024-08-16 14:32:53 +05:30
ruthra kumar
13bb48434f fix(patch): replace repost with direct sql to update 'against_voucher 2024-08-16 14:31:13 +05:30
rohitwaghchaure
32c4fab14f fix: not able to create the batch (#42784) 2024-08-16 11:27:08 +05:30
ruthra kumar
c1a5a0510e Merge pull request #42774 from ruthra-kumar/loosen_account_currency_validation_on_groups
refactor: Loosen account currency validation on groups
2024-08-16 09:58:52 +05:30
Raffael Meyer
5011b76de9 Merge pull request #42713 from frappe/l10n_develop 2024-08-15 17:00:52 +02:00
Frappe PR Bot
4c0c0d3eb3 fix: Turkish translations 2024-08-15 16:53:43 +05:30
ruthra kumar
164498bafb refactor: allow foreign currency accounts in Supplier Group 2024-08-14 17:31:19 +05:30
ruthra kumar
066e935892 refactor: allow foreign currency accounts in customer group 2024-08-14 17:30:46 +05:30
Nihantra C. Patel
3dfee0ae43 Merge pull request #42769 from Nihantra-Patel/fix_rename_stop_warehouse
fix: disable rename from warehouse
2024-08-14 16:32:50 +05:30
Frappe PR Bot
85c47b9a5a fix: Spanish translations 2024-08-14 16:28:41 +05:30
Frappe PR Bot
6f8eb4d9ed fix: Turkish translations 2024-08-14 16:28:37 +05:30
Frappe PR Bot
3231bedfb3 fix: Persian translations 2024-08-14 16:28:33 +05:30
Frappe PR Bot
e79b57975e fix: German translations 2024-08-14 16:28:29 +05:30
Nihantra C. Patel
c1812f74e8 fix: disable rename from warehouse 2024-08-14 16:11:50 +05:30
rohitwaghchaure
0db82ec93a fix: ignore pricing rule while making DN from Pick List (#42763) 2024-08-14 15:22:19 +05:30
Khushi Rawat
ad4991dc47 Merge pull request #42765 from khushi8112/set-filters-in-asset-capitalization-fields
fix: set up filters for dimensions
2024-08-14 14:35:52 +05:30
Khushi Rawat
0d42793397 chore: linters check 2024-08-14 14:31:56 +05:30
Khushi Rawat
6fa29376a0 fix: removed extra filter condition 2024-08-14 14:26:47 +05:30
Khushi Rawat
2fd8de2f76 fix: set up filters for dimensions 2024-08-14 14:21:48 +05:30
Smit Vora
9e8f25d020 Merge pull request #42458 from Sanket322/currency_format_in_report
fix: use company default currency in report
2024-08-14 13:38:21 +05:30
ruthra kumar
144cad81a4 Merge pull request #42720 from ruthra-kumar/pos_return_with_self_flag
fix: incorrect 'against_voucher' for Pos return with 'Update Outstanding for Self' disabled.
2024-08-14 11:55:22 +05:30
ruthra kumar
da2286802a refactor: move patch to v14 and update patches.txt 2024-08-14 11:35:05 +05:30
ruthra kumar
3fb0858321 test: against_voucher for pos_returns without updating for self 2024-08-14 11:32:26 +05:30
Khushi Rawat
ad5aadde0f Merge pull request #42719 from khushi8112/recalculate-depreciation-correctly-after-asset-repair
fix: linkage between asset repair and asset value adjustment
2024-08-14 00:30:03 +05:30
Khushi Rawat
88a5824e31 test: new depreciation after cancelling asset repair 2024-08-14 00:06:09 +05:30
Khushi Rawat
c085b6159b fix: resolved conflict 2024-08-14 00:03:35 +05:30
rohitwaghchaure
8aadc18ee8 fix: duplicate labels in stock entry (#42756) 2024-08-13 19:32:15 +05:30
ruthra kumar
f6933111ac Merge pull request #40964 from Nihantra-Patel/fix_timesheet_to_invoice_pricelist
fix: price list when invoice created from timesheet
2024-08-13 17:10:49 +05:30
ruthra kumar
7eb811c71a Merge pull request #42221 from ruthra-kumar/fix_subscription_issue
fix: Force Fetching updates on old subscriptions
2024-08-13 16:22:23 +05:30
ruthra kumar
fd680380bb refactor: test for force-fetch on future subscription 2024-08-13 16:05:06 +05:30
Frappe PR Bot
54ed6a9868 fix: Turkish translations 2024-08-13 15:54:38 +05:30
Frappe PR Bot
f65292612b fix: Persian translations 2024-08-13 15:54:34 +05:30
Khushi Rawat
616ce2dbec Merge pull request #42689 from khushi8112/depreciation-amount-correction
fix: fetch month's last date to avoid miscalculation
2024-08-13 14:11:35 +05:30
ruthra kumar
af11480b7f Merge pull request #42726 from ljain112/sales-funnel
fix: text color in sales funnel report based on theme
2024-08-13 14:05:08 +05:30
ruthra kumar
44261223d5 Merge pull request #42590 from ljain112/coa
fix: error message in coa importer
2024-08-13 14:01:49 +05:30
ruthra kumar
d8b6767697 chore: minor naming change 2024-08-13 12:36:42 +05:30
ruthra kumar
3a11577411 refactor: don't process future subscriptions 2024-08-13 12:36:39 +05:30
ruthra kumar
1ef890db73 fix: force fetch updates for subcription 2024-08-13 12:26:59 +05:30
ruthra kumar
4dc0d3a003 refactor: update patches.txt 2024-08-13 11:58:57 +05:30
ruthra kumar
487d0a55f5 fix: patch to fix incorrect against_voucher references in ledger 2024-08-13 11:58:57 +05:30
ruthra kumar
2cd9b28e5b fix: ledger entries for pos return with update outstanding for self 2024-08-13 11:58:57 +05:30
ruthra kumar
6c2700cd8f Merge pull request #42733 from ruthra-kumar/default_ignore_in_soa
refactor: add a new filter flag in Process Statement of Accounts
2024-08-13 11:10:15 +05:30
ruthra kumar
90880c8c01 refactor: pass filter to General Ledger 2024-08-13 10:42:32 +05:30
ruthra kumar
0cf478c4c2 refactor: cr and dr note filter in Statement of Accounts 2024-08-13 10:41:31 +05:30
ruthra kumar
4cc5cd5a71 refactor: combine vouchers from both ignore 2024-08-13 10:37:55 +05:30
Khushi Rawat
245549951d Merge pull request #42729 from khushi8112/cancel-jl-entry-on-doctype-cancellation
fix: cancel Journal Entry on cancellation of asset value adjustment
2024-08-13 02:12:57 +05:30
Khushi Rawat
4b7f1f2d67 fix: cancel Journal Entry on cancellation of asset value adjustment 2024-08-13 01:48:36 +05:30
Shariq Ansari
18b4b09371 Merge pull request #42727 from shariquerik/include-erpnext
fix: include erpnext in apps page
2024-08-12 19:41:55 +05:30
Shariq Ansari
5280132423 chore: renamed include_as_app to include_in_apps_screen 2024-08-12 19:23:43 +05:30
Shariq Ansari
1d52ef7afe fix: include erpnext in apps page 2024-08-12 17:48:54 +05:30
rohitwaghchaure
4abdb28a1a fix: test case for work order (#42723) 2024-08-12 17:45:29 +05:30
ljain112
61bc0925d5 fix: text color in sales funnel report based on theme 2024-08-12 17:09:39 +05:30
ruthra kumar
0a4db47c69 Merge pull request #42672 from ruthra-kumar/correct_paid_and_received_amt_on_payment_request
fix: update 'Paid Amount' on forex payment request
2024-08-12 16:07:21 +05:30
Frappe PR Bot
f194615057 fix: Swedish translations 2024-08-12 15:55:38 +05:30
Frappe PR Bot
5a68e918cd fix: Persian translations 2024-08-12 15:55:33 +05:30
rohitwaghchaure
17ba0cff44 fix: currency changing while making PR from the PO (#42718) 2024-08-12 15:03:53 +05:30
Frappe PR Bot
61a57aaed5 fix: Swedish translations 2024-08-11 15:58:22 +05:30
rohitwaghchaure
deccb007c1 fix: warning message for negative stock (#42683) 2024-08-11 11:35:45 +05:30
Raffael Meyer
2a999e8f58 Merge pull request #42703 from frappe/l10n_develop
fix: sync translations from crowdin
2024-08-10 23:23:00 +02:00
rohitwaghchaure
bf39e3ab32 perf: data import with 99 stock entries (#42685)
perf: data import for stock entries
2024-08-10 22:34:58 +05:30
Frappe PR Bot
534243a4c8 fix: Swedish translations 2024-08-10 15:48:04 +05:30
Frappe PR Bot
d8de6cb708 fix: Spanish translations 2024-08-10 15:48:01 +05:30
Frappe PR Bot
14c40d17d3 fix: Arabic translations 2024-08-10 15:47:58 +05:30
Frappe PR Bot
aa652c8e15 fix: Bosnian translations 2024-08-10 15:47:55 +05:30
Frappe PR Bot
54d6d346c8 fix: Turkish translations 2024-08-10 15:47:52 +05:30
Frappe PR Bot
4070359174 fix: French translations 2024-08-10 15:47:49 +05:30
Frappe PR Bot
908ca511e7 fix: Persian translations 2024-08-10 15:47:46 +05:30
Frappe PR Bot
2ee70c3968 fix: German translations 2024-08-10 15:47:42 +05:30
Raffael Meyer
2c6938120e Merge pull request #42502 from frappe/l10n_develop 2024-08-09 15:12:26 +02:00
ruthra kumar
f913c0fde1 test: currency conversion on foreign currency account 2024-08-09 17:54:45 +05:30
ruthra kumar
d6d0a1b38d test: make use of test fixture 2024-08-09 16:10:05 +05:30
Frappe PR Bot
2028e52c33 fix: Swedish translations 2024-08-09 15:52:25 +05:30
rohitwaghchaure
b65072cd98 fix: delivery note creation issue (#42696) 2024-08-09 12:45:53 +05:30
ruthra kumar
2312757a1d Merge pull request #42428 from cogk/fix-sort-before-groupby
fix: Sort lists before calling itertools.groupby
2024-08-09 11:52:42 +05:30
ruthra kumar
1dcd1b2a23 Merge pull request #42691 from ruthra-kumar/typeerror_on_payment_entry
fix: typeerror on payment entry
2024-08-09 11:39:59 +05:30
ruthra kumar
9cdca0d662 fix: typeerror on payment entry 2024-08-09 11:34:05 +05:30
Khushi Rawat
70ff4e7644 fix: fetch months last date to avoid miscalculation 2024-08-09 03:21:09 +05:30
barredterra
1d6d383ec8 fix(Process Statement Of Accounts): translatable strings in print 2024-08-08 13:07:33 +02:00
barredterra
34089ba230 style(PSA): fix indentation 2024-08-08 12:40:23 +02:00
Raffael Meyer
38568a3e15 Merge pull request #42679 from barredterra/fix-translatable-string-jv 2024-08-08 12:09:02 +02:00
barredterra
8bd84e9d51 refactor(Exchange Rate Revaluation): remove unused variables 2024-08-08 12:05:25 +02:00
barredterra
dc29fb8759 fix(Exchange Rate Revaluation): translatable strings 2024-08-08 12:05:08 +02:00
Frappe PR Bot
29fe8377a1 fix: Swedish translations 2024-08-08 15:27:45 +05:30
ruthra kumar
657acab32f Merge pull request #42673 from ruthra-kumar/maintain_rate_on_quotation_to_sales_order
fix: Maintain same rate on qty change on Quotation to Sales Order
2024-08-08 13:32:52 +05:30
ruthra kumar
91ce9fce9b fix: Maintain same rate on qty change on Quotation to Sales Order 2024-08-08 11:58:58 +05:30
ruthra kumar
7b0dfb2a05 fix: update 'Paid Amount' on forex payment request 2024-08-08 10:37:57 +05:30
Raffael Meyer
755c162093 Merge pull request #42670 from barredterra/extract-incoterms 2024-08-07 20:45:57 +02:00
barredterra
e177ece008 fix: extract incoterm titles as translatable strings 2024-08-07 20:28:39 +02:00
Shariq Ansari
47c2127a31 Merge pull request #42596 from Didiman1998/bugfix/fix-opportunity-contact-address-bug
fix: changes in opportunity.py to show contacts and addresses created from opportunity
2024-08-07 19:58:36 +05:30
Nihantra Patel
12834ccf9a fix: add the company in payment request bcz delete company transactions 2024-08-07 16:48:29 +05:30
ruthra kumar
efadf94cf3 Merge pull request #42578 from ljain112/fix-dimensions
fix: dimensions in common party journal entry
2024-08-07 16:02:46 +05:30
Khushi Rawat
b1c23ba85c Merge pull request #42593 from khushi8112/disable-submit-button-for-composite-asset
fix: disable primary action button only when there are no active capitalization
2024-08-06 19:11:58 +05:30
Raffael Meyer
82b02d6c9b Merge pull request #42400 from barredterra/root-supplier-group 2024-08-06 14:46:02 +02:00
ruthra kumar
8040544216 test: dimension inheritance on Exc Gain/Loss JV on Common party 2024-08-06 17:46:19 +05:30
ruthra kumar
34ad9d33ff Merge pull request #41708 from Mutantpenguin/patch-1
refactor: use doctype File directly instead of save_file from file_manager.py
2024-08-06 14:34:07 +05:30
ruthra kumar
113362e2d9 Merge pull request #42592 from ljain112/tds-filters
fix: company filter for filtring tax withheld vouchers
2024-08-06 13:16:13 +05:30
ruthra kumar
165ec2ed53 Merge pull request #42545 from ljain112/fix-sales-funnel
fix: min height for rows in sales funnel
2024-08-06 13:01:41 +05:30
rohitwaghchaure
faff84c6e5 feat: expiry date column in Available Batch Report (#42628) 2024-08-06 12:20:41 +05:30
ruthra kumar
4a4e1d36f2 Merge pull request #42636 from ruthra-kumar/ignore_on_gl_should_pull_all_records
refactor: posting date should not be considered for ignore filters in GL
2024-08-06 10:54:54 +05:30
ruthra kumar
c930f8ba9d refactor: posting date is not considered for ignore filters in GL 2024-08-06 10:36:26 +05:30
Frappe PR Bot
42885a81f0 fix: Swedish translations 2024-08-06 03:08:20 +05:30
rohitwaghchaure
c8af544ef3 fix: do not update item price and last purchase rate for inter transf… (#42616)
fix: do not update item price and last purchase rate for inter transfer transaction
2024-08-05 20:20:36 +05:30
ruthra kumar
0f0b19688a Merge pull request #42555 from ruthra-kumar/sales_pipeline_analytics_filters
refactor: date filters should be mandatory in Sales Pipeline Analytics report
2024-08-05 15:07:59 +05:30
ruthra kumar
4253caf910 refactor(test): use test fixture and supply from and to dates 2024-08-05 14:47:09 +05:30
ruthra kumar
213b2ba942 refactor: consider empty-string as Not Assigned 2024-08-05 14:08:08 +05:30
ruthra kumar
e78e948b7c Merge pull request #42621 from ruthra-kumar/clear_data_on_gl_tests
refactor(test): clear data before GL report tests
2024-08-05 13:43:59 +05:30
ruthra kumar
56620785a0 refactor(test): clear old records on GL report tests 2024-08-05 13:26:03 +05:30
ruthra kumar
751a25c4b7 refactor: report columns should be based on from and to dates 2024-08-05 11:31:13 +05:30
ruthra kumar
05b92c5321 Merge pull request #42597 from ruthra-kumar/ignore_reconciliation_jv_on_general_ledger
refactor: filter to ignore system generated cr / dr reconciliation journals on general ledger
2024-08-05 11:12:56 +05:30
ruthra kumar
9ade269b7a refactor(test): filter and reconcile concerned vouchers 2024-08-05 10:46:35 +05:30
ruthra kumar
991069bfbc test: clear old data 2024-08-05 10:23:52 +05:30
ruthra kumar
3617b41b95 refactor: make 'from_date' and 'to_date' mandatory 2024-08-05 10:18:42 +05:30
ruthra kumar
03f3ab522f refactor: make use of date filters on ignore filterss 2024-08-05 10:01:09 +05:30
ruthra kumar
3ffac73598 test: ignore filter for system generated cr / dr note journals 2024-08-05 10:01:07 +05:30
Frappe PR Bot
f7c0ccce0a fix: Swedish translations 2024-08-05 03:03:25 +05:30
Frappe PR Bot
a1bcc6b418 fix: Esperanto translations 2024-08-05 03:03:22 +05:30
Raffael Meyer
6d2a36c4f9 Merge pull request #42612 from frappe/pot_develop_2024-08-04 2024-08-04 13:48:21 +02:00
frappe-pr-bot
5040e3ca7d chore: update POT file 2024-08-04 09:34:51 +00:00
rohitwaghchaure
da22a8df42 Merge pull request #42584 from rohitwaghchaure/fixed-support-19715
fix: all warehouse filter for the stock report
2024-08-02 18:55:42 +05:30
Dietmar Fischer
511a0b9f37 fix: pre-commit for better code formatting 2024-08-02 12:51:48 +02:00
Khushi Rawat
5d58eb67a6 fix: use get_last_day to get the correct date (#42564) 2024-08-02 16:21:21 +05:30
ruthra kumar
bb8c9b5a58 refactor: ignore system generated cr / dr notes on general ledger 2024-08-02 15:47:47 +05:30
ruthra kumar
59d5beee20 refactor: ignore filter in general ledger for cr / dr notes 2024-08-02 15:43:04 +05:30
Khushi Rawat
bb877f4a6b fix: disable primary action button only when there are no active capitalization 2024-08-02 13:37:59 +05:30
ljain112
cfe2ae604b fix: company filter for filtring tax withheld vouchers 2024-08-02 13:12:04 +05:30
ljain112
5d0a38dfc7 fix: error message in coa importer 2024-08-02 11:50:57 +05:30
David
41e395a7e3 fix: hot path in page load 2024-08-01 23:23:48 +02:00
Rohit Waghchaure
a4311e345d fix: all warehouse filter for the stock report 2024-08-01 23:10:46 +05:30
Dietmar Fischer
61576ca030 feat: changes in opportunity.py to show contacts and addresses from referenced and opportunities 2024-08-01 17:01:43 +02:00
Nabin Hait
281198456d fix: Discount and taxes in return document should follow the reference document (#41911)
* fix: Discount and taxes in return document should follow the reference document

* fix: Ignore Pricing rule on debit/credit note if created against PI/SI with test cases

* fix: linter issue
2024-08-01 14:51:01 +05:30
ljain112
ac629ede79 fix: dimensions in common party journal entry 2024-07-31 18:49:19 +05:30
ruthra kumar
fb2aa7d205 Merge pull request #42563 from ruthra-kumar/set_query_filter_on_pe_tax_templates
fix: set query filters for sales / purchase tax template on PE
2024-07-31 17:08:11 +05:30
ruthra kumar
9fe47ac101 fix: set query filters for sales / purchase tax template on PE 2024-07-31 16:42:33 +05:30
ruthra kumar
d811fdf675 Merge pull request #42558 from ruthra-kumar/fix_undefined_in_consolidate_report
fix: 'undefined' in PL and BS report summary on Consolidated report
2024-07-31 15:32:36 +05:30
ruthra kumar
dd5a5e4919 fix: 'undefined' in PL and BS report summary on Consolidated report 2024-07-31 14:40:55 +05:30
rohitwaghchaure
f620ef20ae fix: inter transfer delivery note issue with batch (#42552) 2024-07-31 14:17:22 +05:30
ruthra kumar
40c166a0a0 refactor: date filters should be explicit 2024-07-31 14:01:27 +05:30
Smit Vora
33a0a529a5 Merge pull request #42392 from ljain112/fix-asset
fix: allow sale of asset for internal transfer
2024-07-31 13:22:20 +05:30
Lakshit Jain
8624aeca54 fix: promotional scheme doctype fields in consitency with pricing rule (#42432)
* fix: add "round_free_qty" check box in promotional scheme

* fix: add `add_for_price_list` field

* fix: set_query in setup for promotional scheme

---------
2024-07-31 13:19:54 +05:30
Lakshit Jain
a694390a12 fix: reverse debit credit for party gl entry in payment entry based on negative amount (#42367)
* fix: do not absolute the amount for party gl entries

* fix: reverse debit credit for party gl entry based on negative amount

* refactor: reduce nesting of if condition

---------
2024-07-31 12:46:10 +05:30
Nabin Hait
4986f28a89 fix: set currency on change of company considering customer default currency (#42405) 2024-07-31 11:44:05 +05:30
Khushi Rawat
0e5e503b42 Merge pull request #42525 from khushi8112/depreciation-adjustment-for-existing-asset
fix: Adjust initial month's depreciation to end of depreciation period
2024-07-30 19:04:26 +05:30
ljain112
fd71d8af52 fix: min height for rows in sales funnel 2024-07-30 17:49:56 +05:30
rohitwaghchaure
1c7f7c8d1a perf: huge number of serial no creation (#42522) 2024-07-30 16:33:53 +05:30
ruthra kumar
93ee922c5f Merge pull request #42393 from blaggacao/payments/pr-5
refactor: explicate intent on make_payment_request interface
2024-07-30 16:31:53 +05:30
rohitwaghchaure
23fed831a0 fix: price_list_currency not found error (#42534) 2024-07-30 14:26:29 +05:30
rohitwaghchaure
0ecfa709d8 fix: warehouse filter in Product Bundle Balance (#42532) 2024-07-30 14:26:06 +05:30
rohitwaghchaure
c5d68333c9 fix: purchase return from rejected warehouse (#42531) 2024-07-30 14:24:35 +05:30
ruthra kumar
ff3a5058c1 Merge pull request #42476 from ruthra-kumar/configuration_to_control_payment_request_creation
refactor: checkbox to control Payment Request creation
2024-07-30 13:35:59 +05:30
ruthra kumar
5ec9df8d1c Merge pull request #42528 from ruthra-kumar/rename_button_on_payment_order
chore: button name should reflect what it creates
2024-07-30 11:59:46 +05:30
ruthra kumar
0b6e7f83cd chore: button name should reflect what it creates 2024-07-30 11:54:41 +05:30
Khushi Rawat
f0768010d9 fix(tests): added tests for usecase 2024-07-30 01:28:52 +05:30
Khushi Rawat
cbb749a3a5 fix: Adjust initial month's depreciation to end of depreciation period 2024-07-29 23:50:57 +05:30
David
b94af28587 fix: link cash flow rows and fix summary linking 2024-07-29 20:02:52 +02:00
rohitwaghchaure
8eff168d76 fix: Warranty Expiry Date not set in the serial number (#42513)
* fix: Warranty Expiry Date not set in the serial number

* chore: fix linters issue
2024-07-29 14:47:42 +05:30
rohitwaghchaure
25dac1f18e fix: builtins.KeyError: ('ABC', 'Store - CP') (#42505) 2024-07-29 09:49:53 +05:30
rohitwaghchaure
cb522f8f22 fix: performance issue for the report Purchase Order Analysis report (#42503) 2024-07-28 23:41:00 +05:30
Frappe PR Bot
0b27b19c35 fix: Swedish translations 2024-07-28 23:06:42 +05:30
Raffael Meyer
21d8b09f47 Merge pull request #42499 from frappe/l10n_develop
fix: sync translations from crowdin
2024-07-28 14:49:19 +02:00
Frappe PR Bot
e9c1a7e3e3 fix: Esperanto translations 2024-07-27 22:53:17 +05:30
Raffael Meyer
24b26627e7 Merge pull request #42498 from frappe/pot_develop_2024-07-27 2024-07-27 19:18:38 +02:00
frappe-pr-bot
9aaf6e47d5 chore: update POT file 2024-07-27 17:02:08 +00:00
Raffael Meyer
4931b74b3f Merge pull request #42466 from frappe/l10n_develop 2024-07-27 19:00:36 +02:00
Raffael Meyer
532bc163f6 Merge pull request #42457 from barredterra/review-translations 2024-07-27 18:59:26 +02:00
Raffael Meyer
4c3ec767ce Merge pull request #42418 from barredterra/si-queries 2024-07-27 18:58:27 +02:00
ruthra kumar
0d77e0b0cd Merge pull request #42477 from ruthra-kumar/incorrect_cost_center_on_AR_AP_report
fix: incorrect cost_center on AR/AP report
2024-07-26 19:42:56 +05:30
Ninad Parikh
723ac0ffc4 fix: Update Rate as per Valuation Rate for Internal Transfers only if Setting is Enabled (#42050)
* fix: update rate for internal transfers only if settings enabled

* fix: better naming

* fix: create field for storing incoming rate in purchase doctypes

* fix: use qty instead of qty_in_stock_uom

* fix: add description, refactor for readablility

* test: test case to validate internal transfers at arm's length price

* fix: minor fix

* fix: deletion of code not required

---------

Co-authored-by: Smit Vora <smitvora203@gmail.com>
2024-07-26 18:22:40 +05:30
ruthra kumar
9a0894fd65 test: invoice cost center reported in AR/AP report 2024-07-26 18:16:40 +05:30
Smit Vora
096ec2db6a Merge pull request #42470 from Ninad1306/field_changes_for_subcontracting
fix: Fields Alteration Related to Subcontracting
2024-07-26 16:24:47 +05:30
Smit Vora
3b481ae656 Merge pull request #42305 from ljain112/fix-tds-adv
fix: consider payment entries for checking if tds is deducted
2024-07-26 14:40:15 +05:30
Smit Vora
ad31b63537 Merge pull request #42444 from ljain112/parenttype
fix: parenttype in purchase and sales item query
2024-07-26 14:23:21 +05:30
ruthra kumar
3e19041fa3 fix: incorrect cost_center on AR/AP report 2024-07-26 08:00:13 +05:30
ruthra kumar
ce81fd9ba6 refactor: checkbox to control Payment Request creation 2024-07-26 06:52:55 +05:30
ruthra kumar
07281d30bb Merge pull request #42472 from ruthra-kumar/index_on_release_date
refactor: index on Purchase Invoice 'release_date'
2024-07-25 21:26:22 +05:30
ruthra kumar
764dd12b10 refactor: index on Purchase Invoice 'release_date' 2024-07-25 19:51:54 +05:30
Ninad1306
77590e6077 fix: fields alteration related to subcontracting 2024-07-25 18:05:31 +05:30
ljain112
40b59de4cd fix: consider payment entries for checking if tds is deducted 2024-07-25 17:26:52 +05:30
Ninad Parikh
302339998f fix: Fields Modification for Subcontracting DocTypes (#42383)
* fix: fields renaming and reordering for enhanced user experience

* fix: dashboard data for stock entry
2024-07-25 10:18:21 +05:30
rohitwaghchaure
0e817f42ef fix: dynamic condition in the pricing rule not working (#42467) 2024-07-25 10:15:05 +05:30
Frappe PR Bot
8c6d666163 fix: Swedish translations 2024-07-24 20:18:54 +05:30
Frappe PR Bot
4ab6134306 fix: Esperanto translations 2024-07-24 20:18:50 +05:30
ruthra kumar
e062ec38b0 Merge pull request #42462 from ruthra-kumar/monthly_err_revaluation
refactor: provision for re-evaluating Exchange Rates in monthly frequency
2024-07-24 18:44:04 +05:30
ruthra kumar
fc4e5f165c refactor: hooks for monthly re-evaluation jobs 2024-07-24 18:18:21 +05:30
ruthra kumar
ce2b9e0f1a refactor: provision for monthly re-evaluation 2024-07-24 18:18:13 +05:30
rohitwaghchaure
06e2d7265c fix: keyerror posting_time (#42452)
fix: keyerror: posting_time
2024-07-24 16:39:11 +05:30
rohitwaghchaure
9cd3374101 fix: incorrect current qty for the batch in stock reco (#42434) 2024-07-24 16:38:20 +05:30
Sanket322
2533808f1e fix: set proper currency format 2024-07-24 13:42:04 +05:30
barredterra
89c458e229 chore: set PR reviewer for translations 2024-07-24 09:59:46 +02:00
Raffael Meyer
ffc5bbfa4c Merge pull request #42319 from frappe/pot_develop_2024-07-14 2024-07-24 09:51:13 +02:00
Raffael Meyer
92a6fc8c2e Merge pull request #42206 from frappe/l10n_develop 2024-07-24 09:50:43 +02:00
ruthra kumar
8ccf8c0ea2 Merge pull request #42390 from ruthra-kumar/remove_stale_code_from_reposting
refactor: cleaning up stale code related to reposting
2024-07-24 12:57:51 +05:30
ljain112
972329cc16 fix: allow sale of asset for internal transfer 2024-07-23 17:44:37 +05:30
ljain112
35981b8730 fix: parenttype in item wise purchase and sales register 2024-07-23 17:36:33 +05:30
Khushi Rawat
6e1fc33d01 Merge pull request #42372 from khushi8112/correct-validation-for-depreciation-posting-date
fix: correct validation for depreciation posting date
2024-07-23 15:23:41 +05:30
Smit Vora
c8e85f4bb7 Merge pull request #42377 from vorasmit/ignore-duplicates
fix: ignore duplicates while creating default templates
2024-07-23 10:25:29 +05:30
Raffael Meyer
bf2c9a7f41 Merge pull request #42419 from barredterra/si-initial-value 2024-07-22 20:40:49 +02:00
rohitwaghchaure
be2648245b fix: qty in the 'Serial No Ledger' report (#42429) 2024-07-22 17:45:48 +05:30
Corentin Forler
45a6ecbd38 fix: Sort lists before calling itertools.groupby 2024-07-22 10:13:10 +02:00
HarryPaulo
669cf6094e fix: process on background based on number of invoices on POS Closing Entry (#42417)
* fix: process on background based on number of invoices on POS Closing Entry

* fix: process on background based on number of invoices on POS Closing Entry
2024-07-20 10:17:34 +05:30
barredterra
65f80abf2f fix: provide initial value for .reduce() call
Fixes the error "TypeError: Reduce of empty array with no initial value" (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Reduce_of_empty_array_with_no_initial_value#invalid_cases)
2024-07-20 00:44:31 +02:00
barredterra
9b463753b7 refactor(Sales Invoice): queries 2024-07-20 00:27:16 +02:00
Khushi Rawat
f4d4658cbb Merge pull request #42412 from khushi8112/set-filter-on-asset-name-field
fix: set filter to show only submitted asset
2024-07-19 19:16:38 +05:30
Khushi Rawat
69b8e10e20 fix: set filter to show only submitted asset 2024-07-19 19:10:33 +05:30
Frappe PR Bot
9e93bc5819 fix: Swedish translations 2024-07-19 17:47:54 +05:30
ruthra kumar
ebb95b7d9a Merge pull request #42407 from ruthra-kumar/test_for_item_wise_purchase_register
test: basic test case for item-wise purchase register
2024-07-19 16:50:06 +05:30
ruthra kumar
c3c5d3f615 test: basic test case for item-wise purchase register 2024-07-19 16:31:58 +05:30
HENRY Florian
1bbe020cfd feat: add make_regional_gl_entries override for Sales Invoice (#42399)
* feat: add make_regional_gl_entries override for Sales Invoice and Stock Controler

* chore: remove regionnal override for stock management
2024-07-19 16:22:11 +05:30
Poorvi-R-Bhat
d62eb0f5c1 fix: Billing hours is not updated in Time sheet#19026 (#42404) 2024-07-19 14:46:24 +05:30
ruthra kumar
930ecb3170 Merge pull request #41959 from hiteshprajapati/bug-Don't_allow_negative_amount_on_Payment_Request
fix: Don't allow negative amount on Payment Request #41905
2024-07-19 10:33:49 +05:30
ruthra kumar
f44de670ca Merge pull request #42386 from ljain112/fix-pos
fix: set pos data if not return doc
2024-07-19 10:23:55 +05:30
barredterra
5d4578a172 refactor(Supplier Group): use frm.is_new() instead of frm.doc.__islocal 2024-07-18 21:00:42 +02:00
barredterra
45391c951b fix(Supplier Group): remove useless headline
Not sure what it was supposed to mean. It was only visible on root group, along with the other message.
2024-07-18 20:59:26 +02:00
barredterra
741fc54eca fix(Supplier Group): properly call frm.set_read_only() 2024-07-18 20:56:56 +02:00
rohitwaghchaure
e5dfc5e545 fix: serial and batch bundle for POS Invoice (#41491) 2024-07-18 19:54:00 +05:30
rohitwaghchaure
e1b9b432c3 fix: rounding issue causing incorrect quantity in SE (#42380) 2024-07-18 19:53:45 +05:30
rohitwaghchaure
67bf9bec47 fix: Purchase Order Analysis Report Data (#42387) 2024-07-18 19:52:30 +05:30
David
6d83c11d8e refactor: explicate intent on make_payment_request interface 2024-07-18 15:18:27 +02:00
ljain112
65d672da65 fix: set pos data if not return doc 2024-07-18 17:40:19 +05:30
ruthra kumar
79a46ad6f8 Merge pull request #42148 from blaggacao/payments/pr-4
feat(payment): add more payment channels than just email and phone (think: chat)
2024-07-18 17:20:33 +05:30
ruthra kumar
a912e07b74 Merge pull request #39638 from blaggacao/feat/add-login-user-to-driver
feat: add login user to driver if available for notifications
2024-07-18 17:18:10 +05:30
ruthra kumar
e71cb4eab7 refactor(test): remove assert on 'repost_required' 2024-07-18 15:39:30 +05:30
ruthra kumar
07fc952a43 refactor: remove attribute check on 'repost_required' 2024-07-18 15:38:15 +05:30
ruthra kumar
09f429ffba refactor: repost without checking on flag 2024-07-18 15:34:59 +05:30
ruthra kumar
fe46e1d089 chore: remove stale UI code related to repost 2024-07-18 15:34:02 +05:30
ruthra kumar
e81373bb6a chore: remove 'repost_required' from Journal Entry 2024-07-18 15:32:51 +05:30
ruthra kumar
a467888a67 chore: remove 'repost_required' from purchase invoice 2024-07-18 15:31:59 +05:30
ruthra kumar
06c5334f2a chore: remove stale 'repost_required' flag from sales invoice 2024-07-18 15:31:01 +05:30
ruthra kumar
f3fda9ce98 chore: remove stale code from sales invoice 2024-07-18 15:29:30 +05:30
ruthra kumar
57f928da55 Merge pull request #42374 from nabinhait/ar_ap_fix
fix: Show the rows in AR/AP report where outstanding equals to 0.01
2024-07-18 13:43:56 +05:30
ruthra kumar
bb9e42cce2 test: AR/AP report on miniscule outstanding 2024-07-18 12:58:09 +05:30
ruthra kumar
c587ede548 Merge pull request #42369 from ruthra-kumar/fix_missing_cr_note_on_payment_reconciliation
fix: missing cr/dr notes on payment reconciliation
2024-07-18 12:37:49 +05:30
Nihantra Patel
ee44022249 fix: update the testcase format 2024-07-18 12:26:23 +05:30
Nihantra Patel
29d50b770e fix: update the testcase format 2024-07-18 12:24:52 +05:30
Nihantra Patel
2f63fae31d fix: Create Sales Order from Quotation for Prospect 2024-07-18 12:14:53 +05:30
Smit Vora
cf55c2ab3d fix: ignore duplicates while creating default templates 2024-07-18 10:07:02 +05:30
Nabin Hait
e1dedc5402 fix: Show the rows in AR/AP report where outstanding equals to 0.01 2024-07-17 21:23:56 +05:30
rohitwaghchaure
62fb495a65 fix: not able to save QC (#42371) 2024-07-17 19:49:53 +05:30
Khushi Rawat
da4ed90a3e fix: correct validation for depreciation posting date 2024-07-17 19:19:31 +05:30
ruthra kumar
2d686c06ea test: payment filter should not affect dr/cr notes 2024-07-17 17:52:55 +05:30
ruthra kumar
a30af68e9e fix: missing cr/dr notes on payment reconciliation 2024-07-17 15:27:58 +05:30
Smit Vora
c8dad976e2 Merge pull request #42307 from Sanket322/update_proprietorship_to_individual
fix: remove redundant proprietorship field from customer type and supplier type
2024-07-17 14:01:18 +05:30
Smit Vora
ea03ce3662 Merge pull request #42352 from ljain112/balance-sheet
fix: show total rows credit row in balance sheet
2024-07-16 19:27:29 +05:30
rohitwaghchaure
001e5b612b fix: items not fetching in End Transit entry (#42358) 2024-07-16 17:49:24 +05:30
Khushi Rawat
81e0b96c30 fix: service item capitalization (#42188)
* feat: capitalize with service expenses only

* chore: added test

* refactor: removed Capitalized In field from asset doc
2024-07-16 17:45:29 +05:30
rohitwaghchaure
85d2d34116 fix: same posting date and time causing incorrect valuation rate (#42351) 2024-07-16 16:08:39 +05:30
rohitwaghchaure
21df38bf18 fix: bin deadlock issue (#42342) 2024-07-16 16:08:03 +05:30
ljain112
327b19cba6 fix: show total rows credit row in balance sheet 2024-07-16 14:33:52 +05:30
Frappe PR Bot
656e363aef fix: Swedish translations 2024-07-16 02:32:01 +05:30
rohitwaghchaure
6a50b40976 fix: extra qty pick in pick list (#42345) 2024-07-15 23:00:12 +05:30
Nihantra C. Patel
17b437709c fix: remove doctype link from serial no ledger report (#42327)
* fix: remove doctype link from serial no ledger report

* fix: remove doctype link from serial no ledger report

* fix: remove doctype link from serial no ledger report --update
2024-07-15 22:59:43 +05:30
Nihantra C. Patel
66b35ec9fb feat: create variant with/without image (#41317)
* feat: create variant with/without image

* feat: create variant with/without image

* feat: create variant with/without image

* feat: create variant with/without image

* feat: create variant with/without image

* feat: create variant with/without image

* fix: change the variable name use_same_image to use_template_image
2024-07-15 16:59:41 +05:30
rohitwaghchaure
6d42cd0f4c fix: not able to cancel the inter transfer DN (#42333) 2024-07-15 16:21:07 +05:30
ruthra kumar
58bfd3b973 Merge pull request #42339 from ruthra-kumar/refactor_gp_test_for_dict_assert
fix(test): incorrect linter changes on test_gross_profit.py by ruff
2024-07-15 16:13:56 +05:30
ruthra kumar
fde348c8a0 fix(test): incorrect ruff changes 2024-07-15 15:52:59 +05:30
ruthra kumar
40cebf257b fix(test): incorrect linter fix from ruff 2024-07-15 15:49:37 +05:30
ruthra kumar
8784966138 Merge pull request #42294 from ruthra-kumar/implicit_repost_on_invoice_update
refactor: make reposting implicit
2024-07-15 15:10:33 +05:30
ruthra kumar
794a62aecb chore: contextual comments 2024-07-15 14:29:07 +05:30
ruthra kumar
c283cda169 refactor(test): reposting happens implicitly 2024-07-15 14:28:15 +05:30
ruthra kumar
8f135e9859 refactor(test): no need to assert repost_required flag
Reposting happens implicitly upon 'Update After Submit'
2024-07-15 14:24:25 +05:30
ruthra kumar
05fedf046c Merge pull request #42330 from ruthra-kumar/fix_gross_profit_valuation_rate_for_diff_warehouse
fix: incorrect valuation rate for items from different warehouses in Gross Profit
2024-07-15 14:19:10 +05:30
ruthra kumar
577ce5ccd4 test(gross profit): valuation rate from different warehouse 2024-07-15 13:05:09 +05:30
ruthra kumar
f9d2dd0a62 fix(gross profit): incorrect valuation rate on different warehouses 2024-07-15 11:44:35 +05:30
frappe-pr-bot
372b5a4ca7 chore: update POT file 2024-07-14 09:35:44 +00:00
Frappe PR Bot
5e3359c5c5 fix: Swedish translations 2024-07-14 02:09:38 +05:30
rohitwaghchaure
61daa318fe fix: incoming rate zero for supplied items in returned SCR (#42314) 2024-07-13 16:06:24 +05:30
rohitwaghchaure
7656220075 fix: address and contact filters for SCO and SCR (#42310) 2024-07-13 15:29:37 +05:30
Sanket322
c8ad6d1b2c fix: remove proprietorship and update it with individual 2024-07-12 18:58:14 +05:30
rohitwaghchaure
9cf92eaeab fix: not able to submit LCV entry (#42303) 2024-07-12 16:57:50 +05:30
Khushi Rawat
b04da63aad feat: configurable depreciation calculation via accounts settings (#42276)
* feat: configurable depreciation calculation via accounts settings

* refactor: code optimization

* style: changes in description and label
2024-07-12 14:25:57 +05:30
Nabin Hait
d0bbc8ca70 fix: While submitting PCV ensure previous FY is closed (#42284) 2024-07-12 14:24:42 +05:30
rohitwaghchaure
9838f7e6ba fix: cost center filter by company (#42297) 2024-07-12 12:36:39 +05:30
rohitwaghchaure
10280d6140 fix: keep status as In Progress for RIV for Timeout Error (#42274) 2024-07-12 11:54:35 +05:30
ruthra kumar
722ef92324 refactor: make reposting implicit 2024-07-12 10:30:19 +05:30
rohitwaghchaure
b17696a8ae fix: slowness in reposting dependent vouchers. (#42282) 2024-07-11 19:05:46 +05:30
ruthra kumar
3bde29c98b Merge pull request #42192 from ruthra-kumar/tests_for_item_wise_sales_and_purchase_reports
refactor: tests for item wise sales register report
2024-07-11 18:02:52 +05:30
ruthra kumar
cf4fbfb601 refactor(test): use each instance UOM for assertion 2024-07-11 17:40:34 +05:30
ruthra kumar
a4a6d90857 Merge pull request #42287 from ruthra-kumar/fix_missing_discount_on_pos_credit_note
fix: missing discount on POS Credit Notes
2024-07-11 17:28:07 +05:30
ruthra kumar
1049550951 fix: missing discount on POS Credit Notes 2024-07-11 17:21:41 +05:30
Frappe PR Bot
62fc3bd586 fix: Swedish translations 2024-07-11 01:37:52 +05:30
Raffael Meyer
22549186ab Merge pull request #42232 from barredterra/warehouse-buttons 2024-07-10 13:14:44 +02:00
ruthra kumar
d4c16c1740 Merge pull request #42247 from ruthra-kumar/fix_purchase_receipt_tax_on_stock_rbnb
fix: don't merge tax into stock account on purchase receipt repost
2024-07-10 15:27:19 +05:30
ruthra kumar
9562628ed6 test: tax account heads on PR report without LCV 2024-07-10 15:05:31 +05:30
ruthra kumar
8633080dff fix: tax on stock_rbnb on repost of Purchase Receipt 2024-07-10 15:05:28 +05:30
Smit Vora
3ef7e6ce5c Merge pull request #42204 from DaizyModi/fix-project-status
fix: Reopen Project if Completion Percentage is Below 100%
2024-07-10 12:38:57 +05:30
Smit Vora
d3520a62cc Merge pull request #42127 from ljain112/fix-disc-validation
fix: removed max discount validation for sales return
2024-07-10 12:30:04 +05:30
Smit Vora
5c0d52f783 fix(tds): use doctype reference when mapping keys across multiple doctypes (#42258)
* fix(tds): use doctype reference when mapping keys across multiple doctypes

* fix: changes as per review

---------

Co-authored-by: ljain112 <ljain112@gmail.com>
2024-07-10 06:26:38 +00:00
Smit Vora
d86e0ad694 Merge pull request #42060 from ljain112/fix-tds
fix: updated logic for calculating tax_withholding_net_total in payment entry
2024-07-10 10:40:14 +05:30
Khushi Rawat
0893a06b42 Merge pull request #42233 from khushi8112/show-only-submitted-assets
fix: added filter to show only submitted assets
2024-07-09 16:40:13 +05:30
rohitwaghchaure
1186ee128c fix: actual qty in sales order (#42248) 2024-07-09 15:09:17 +05:30
Poorvi-R-Bhat
623b4c21cd fix: corrected mismatch in the Purchase Receipt Status #15620 (#42138) 2024-07-09 14:59:31 +05:30
Rucha Mahabal
ad137250fc fix(Holiday List): sort holidays on save to avoid disorienting the user (#42236)
fix: sort holidays on save to avoid disorienting the user
2024-07-09 14:56:25 +05:30
Nihantra C. Patel
0c76a8cc9e fix: Billed Qty and Qty to Bill Calculation in Purchase Order Analysis (#42100) 2024-07-09 14:53:04 +05:30
Raffael Meyer
4936514c8d fix(Stock Entry Type): reduce perms for Stock User (#42225) 2024-07-09 12:15:52 +05:30
Raffael Meyer
96b275c61e fix(Putaway Rule): reduce perms for Stock User (#42227) 2024-07-09 12:13:59 +05:30
Raffael Meyer
edc1f84250 fix(Inventory Dimension): reduce perms for Stock User (#42226) 2024-07-09 12:13:42 +05:30
rohitwaghchaure
5f53ad3117 fix: auto serial and batch bundle not creating for Asset Capitalization (#42231) 2024-07-09 11:11:44 +05:30
ruthra kumar
2383a1a18e Merge pull request #42026 from ljain112/fix-bank-import
fix:  Multiple fixes in Bank Statement Import
2024-07-09 10:09:32 +05:30
Frappe PR Bot
e7ee508de4 fix: Esperanto translations 2024-07-09 00:53:26 +05:30
Khushi Rawat
cd3a900495 fix: added filter to show only submitted assets 2024-07-08 20:48:53 +05:30
barredterra
10ae5aaf52 fix(Warehouse): add buttons only if the user can use them 2024-07-08 17:08:38 +02:00
Raffael Meyer
fa614dd8d3 Merge pull request #42211 from frappe/pot_develop_2024-07-07 2024-07-08 15:04:43 +02:00
Frappe PR Bot
4b415987f9 fix: Swedish translations 2024-07-08 00:51:51 +05:30
frappe-pr-bot
b4d3dfc234 chore: update POT file 2024-07-07 09:35:29 +00:00
Frappe PR Bot
cfda332faf fix: Swedish translations 2024-07-07 00:29:52 +05:30
DaizyModi
c52fdffdaf fix: Project Status should be Open again if percent_complete is not 100 2024-07-06 19:05:36 +05:30
ruthra kumar
4cea34c1c6 Merge pull request #42146 from ljain112/fix-general-ledger
fix: Multiple fixes for General Ledger Report
2024-07-06 17:14:36 +05:30
rohitwaghchaure
f06ba0cc36 fix: provision to enable do not use batch-wise valuation (#42186)
fix: provision to enable do not use batchwise valuation
2024-07-05 20:14:32 +05:30
ruthra kumar
3aaa22e672 refactor: test suite for item-wise sales register 2024-07-05 10:04:58 +05:30
ruthra kumar
9474f72776 chore: rename test suite for payable report 2024-07-05 09:40:33 +05:30
ruthra kumar
36403cde98 Merge pull request #42183 from ruthra-kumar/empty_item_on_select
fix: empty item-wise sales/purchase register reports on initial load
2024-07-04 15:06:17 +05:30
ruthra kumar
ee862126e4 fix: empty item-wise sales/purchase register reports on initial load 2024-07-04 15:01:35 +05:30
Syed Mujeer Hashmi
55e2b876a2 fix: Consider adding warranty period to serial nos (#42051) 2024-07-04 14:38:06 +05:30
ruthra kumar
ddaf81fc33 Merge pull request #41975 from Nihantra-Patel/fix_iwpr_v15
fix: group by in item-wise purchase register
2024-07-04 14:37:35 +05:30
Richard Case
9cfe09bdf6 fix: BOM Creator Recursion Error on duplicate save (#41622) 2024-07-04 14:35:56 +05:30
ruthra kumar
1594e7bc25 Merge pull request #42143 from ruthra-kumar/validation_to_prevent_recurse_with_mixed
refactor: validation to prevent recursion with mixed conditions
2024-07-03 20:56:31 +05:30
ruthra kumar
6a2a6667d2 Merge pull request #42165 from ruthra-kumar/fix_recursize_free_items_on_item_group
fix: multiple free items on same Item Group
2024-07-03 17:57:28 +05:30
ruthra kumar
eb4af58bf0 test: validation on mixed condition and recursion on pricing rule 2024-07-03 17:54:41 +05:30
ruthra kumar
9bd4e7b709 test: validation on mixed condition with recursion 2024-07-03 17:11:32 +05:30
ruthra kumar
9d7be293ae fix: use standard method to get _doc_before_save 2024-07-03 17:05:13 +05:30
Raffael Meyer
e923e539d8 Merge pull request #42157 from Nihantra-Patel/fix_asset_log_path 2024-07-03 12:54:48 +02:00
ruthra kumar
c4ae0d283f fix: multiple free items on same Item Group 2024-07-03 15:58:19 +05:30
Markus Lobedann
4512432816 refactor: remove obsolete function call (#42162) 2024-07-03 12:21:12 +02:00
rohitwaghchaure
938dd4b2aa fix: manual pick allow to pick more than available stock (#42155) 2024-07-03 13:33:17 +05:30
Nihantra C. Patel
909aa8f359 fix: path of automatically updates the status of asset maintenance log 2024-07-03 13:12:00 +05:30
rohitwaghchaure
1dae2156e3 fix: show zero stock items filter in the stock balance report (#42147) 2024-07-03 07:39:47 +05:30
ruthra kumar
dc5d3b69be Merge pull request #42073 from ruthra-kumar/fix_lcv_repost_on_item_revaluation
fix: always post to tax account heads if LCV is booked
2024-07-03 07:03:48 +05:30
Frappe PR Bot
9eb0521e95 fix: sync translations from crowdin (#41635) 2024-07-03 00:00:10 +02:00
David Arnold
c39a44c016 perf: flush db at once 2024-07-02 19:48:23 +02:00
ljain112
c8a34cde7f fix: updated logic for calculating tax_withholding_net_total in payment entry 2024-07-02 19:07:31 +05:30
Sagar Vora
97f02015c2 fix: Multiple fixes for General Ledger Report 2024-07-02 17:38:40 +05:30
ruthra kumar
0e256b8b29 refactor(test): fix flaky test 2024-07-02 17:00:16 +05:30
Khushi Rawat
bd98f2f685 Merge pull request #42144 from khushi8112/site-migration-issue
fix: handle none type object error
2024-07-02 16:36:50 +05:30
Khushi Rawat
6760c9c4e2 fix: handle none type object error 2024-07-02 16:10:47 +05:30
ruthra kumar
6ba6b5aa33 refactor(test): cleanup test data 2024-07-02 15:50:01 +05:30
ruthra kumar
406dfd528f refactor: validation to prevent recursion with mixed conditions 2024-07-02 15:44:54 +05:30
ruthra kumar
fa56555150 test: Repost should not merge expense accounts from LCV 2024-07-02 12:45:01 +05:30
ruthra kumar
0fcd5d5130 fix: always post to tax account heads if LCV is booked 2024-07-02 12:10:22 +05:30
rohitwaghchaure
99f2735ad3 fix: stock qty validation in SCR (#42124) 2024-07-01 18:19:20 +05:30
ruthra kumar
cbd25aeaa4 Merge pull request #42126 from ruthra-kumar/sales_order_credit_limit_check_on_reopen
fix: Re-open allows SO's to be over credit limit
2024-07-01 17:02:31 +05:30
Khushi Rawat
c5e474f4f5 fix: add auto-update for overdue status (#42105)
* fix: auto-update for overdue status

* chore: use qb.update
2024-07-01 16:55:49 +05:30
ruthra kumar
60694e09c4 test: credit check on Sales Order re-open 2024-07-01 16:43:33 +05:30
ljain112
db807d433b fix: removed max discount validation for sales return 2024-07-01 16:07:38 +05:30
ruthra kumar
5eed781263 fix: Re-open allows SO's to be over credit limit 2024-07-01 15:49:48 +05:30
rohitwaghchaure
8f424528dd fix: batch reset while making SABB (#42076) 2024-07-01 14:14:19 +05:30
ruthra kumar
7c9129d0be Merge pull request #42119 from ruthra-kumar/ui_typerror_on_lead
fix: broken button under `Actions` in Lead doctype
2024-07-01 13:20:07 +05:30
ruthra kumar
f440e7cd94 fix: broken UI buttons under Actions in Lead 2024-07-01 13:15:36 +05:30
Khushi Rawat
55a4bd469b fix: resolve gl entries duplication in asset purchase workflow (#41845)
* fix: resolve gl entries duplication in asset purchase workflow

* fix: prevent duplicate entry when creating purchase receipt from purchase invoice

* chore: test case added

* fix: fixed missing asset category issue
2024-07-01 13:08:51 +05:30
ruthra kumar
9d8794f3ca Merge pull request #42014 from Nihantra-Patel/fix_lead_issue_dev
fix: creation of contact, customer, opportunity, quotation and prospect from lead
2024-07-01 13:05:41 +05:30
ruthra kumar
ec9ab6d762 Merge pull request #42000 from blaggacao/payments/pr-3
perf: flush db at once
2024-07-01 09:58:08 +05:30
Smit Vora
188f0e0f32 Merge pull request #41896 from cogk/fix-so-supplier-change-detection
fix(SO): Fix logic to check if supplier has changed
2024-07-01 08:09:51 +05:30
creative-paramu
6e2ac09821 fix: bank reconcilation tool cost center company filter adding 2024-06-30 20:37:09 +05:30
ruthra kumar
8b0de4aaf7 Merge pull request #42029 from ruthra-kumar/bug_in_advance_against_journal
fix: incorrect ledger entries on Advance payment against Journals for customer
2024-06-30 05:37:51 +05:30
rohitwaghchaure
32bdcdb08f fix: timeout error while submitting JV (#42040) 2024-06-29 07:35:13 +05:30
rohitwaghchaure
03e674e21d fix: reposting file attachment permission issue (#42068) 2024-06-28 23:25:17 +05:30
ruthra kumar
9ec6aef95d refactor: handle purchase invoice as reference 2024-06-28 20:48:22 +05:30
ruthra kumar
ad7efd5939 chore: better test name 2024-06-28 20:40:35 +05:30
ruthra kumar
1b384b9942 test: advance payment entry against journal - supplier type 2024-06-28 20:40:35 +05:30
ruthra kumar
5e84272cf9 test: advance payment against journal entry - customer type 2024-06-28 20:40:35 +05:30
ruthra kumar
f6c1dffb35 fix: incorrect dr/cr on Adv Payment against Journals 2024-06-28 20:40:35 +05:30
tonspar
affaaee1f4 fix: Correct dunnings resolving after PE submit (#41792)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2024-06-28 13:47:51 +02:00
Raffael Meyer
0c5cda1380 Merge pull request #42063 from barredterra/stage-only-pot-file 2024-06-28 13:24:17 +02:00
Smit Vora
252d052f86 Merge pull request #41979 from ljain112/fix-dashboard
fix: dynamic_link for party in customer and supplier dashboard
2024-06-28 12:04:23 +05:30
barredterra
1f74439b16 ci: explicitly stage pot file
Avoid accidentally adding any other changed files, like yarn.lock, to the commit.
2024-06-27 19:43:46 +02:00
Khushi Rawat
ba79e68190 fix: refactor Asset Repair and Stock Entry linkage to resolve amendme… (#41919)
* fix: refactor Asset Repair and Stock Entry linkage to resolve amendment issues

* chore: added missing patch to patches.txt

* chore: fixing previous changes

* chore: fixing minor issues

* fix: code changes to enhance efficiency

* chore: replaced frappe.qb with db.sql because of conflict

* fix: minor changes
2024-06-27 17:34:25 +05:30
rohitwaghchaure
9738c04ef0 fix: not able to make purchase return (#42053) 2024-06-27 16:01:51 +05:30
Raffael Meyer
f850ccc4d8 Merge pull request #42054 from frappe/pot_develop_2024-06-27 2024-06-27 12:31:43 +02:00
frappe-pr-bot
7b5e041928 chore: update POT file 2024-06-27 10:15:22 +00:00
Raffael Meyer
42d401a1dd Merge pull request #42048 from barredterra/ci-typo 2024-06-26 18:58:26 +02:00
barredterra
26aa1a128f ci: fix typo in pot file regeneration 2024-06-26 17:54:51 +02:00
Khushi Rawat
80c6981cfa fix: unhide serial no field (#42045) 2024-06-26 12:22:52 +00:00
Nihantra C. Patel
8ae2b8ff8c fix: lead status filter (#41816) 2024-06-26 17:45:57 +05:30
Khushi Rawat
625f16dee0 fix: incorrect time period in asset depreciation schedule (#41805)
* fix(wip): depreciation calculation for existing asset

* fix(wip): added validation for incorrect depreciation period

* fix: depreciation schedule time period issue for existing asset

* chore: run pre-commit checks and apply fixes

* style: apply formatting changes

* style: made some necessary changes

* chore: modified test
2024-06-26 16:33:53 +05:30
Khushi Rawat
5fdd1d3278 chore: patch to enable total number of booked depreciations field (#41940)
* chore: patch to enable total number of booked depreciations field

* fix: conflict resolved

* refactor: replaced fb_row.db_set with set_value
2024-06-26 16:28:27 +05:30
rohitwaghchaure
eca3e02f8d fix: manufacturing date issue in the batch (#42034) 2024-06-26 09:11:20 +05:30
Poorvi-R-Bhat
1a9899b32b fix: Stock Reservation Entry was not getting created (#42033) 2024-06-25 18:42:07 +05:30
mergify[bot]
2e76b9f9db fix: timeout while cancelling LCV (backport #42030) (#42031)
fix: timeout while cancelling LCV (#42030)

fix: timeout while canelling LCV
(cherry picked from commit 21bf7fd1f8)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-06-25 18:11:41 +05:30
ljain112
ba08b2e8e8 fix: changes as per review 2024-06-25 17:48:10 +05:30
Raffael Meyer
61fe95a0bd Merge pull request #41756 from fzozyurt/tr_account_plan-#41536 2024-06-25 12:56:09 +02:00
Khushi Rawat
1c643a0ead fix: fixed asset value in Fixed Asset Register (#41930) 2024-06-25 16:05:04 +05:30
Khushi Rawat
5738d93f95 perf: code optimization to handle large asset creation (#42018) 2024-06-25 15:30:17 +05:30
ljain112
98ad01c736 fix: field position 2024-06-25 15:04:21 +05:30
ljain112
2112d8f772 fix: download_import_log if rows are greater than 5000 2024-06-25 14:55:51 +05:30
ljain112
1ad264de48 fix: import log preview 2024-06-25 14:47:23 +05:30
rohitwaghchaure
97c9941143 fix: batch picking in pick list based on Stock Settings (#42021) 2024-06-25 14:28:31 +05:30
ljain112
07f68884e0 fix: import status 2024-06-25 14:27:28 +05:30
ljain112
b202409428 fix: remove deprecated field "statement_import_log" 2024-06-25 14:27:04 +05:30
ljain112
13fb560401 fix: custom delimiters 2024-06-25 13:05:30 +05:30
rohitwaghchaure
9ab333d105 fix: valuation rate for the legacy batches (#42011) 2024-06-25 12:32:27 +05:30
Nihantra Patel
5844897c34 fix: creation of contact, customer, opportunity, quotation and prospect from lead --prettier 2024-06-24 16:03:39 +05:30
Nihantra Patel
8304d19e8b fix: creation of contact, customer, opportunity, quotation and prospect from lead 2024-06-24 15:54:01 +05:30
rohitwaghchaure
d50487ce53 fix: Wrong Delete Batch on Purchase Receipt (#42007) 2024-06-24 14:56:08 +05:30
rohitwaghchaure
7d91c6cbd5 fix: incorrect Difference Amount (#42008) 2024-06-24 14:55:57 +05:30
Deepesh Garg
379a290625 Merge pull request #41751 from rtdany10/gp-dimension
feat: accounting dimension filters in gp report
2024-06-24 10:51:55 +05:30
David
cf6c13ecae perf: flush db at once 2024-06-23 16:47:41 +02:00
ruthra kumar
73d56c4b33 Merge pull request #41704 from blaggacao/payments/pr-2
chore: clarify codepath around mute email and make invoice
2024-06-23 05:39:00 +05:30
ruthra kumar
5ec62756fb Merge pull request #41976 from ruthra-kumar/pricing_rule_priority_and_apply_multiple
fix: pricing rule with and without 'apply multiple' and priority
2024-06-23 05:31:20 +05:30
ruthra kumar
a4c0115b5e Merge pull request #41844 from ruthra-kumar/forex_accounts_support_for_advance_accounts
refactor: allow foreign currency advance accounts
2024-06-23 05:26:52 +05:30
Sagar Vora
ac6d85aed6 perf: dont run queries unnecessarily, improved filters (#41993)
* perf: dont run queries unnecessarily, improved filters

* perf: dont run query if `in` filter is empty
2024-06-22 21:27:00 +05:30
ruthra kumar
efebc3662e test: priority takes effect on with and without apply multiple 2024-06-22 20:30:55 +05:30
ruthra kumar
3fabf4aaa4 refactor(test): make and use a different party for subscription 2024-06-22 19:32:07 +05:30
rohitwaghchaure
fd7666a029 feat: default account head for operating cost (#41985) 2024-06-21 18:56:48 +05:30
ruthra kumar
4f92ab0ac7 Merge pull request #41981 from ruthra-kumar/repost_should_update_against_account
fix: incorrect against_account upon reposting
2024-06-21 17:58:14 +05:30
rohitwaghchaure
21adc7b63e fix: decimal issue in pick list (#41972) 2024-06-21 17:41:48 +05:30
ruthra kumar
20c4098399 fix: incorrect against_account upon reposting 2024-06-21 17:21:32 +05:30
ljain112
c0a8800832 fix: dynamic_link for party in customer and supplier dashboard 2024-06-21 16:08:04 +05:30
ruthra kumar
5f8f81c0ba Merge pull request #41956 from ruthra-kumar/discount_on_other_item
fix: incorrect discount on other item
2024-06-21 15:51:17 +05:30
Nihantra C. Patel
3fab00135b fix: group by in item-wise purchase register 2024-06-21 15:49:40 +05:30
ruthra kumar
5e875b238c fix: pricing rule with and without 'apply multiple' and priority
Either all of the pricing rules identified for an item should have
'apply multiple' enabled. If not, Priority is applied and only the
highest priority is applied
2024-06-21 15:46:16 +05:30
Raffael Meyer
86869ac8b8 Merge pull request #41966 from barredterra/per-for-shipment 2024-06-20 14:34:39 +02:00
barredterra
100d8e2007 fix: move condition for shipment 2024-06-20 14:33:03 +02:00
rohitwaghchaure
d5ed4582c3 fix: this.frm.events.update_cost is not a function (#41960) 2024-06-20 17:05:19 +05:30
mahsem
f28c692dca fix: add string for translation (#41903)
fix: add string for translation
2024-06-20 14:23:57 +05:30
rohitwaghchaure
306ab454d5 Merge pull request #41957 from rohitwaghchaure/fixed-17237
fix: expense account from item group not fetched
2024-06-20 14:22:22 +05:30
rohitwaghchaure
ef744c1f2c Merge pull request #41958 from rohitwaghchaure/fixed-17439
fix: do not show zero balance stock items in stock balance report
2024-06-20 14:19:13 +05:30
hiteshprajapati
b823aa66bf fix: Don't allow negative amount on Payment Request #41905 2024-06-20 14:11:18 +05:30
Rohit Waghchaure
7f7b363d48 fix: do not show zero balance stock in stock balance 2024-06-20 13:59:02 +05:30
Rohit Waghchaure
86ebe58231 fix: expense account from item group not fetched 2024-06-20 13:42:45 +05:30
ruthra kumar
654764e398 fix: incorrect discount on other item
When discount is applied on other item, don't update `discount_amount`
as the amount is calculated for current item
2024-06-20 12:04:00 +05:30
Nihantra Patel
2851764ed6 refactor: item-wise purchase history (query to script report) --upd 2024-06-19 16:09:44 +05:30
Nihantra Patel
7bae18aba8 refactor: item-wise purchase history (query to script report) --prettier 2024-06-19 15:06:09 +05:30
Nihantra Patel
f740c94363 refactor: item-wise purchase history (query to script report) --prettier 2024-06-19 14:59:24 +05:30
Nihantra Patel
003a9608dc refactor: item-wise purchase history (query to script report) -- formatter 2024-06-19 14:57:02 +05:30
Nihantra Patel
49331e6109 refactor: item-wise purchase history (query to script report) 2024-06-19 14:37:29 +05:30
Nihantra Patel
5de91cf55e refactor: item-wise purchase history (query to script report) 2024-06-19 14:31:52 +05:30
Raffael Meyer
a9910817f5 Merge pull request #41421 from frappe/migrate_lead_notes 2024-06-19 00:56:04 +02:00
ruthra kumar
64e63887be refactor(test): enfore use of customer/supplier master
While using advance accounts in foreign currency, always use
Customer/Supplier master to maintain them
2024-06-18 15:10:25 +05:30
ruthra kumar
c696d13a5e fix(test): incorrect field for customer default billing currency 2024-06-18 14:35:35 +05:30
ruthra kumar
8a397a4506 Merge pull request #41900 from ljain112/unreco
refactor: ignore unreconcile doc for PO and SO on cancel/delete
2024-06-18 10:26:58 +05:30
rohitwaghchaure
1cce7064e0 Merge pull request #41936 from casesolved-co-uk/prodplan_bomqty_test
feat: add production plan test for complex bom qtys
2024-06-18 09:42:35 +05:30
Richard Case
3025501500 chore: linting 2024-06-17 17:55:23 +01:00
Richard Case
a2ba0f51a0 feat: add production plan test for complex bom qtys 2024-06-17 17:49:31 +01:00
rohitwaghchaure
46d33d27cf Merge pull request #41931 from rohitwaghchaure/fixed-validation-for-reposting
fix: reposting validation related PCV
2024-06-17 17:49:35 +05:30
rohitwaghchaure
8141eacb02 Merge pull request #41907 from mahsem/fix-add-strings-for-translation-in-pos_item_cart.js
fix: add strings for translation in pos_item_cart.js
2024-06-17 17:09:42 +05:30
Rohit Waghchaure
194f1dc674 fix: reposting validation related PCV 2024-06-17 16:54:02 +05:30
rohitwaghchaure
28f195023e Merge pull request #41920 from ljain112/fix-sales-register
fix: handle NoneType error where customer details are not available in sales register
2024-06-17 14:58:07 +05:30
rohitwaghchaure
2e5b85c329 Merge pull request #41927 from ljain112/fix-item-pur-report
fix: consistent query field name in item wise purchase register with item wise sales register
2024-06-17 14:57:08 +05:30
ljain112
6d539e0fc0 fix: consistent query field name in item wise purchase register with item wise sales register 2024-06-17 14:30:31 +05:30
rohitwaghchaure
1b072228d3 Merge pull request #41921 from Nihantra-Patel/item-wise-sales_purchase_report_v15
fix: item_code filter in item-wise sales-purchase register
2024-06-17 14:01:06 +05:30
David
18993a97ce fix: spec mobile and email fields for notifications 2024-06-17 10:28:38 +02:00
rohitwaghchaure
2c0f03d43a Merge pull request #41922 from rohitwaghchaure/fixed-17235
fix: duplicate rows fetching in RFQ
2024-06-17 13:05:18 +05:30
Rohit Waghchaure
555510c128 fix: duplicate rows fetching in RFQ 2024-06-17 12:48:44 +05:30
Nihantra Patel
757aef3972 fix: item_code filter in item-wise sales-purchase register 2024-06-17 12:33:14 +05:30
ljain112
f876fec6f5 fix: handle NoneType error where customer details are not available in sales register 2024-06-17 12:32:17 +05:30
rohitwaghchaure
3f13554bfb Merge pull request #41898 from Nihantra-Patel/upd_mr_received_qty_v15
fix: update received qty in MR on purchase invoice submit with update stock
2024-06-17 11:35:36 +05:30
rohitwaghchaure
4fc43b9009 Merge pull request #41916 from rohitwaghchaure/fixed-incorrect-batch-returned
fix: incorrect batch return from sales return
2024-06-17 11:16:31 +05:30
Rohit Waghchaure
317047c808 fix: incorrect batch return from sales return 2024-06-17 10:22:06 +05:30
ruthra kumar
7e318c0132 chore: remove dead code 2024-06-17 08:45:54 +05:30
ruthra kumar
07d59443b7 chore: fix test data 2024-06-17 07:39:52 +05:30
ruthra kumar
83ff94b9b8 refactor: better error messages 2024-06-17 07:29:24 +05:30
fzozyurt
b401ba2c26 feat: Create Turkish Chart Of Accounts 2024-06-15 20:58:24 +03:00
ruthra kumar
7479459cb6 Merge pull request #40187 from GursheenK/valuation-tax-gle-via-lcv
fix: valuation tax entries on LCV after billing PR
2024-06-15 20:41:22 +05:30
barredterra
895aede590 fix: only show user and date if available 2024-06-14 17:47:02 +02:00
mahsem
2fb3e5da4a fix: add strings for translation in pos_item_cart.js
fix: add strings for translation in pos_item_cart.js
2024-06-14 15:40:08 +02:00
Nihantra Patel
77959596db fix: add test case for update received qty in MR - import sorter 2024-06-14 16:50:49 +05:30
Nihantra Patel
73f22ba9a0 fix: add test case for update received qty in MR - import sorter 2024-06-14 16:50:04 +05:30
Nihantra Patel
62e4e88f1d fix: add test case for update received qty in MR 2024-06-14 16:47:30 +05:30
Nihantra Patel
cff1050159 fix: add test case for update received qty in MR 2024-06-14 16:46:23 +05:30
Nihantra Patel
ebb0cef601 fix: add test case for update received qty in MR 2024-06-14 16:44:26 +05:30
ljain112
b618d685c6 refactor: ignore unreconcile doc for PO and SO on cancel/delete 2024-06-14 13:13:11 +05:30
Nihantra Patel
13cb53fa89 fix: update received qty in MR on purchase invoice submit with update stock 2024-06-14 12:39:45 +05:30
Corentin Flr
339b6692fe fix(SO): Fix logic to check if supplier has changed 2024-06-13 18:11:42 +02:00
Smit Vora
99695df7bc Merge pull request #41842 from ljain112/fix-item-valuation
fix: regional overide for updating item valution
2024-06-13 13:38:24 +05:30
rohitwaghchaure
7996723e07 Merge pull request #41886 from Kishan0330/bugfix/download-materials-required-v15
fix: download materials request plan in production plan
2024-06-13 11:14:02 +05:30
Deepesh Garg
8b3c0f6d69 Merge pull request #41112 from barredterra/print-language
fix: language in sales transactions
2024-06-13 00:09:49 +05:30
Kishan0330
f4e369977a refactor: change warehousesData variable name 2024-06-12 22:08:29 +05:30
Kishan0330
6e55651795 fix: download materials request plan in production plan 2024-06-12 21:46:30 +05:30
mergify[bot]
b44630a28c Merge branch 'develop' into print-language 2024-06-12 15:40:34 +00:00
Bernhard Sirlinger
d85f316995 fix: correct creation of opportunity with lead dashboard plus button (#40987) 2024-06-12 16:52:25 +05:30
Rucha Mahabal
56082f5a29 fix: allow Employee role to select Department (#41877) 2024-06-12 11:19:39 +00:00
rohitwaghchaure
75983ead33 Merge pull request #41872 from rohitwaghchaure/fixed-purchase-receipt-return-issue-16966
fix: return from accepted and rejected warehouse at a same time not working
2024-06-12 15:45:35 +05:30
Rohit Waghchaure
17731f09ef fix: return from accepted and rejected warehouse at a same time not working 2024-06-12 15:13:59 +05:30
rohitwaghchaure
9f3b1ce5d5 Merge pull request #41867 from Nihantra-Patel/download_materials_required_v15
fix: download materials request plan in PP
2024-06-12 13:02:06 +05:30
Himanshu Shivhare
7ee2a19f53 chore: typo in bom_operation.json (#41650)
chore: typo in bom_operation.json
2024-06-12 13:01:28 +05:30
rohitwaghchaure
53d99b7c8c Merge pull request #41865 from rohitwaghchaure/fixed-batch-qty-16601
fix: batch qty in the dropdown field
2024-06-12 13:00:30 +05:30
Nihantra C. Patel
a1c4e0e93c fix: download materials request plan in PP -prettier 2024-06-12 12:36:53 +05:30
Nihantra C. Patel
cb52b76342 fix: download materials request plan in PP 2024-06-12 12:34:46 +05:30
Nihantra C. Patel
f4acdd9636 fix: download materials request plan in PP 2024-06-12 12:26:40 +05:30
Rohit Waghchaure
eb426c69fe fix: batch qty in the dropdown field 2024-06-12 12:12:58 +05:30
rohitwaghchaure
7249a691b3 fix: valuation rate for serial and batch bundle for current bundle (#41850) 2024-06-11 18:10:02 +05:30
Deepesh Garg
db313706a7 Merge pull request #41852 from deepeshgarg007/ledger_views
fix: Add timestamp to key for immutable views
2024-06-11 15:04:55 +05:30
Deepesh Garg
6bded59f1c fix: Add timestamp to key for immutable views 2024-06-11 14:47:08 +05:30
Khushi Rawat
857c689405 fix: asset depreciations and balances report correction (#41824)
* fix: asset depreciations and balances report correction

* chore: suppress linter warnings with # nosemgrep
2024-06-11 14:27:28 +05:30
ruthra kumar
8d7e68d355 Merge pull request #41707 from ruthra-kumar/is_opening_for_payment_entry
refactor: add `Is opening` flag for payment entry
2024-06-11 10:26:01 +05:30
ruthra kumar
4c03dcb4ba Merge pull request #41685 from ruthra-kumar/allow_partial_tds_on_purchase_invoice
refactor: enabling partial TDS application on partial invoice
2024-06-11 10:10:43 +05:30
ruthra kumar
17f968e1e1 test: is_opening flag for advance in separate party account 2024-06-11 10:08:49 +05:30
ruthra kumar
107b614518 refactor: validation in Supplier Group 2024-06-10 20:16:23 +05:30
ruthra kumar
4f9a228175 refactor: validation in customer group 2024-06-10 20:16:23 +05:30
ruthra kumar
0f0b4d88bc refactor: validation to force accounts to be on same currency 2024-06-10 20:16:23 +05:30
ruthra kumar
90c84822d0 test: advance against purchase invoice 2024-06-10 20:16:23 +05:30
ruthra kumar
827d67d02f test: exc gain/loss booking on advances under asset/liability 2024-06-10 20:16:23 +05:30
ruthra kumar
475e0ddeee refactor(test): simpler create_account helper method 2024-06-10 20:16:23 +05:30
ruthra kumar
7dce6e03c7 refactor: for advances uses the party account in references table 2024-06-10 20:16:23 +05:30
ruthra kumar
c9ede1ffbe refactor: convert amount to base currency for advances 2024-06-10 20:16:23 +05:30
ruthra kumar
e7740033ca chore: remove validation on payment entry 2024-06-10 20:16:14 +05:30
ljain112
1a10f0bcbd fix: regional overide for updating item valution 2024-06-10 20:06:05 +05:30
rohitwaghchaure
7ce9f7bc12 chore: patch to enable old serial/batch fields (#41723)
* chore: patch to enable old serial/batch fields

* chore: fix linters issue
2024-06-10 19:08:59 +05:30
Poorvi-R-Bhat
d9ddad0f1f fix:Tasks with duration less than a day not displayed correctly#15554 (#41633)
* fix: Tasks with duration less than a day not displayed correctly#15554

* fix: Tasks with duration less than a day not displayed correctly#15554
2024-06-10 17:30:35 +05:30
ruthra kumar
cf0a29b05f fix: use invoice outstanding on Dunning (#41817) 2024-06-10 17:14:27 +05:30
ruthra kumar
fec9d45ab3 Merge pull request #41793 from Nihantra-Patel/update_totals_taxes_15
fix: calculate totals and taxes
2024-06-10 15:17:28 +05:30
rohitwaghchaure
4b026d66dc fix: terms and conditions for material request (#41834) 2024-06-10 14:47:03 +05:30
rohitwaghchaure
36413d14d8 fix: do not fetch items with no active BOM in PP (#41833) 2024-06-10 14:18:39 +05:30
Deepesh Garg
c9bcd70173 Merge pull request #41424 from Poorvi-R-Bhat/item-code-purchase-sales-register
fix: Item-wise Sales and Purchase register with no item codes #41373
2024-06-09 11:42:09 +05:30
rohitwaghchaure
f6a4d391c0 fix: stock_value_change for legacy serial nos (#41825) 2024-06-07 22:34:05 +05:30
Deepesh Garg
8ec364df6f fix: Add additional condition application 2024-06-07 18:48:16 +05:30
rohitwaghchaure
3956354e08 fix: valuation rate for backdated legacy serial/batches (#41788) 2024-06-07 16:15:38 +05:30
Nihantra C. Patel
699cfd85c6 fix: typo in method - holiday list (#41811) 2024-06-06 19:05:57 +05:30
Deepesh Garg
c992656fa8 Merge pull request #41808 from deepeshgarg007/general_ledger_key
fix: Add posting date to key for consolidated view
2024-06-06 17:43:43 +05:30
Deepesh Garg
2c164b47a1 fix: Add posting date to key for consolidated view 2024-06-06 17:22:27 +05:30
ruthra kumar
746f95660d Merge pull request #41804 from ruthra-kumar/allow_system_manager_for_repost_settings
chore: repost settings permission overhaul
2024-06-06 15:56:33 +05:30
ruthra kumar
458d8f5ed8 chore: repost settings permission overhaul 2024-06-06 13:57:14 +05:30
Deepesh Garg
49e180a9b9 Merge pull request #41727 from deepeshgarg007/price_rule_change
fix: Do no apply pricing rule on qty change for mapped docs
2024-06-06 09:13:24 +05:30
Nihantra C. Patel
a7ec0c1cec fix: calculate totals and taxes 2024-06-05 15:49:44 +05:30
fzozyurt
5c8ea86a3f feat: Create Turkish Chart Of Accounts 2024-06-05 06:17:42 +03:00
Viny Selopal
c76f466528 fix(Vehicle): allow doc renaming and add test (#41729)
fix(Vehicle): allow renaming doc and add test
2024-06-04 21:55:27 +05:30
Nabin Hait
689e1cfc23 fix: Copy depreciation schedule on asset split only if it exists (#41775) 2024-06-04 21:50:43 +05:30
Nabin Hait
d163dbec7d fix: bank account no fieldname mismatch (#41778) 2024-06-04 21:50:05 +05:30
Nabin Hait
4ff3e6caaa fix: local var referenced before assignment (#41780) 2024-06-04 21:49:56 +05:30
Nabin Hait
71f5470dfd fix: convert percentage from str to float (#41766) 2024-06-04 15:19:42 +05:30
Nabin Hait
12e48f0b63 fix: link opportunity in prospect after creating opportunity from prospect (#41769) 2024-06-04 15:19:24 +05:30
rohitwaghchaure
cb6d8afa26 fix: incorrect batch selection while sales return (#41768) 2024-06-04 14:34:10 +05:30
rohitwaghchaure
cf508ce1ed fix: TypeError: 'float' object is not iterable (#41758) 2024-06-04 11:58:32 +05:30
Khushi Rawat
a8fc32dc32 fix: incorrect accumulated depr amount in asset depr ledger (#41654)
* fix: incorrect accumulated depr amount in asset depr ledger

* refactor: depreciation amount retrieval with query builder

* style: apply formatting changes from pre-commit
2024-06-04 11:44:39 +05:30
Khushi Rawat
60eb03a6c6 fix(minor): corrected wrong filter condition (#41755) 2024-06-04 11:43:15 +05:30
Nabin Hait
80f6228d45 fix: Ignore disabling default currency field while creating new company (#41699) 2024-06-04 11:42:20 +05:30
mergify[bot]
c3ae5bc6a5 fix: get assets received but not billed account only if any asset item is received (backport #41734) (#41750)
fix: get assets received but not billed account only if any asset item is received (#41734)

fix: get assets received but not billed account only if any asset item received
(cherry picked from commit 39885b2b01)

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2024-06-04 11:22:13 +05:30
Dany Robert
e26bc17c75 feat(gp): group by cost center 2024-06-03 13:55:12 +00:00
Dany Robert
d165638bbb feat: accounting dimension filters in gp report 2024-06-03 13:45:55 +00:00
mergify[bot]
a2039bae10 fix: set expense account as Assets RBNB only if it is booked in linked PR (backport #41368) (#41733)
fix: set expense account as Assets RBNB only if it is booked in linked PR (#41368)

* fix: set expense account as Assets RBNB only if it is booked in linked PR

* fix: broken translations

(cherry picked from commit 014486de39)

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2024-06-03 18:36:37 +05:30
Nabin Hait
740c495014 fix(stock settings): Allowed any number in stock frozen upto days field (#41736) 2024-06-03 18:34:57 +05:30
Nabin Hait
9a3569ff15 fix: Use full name instead of abbreviation (#41738) 2024-06-03 18:34:27 +05:30
Nabin Hait
d30c797d24 fix(Company): Allow Equity type account in unrealised exchange gain/loss account (#41740) 2024-06-03 18:33:48 +05:30
ruthra kumar
2be8e0dce0 Merge pull request #41742 from ruthra-kumar/allow_submit_for_repost
chore: System Manager shluld have  submit permission for repost doctypes
2024-06-03 17:49:31 +05:30
Nihantra C. Patel
441596f795 fix: payment term when creating PO from SO (#41376)
* fix: payment term when creating PO from SO

* fix: payment term when creating PO from SO

* fix: payment term when creating PO from SO

* fix: payment term when creating PO from SO
2024-06-03 17:45:31 +05:30
ruthra kumar
4558f64c0f chore: Sys Manager shluld have submit permission for repost doctypes 2024-06-03 17:31:27 +05:30
Nihantra C. Patel
4f0214d00e fix: completed DC will not appear in a delivery trip (#41655)
* fix: completed DC will not appear in a delivery trip

* fix: completed DC will not appear in a delivery trip
2024-06-03 17:26:14 +05:30
Nihantra C. Patel
3c3313594d fix: correcting balance sheet calculation for zero liabilities and equity (#41497)
* fix: correcting balance sheet calculation for zero liabilities and equity

* fix: correcting balance sheet calculation for zero liabilities and equity
2024-06-03 16:05:49 +05:30
Nihantra C. Patel
5a75c847fe fix: Select both account number and company in the account form (#41731)
* fix: Both the account number and the company should be selected in the account form

* fix: select both account number and company in the account form
2024-06-03 15:40:07 +05:30
Deepesh Garg
2b1242170c fix: Do no apply pricing rule on qty change for mapped docs 2024-06-03 10:09:20 +05:30
Deepesh Garg
d2af36e1eb chore: update condition queries in qb 2024-06-02 20:17:24 +05:30
rohitwaghchaure
9e9296e444 feat: track Semi-finished goods (including subcontracted items) against Job Cards (#38341)
* feat: Track Semi-finished goods (including subcontracted items) against Job Cards

* feat: option to add raw materials manually against operation
2024-06-02 01:28:58 +05:30
Deepesh Garg
24926ab665 Merge pull request #41717 from deepeshgarg007/jv_transaction_currency_new
fix: Transaction currency value in Journal Entry
2024-06-01 20:46:43 +05:30
Deepesh Garg
169d77da54 fix: Transaction currency value in Journal Entry 2024-06-01 19:31:28 +05:30
ruthra kumar
666232fd1c Merge pull request #41658 from rtdany10/pr-transaction-condition
fix: condition-wise filter for transaction based pricing rule
2024-06-01 16:18:50 +05:30
rohitwaghchaure
ee846f5950 feat: optional to reconcile all serial nos / batches in stock reconciliation (#41696)
feat: optional to reconcile all serial/batch
2024-06-01 15:25:51 +05:30
Markus Lobedann
0ba4bff943 Merge branch 'frappe:develop' into patch-1 2024-05-31 14:39:41 +02:00
ruthra kumar
c36f0e4a33 refactor: restrict to 'Advance in Separate Party Account' type 2024-05-31 17:11:40 +05:30
ruthra kumar
05d17d0d73 refactor: is_opening in payment entry 2024-05-31 16:55:04 +05:30
David
ee69ec97dd chore: clarify codepath around mute email and make invoice 2024-05-31 11:00:03 +02:00
rohitwaghchaure
4e37ed9033 fix: key error for stock ledger report (#41700) 2024-05-31 11:55:51 +05:30
ruthra kumar
07c421228b Merge pull request #41232 from FHenry/dev_fix_french_chart_of_account
fix: French chart of account the 4191 code must be of type Income Account
2024-05-31 10:17:21 +05:30
ruthra kumar
c6c696247a Merge pull request #41629 from blaggacao/payments/pr-1
test: add payment channel tests
2024-05-30 20:43:09 +05:30
rohitwaghchaure
968120d0eb fix: batch selection issue (#41692) 2024-05-30 18:06:29 +05:30
rohitwaghchaure
be9f960705 fix: show material to supplier button (#41686) 2024-05-30 14:05:20 +05:30
ruthra kumar
091c5496b2 refactor: enabling partial TDS application on partial invoice 2024-05-30 11:49:47 +05:30
Dany Robert
3f2343614b fix: test for pricing rule transaction with cond 2024-05-30 05:21:22 +00:00
Nijith anil
388ba7f945 fix: work order created message pops up if no items are selected (#41677) 2024-05-29 23:32:07 +05:30
Deepesh Garg
289d216552 Merge pull request #41676 from deepeshgarg007/account_balace_report
fix: Filters in account balance report
2024-05-29 12:48:02 +05:30
Deepesh Garg
1c9fe691ea fix: Filters in account balance report 2024-05-29 12:25:56 +05:30
Deepesh Garg
c41b239881 Merge pull request #41548 from Nihantra-Patel/feat_trends_report
fix: add include closed orders option in so/po trends report
2024-05-29 10:31:51 +05:30
Deepesh Garg
9f85483199 Merge pull request #41374 from Nihantra-Patel/no_add_variant_item_dev
fix: not allow template item in product bundle item
2024-05-29 10:30:21 +05:30
Nihantra C. Patel
882227a460 fix: price list when invoice created from timesheet 2024-05-29 10:26:49 +05:30
Deepesh Garg
006b1f553c Merge pull request #40873 from Nihantra-Patel/upd_timesheet_task
fix: update the task status from timesheet
2024-05-29 10:00:53 +05:30
Khushi Rawat
6b0ce33030 refactor: renamed number of depreciations booked to opening booked de… (#41515)
* refactor: renamed number of depreciations booked to opening booked depreciations

* feat: introduced new field for showing total number of booked depreciations
2024-05-28 20:37:52 +05:30
rohitwaghchaure
ce834f5dba fix: multiple issues related to serial and batch bundle (#41662) 2024-05-28 18:48:09 +05:30
Marica
e3cf53a8b7 feat: Add Party details to Serial No Ledger Report (#41656)
- Since no party details are present in Serial No anymore, it is hard to get a view of which SN was sold to/purchased from which party
- Add Party fields to report
2024-05-28 15:28:02 +05:30
barredterra
4165fd44b5 Merge branch 'develop' into print-language 2024-05-27 18:52:05 +02:00
Raffael Meyer
d3bdd41358 Merge pull request #41659 from barredterra/auditor-perms 2024-05-27 18:48:50 +02:00
barredterra
eaa4efbc45 fix: allow Auditor to read a Fiscal Year 2024-05-27 17:40:08 +02:00
barredterra
06401cc84f fix: allow Auditor to select a company 2024-05-27 17:39:46 +02:00
Dany Robert
e3fd82766f fix: condition filter for transaction pricing rule 2024-05-27 14:50:28 +00:00
ruthra kumar
537e0e32b2 Merge pull request #40775 from casesolved-co-uk/sa_report
feat: significant enhancements to sales analytics report to support charts
2024-05-27 14:31:02 +05:30
ruthra kumar
47bc5691a1 refactor: remove use of can_create for Payment Request (#41647) 2024-05-27 09:57:11 +02:00
ruthra kumar
c5c4d5c61f Merge pull request #41401 from Nihantra-Patel/fix_project_cost_center_filter
fix: cost center filter according to the company in project
2024-05-27 10:09:37 +05:30
David
25931c4db2 test: add payment channel tests 2024-05-24 11:08:23 +02:00
rohitwaghchaure
683c1f04c8 fix: Unable to 'Get Suppliers' using tags in Request for Quotation (#41626) 2024-05-24 13:03:57 +05:30
Akhil Narang
b6350c86d1 Merge pull request #41601 from akhilnarang/add-indices
fix: add in some indices to speed up Purchase Order deletion
2024-05-24 10:57:04 +05:30
ruthra kumar
fac0fcb9d5 Merge pull request #41443 from cogk/fix-use-get-all-for-advance-status-update
fix(AccountsController): Use get_all to get payment requests when updating advance payment status
2024-05-24 10:40:15 +05:30
Akhil Narang
3f06f1905f refactor: use json directly instead of using frappe.json (#41609) 2024-05-23 16:00:42 +02:00
Frappe PR Bot
954ef85b95 fix: sync translations from crowdin (#41549) 2024-05-23 15:56:33 +02:00
Raffael Meyer
06c7ce1e95 Merge branch 'develop' into print-language 2024-05-23 14:36:49 +02:00
ruthra kumar
fffcb5dc9f Merge pull request #41594 from ruthra-kumar/refactor_payment_period_report
refactor: 'Payment Period Based On Invoice Date' report
2024-05-23 17:45:28 +05:30
ruthra kumar
5d0e82f40b Merge pull request #41603 from ruthra-kumar/remove_format_based_naming_on_internal_doctypes
refactor: remove 'format:' based naming in internal doctypes
2024-05-23 17:44:14 +05:30
ruthra kumar
e2ec3e453a refactor: remove 'format:' based naming in internal doctypes 2024-05-23 17:01:24 +05:30
Akhil Narang
0303d7dbdc fix: add in some indices to speed up Purchase Order deletion
`tabSales Order`.`inter_company_order_reference`
`tabSales Invoice Item`.`purchase_order`

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-05-23 16:36:41 +05:30
rohitwaghchaure
418439b58f fix: SCR batch qty issue (#41595) 2024-05-23 14:51:54 +05:30
Akhil Narang
e39d2e1e69 Merge pull request #41576 from akhilnarang/sync-ruff-config
chore: sync ruff config with framework
2024-05-23 12:50:33 +05:30
ruthra kumar
c4e2abb973 refactor: replace against_voucher with against_voucher_no 2024-05-23 12:08:51 +05:30
ruthra kumar
014b542cf3 refactor: remove debit and credit 2024-05-23 11:59:57 +05:30
ruthra kumar
cb3c20dcd3 refactor: query payment ledger for payments 2024-05-23 11:52:53 +05:30
rohitwaghchaure
ad817cddad perf: sales order UI render (#41591) 2024-05-22 19:57:52 +05:30
rohitwaghchaure
04a49cef24 fix: opening stock not showing in the stock ledger report for the bat… (#41584)
fix: opening stock not showing in the stock ledger report for the batch filter
2024-05-22 18:22:40 +05:30
Poorvi-R-Bhat
eafa88b8e9 fix: fixing Item-wise sales register #41373 2024-05-22 12:39:22 +05:30
Poorvi-R-Bhat
76073ae228 fix: fixing Item-wise sales register and purchase register #41373 2024-05-22 12:26:02 +05:30
Ankush Menat
85b1a8001b ci: ruff only fix imports 2024-05-21 16:05:16 +05:30
Ankush Menat
3b4913ec81 ci: dont auto apply fixes
I've personally encountered ~5 instances of bad auto fixes, let
developers apply the fixes.
2024-05-21 16:03:31 +05:30
jabir-elat
d7df2cbdc5 fix: correct report name in inner button (#41568)
Previously, the report name was incorrectly listed as "Cash Flow Statement" instead of "Cash Flow". This mismatch caused the "Cash Flow" report to not open correctly in the chart of accounts tree view, as the report ID is "Cash Flow".
2024-05-21 14:38:13 +05:30
rohitwaghchaure
ac4bcd5ca7 fix: job card time logs overlap issue (#41567) 2024-05-21 14:37:04 +05:30
rohitwaghchaure
4261c3474b fix: not able to delete line items in the subcontracting receipt (#41569) 2024-05-21 14:36:35 +05:30
rohitwaghchaure
4e4c1e4bef fix: Deadlock on submitting Sales Invoice (#41417) 2024-05-21 10:33:29 +05:30
rohitwaghchaure
ae3f5a38e1 fix: BOM creator validation for parent row no (#41413)
fix: bom creator valiation for parent row no
2024-05-20 19:19:45 +05:30
Nabin Hait
dfdb95bbbe patch: create custom field for accounting dimensions only if the field not exists already (#41484)
fix: create custom field for accounting dimensions only if the field not exists already
2024-05-20 12:54:20 +00:00
Nabin Hait
a1d489195d fix: convert invoice_portion value from str to float (#41485) 2024-05-20 17:57:59 +05:30
Nabin Hait
f24d61daea fix: Auto reconcile only after selecting bank account (#41489) 2024-05-20 17:57:33 +05:30
Nabin Hait
0191727149 Merge pull request #41502 from khushi8112/gross-purchase-amount-too-low-to-make-depr-schedule
fix: added validation message for low gross purchase amount
2024-05-20 17:55:09 +05:30
Nabin Hait
e22b0fd6e1 Merge pull request #41495 from nabinhait/target-variance-for-parent-item-groups
fix: Show acheived amount and variance for parent item groups
2024-05-20 16:25:01 +05:30
Nihantra Patel
91c9d964f9 fix: add include closed orders option in so/po trends report 2024-05-20 16:02:10 +05:30
Nihantra Patel
6e3782a061 fix: add include closed orders option in so/po trends report 2024-05-20 15:59:45 +05:30
Nihantra Patel
eb4f94ddf2 fix: add include closed orders option in so/po trends report 2024-05-20 15:51:27 +05:30
ruthra kumar
be1fce2da6 Merge pull request #41492 from ruthra-kumar/reconciliation_on_advance_payment_date
refactor: For advances booked in Separate account, reconciliation date can be configured
2024-05-20 14:58:58 +05:30
ruthra kumar
30aa4e031d test: reconciliation date for advance payments 2024-05-20 14:42:41 +05:30
rohitwaghchaure
214b38f7c8 fix: valuation rate for legacy serial nos (#41543)
fix: valuation rate for serial nos
2024-05-20 13:41:16 +05:30
Frappe PR Bot
28e10dd703 fix: sync translations from crowdin (#41411) 2024-05-19 17:14:23 +02:00
Raffael Meyer
f7eb9d44a8 Merge pull request #41540 from frappe/pot_develop_2024-05-19 2024-05-19 15:22:28 +02:00
frappe-pr-bot
b071e952dd chore: update POT file 2024-05-19 09:35:33 +00:00
Raffael Meyer
7b9fd394b0 feat: enter serial range in Serial/Batch Selector (#41530)
* feat: util for generating serial nos from range string

* feat: enter serial range in Serial/Batch Selector
2024-05-18 10:25:50 +05:30
ruthra kumar
7ce8fc9ba2 Merge pull request #41529 from ruthra-kumar/ignore_internal_doctypes_on_cancel_for_dunning
refactor: ignore internal doctypes on Dunning cancellation
2024-05-17 21:00:22 +05:30
ruthra kumar
63c2cf13fd refactor: ignore internal doctypes on Dunning cancellation 2024-05-17 20:43:19 +05:30
Nabin Hait
37d97fad17 Merge pull request #41523 from ruthra-kumar/fix_pr_and_pi_debit_credit_difference
fix: minor Dr and Cr between Purchase Receipt and Purchase Invoice
2024-05-17 17:46:10 +05:30
rohitwaghchaure
5cf5b18aea fix: priority not working for multiple pricing rules (#41516) 2024-05-17 17:09:01 +05:30
ruthra kumar
1c0a24424a fix: minor Dr and Cr between Purchase Receipt and Purchase Invoice
This applies for Provisional Accounting for Non-stock items
2024-05-17 17:06:39 +05:30
rohitwaghchaure
61a4188440 fix: timeout error while submitting purchase invoice (#41520) 2024-05-17 16:36:38 +05:30
ruthra kumar
3f6787b267 Merge pull request #41517 from ruthra-kumar/fix_typeerror_in_purchase_invoice
fix: typerror on hide_fields
2024-05-17 14:47:07 +05:30
ruthra kumar
deb9766f2a fix: typerror on hide_fields 2024-05-17 14:41:17 +05:30
ruthra kumar
d61f56207c Merge pull request #41511 from ruthra-kumar/possible_sql_error_on_general_ledger
fix: possible sql error on General Ledger
2024-05-17 10:55:19 +05:30
ruthra kumar
76131f8e10 fix: possible sql error on General Ledger 2024-05-17 10:37:07 +05:30
ruthra kumar
cafa2f52e5 refactor: enable no-copy on advance payment flags 2024-05-17 10:21:37 +05:30
Deepesh Garg
e883d6a7d3 Merge pull request #41451 from deepeshgarg007/demo_deletion_fixes
fix: Demo data clearing
2024-05-17 09:16:11 +05:30
Deepesh Garg
44e6563af6 Merge pull request #41504 from deepeshgarg007/pos_error_message
fix: Unable to add items in POS Invoice
2024-05-16 19:31:53 +05:30
Deepesh Garg
7a3f8a5afb fix: Unable to add items in POS Invoice 2024-05-16 19:19:52 +05:30
Khushi Rawat
8a30701893 fix: added validation message for low gross purchase amount 2024-05-16 16:37:49 +05:30
rohitwaghchaure
500c546691 fix: stock levels for batch (#41494) 2024-05-16 15:58:58 +05:30
ruthra kumar
af8275c321 Merge pull request #40072 from Nihantra-Patel/fix_print_bold
fix: print format bold for field "total"
2024-05-16 15:19:37 +05:30
Samuel Danieli
bd381cc0c6 chore(BOM Explorer): display items in the same order as in the BOM (#41496) 2024-05-16 15:13:22 +05:30
Nabin Hait
8ac11ae88d fix: Show achieved amount and variance for parent item groups 2024-05-16 14:28:22 +05:30
Nihantra C. Patel
2761705c62 Merge branch 'develop' into fix_print_bold 2024-05-16 14:11:31 +05:30
ruthra kumar
000c1b49dc chore: better description 2024-05-16 12:40:09 +05:30
ruthra kumar
070e2d4d26 refactor: advance payments, allow configurable reconciliation date 2024-05-16 12:07:19 +05:30
Florian HENRY
3c1ca1cfbb Merge branch 'develop' of https://github.com/frappe/erpnext into dev_fix_french_chart_of_account 2024-05-15 18:37:09 +02:00
rohitwaghchaure
81a9521f04 fix: not able to submit landed cost voucher (#41481) 2024-05-15 17:49:02 +05:30
rohitwaghchaure
0363afcfd0 fix: validate reorder group warehouse (#41478) 2024-05-15 14:03:51 +05:30
Ankush Menat
7a47b2157b ci: remove mergify from release notes (#41475)
Mergify isn't author, just backporter.

All our stable branch PRs don't have authors so eh.
2024-05-15 05:37:30 +00:00
Florian HENRY
abfb8a7201 Merge branch 'develop' of https://github.com/frappe/erpnext into dev_fix_french_chart_of_account 2024-05-15 07:34:20 +02:00
Nabin Hait
fc797836af Merge pull request #41235 from khushi8112/depreciation_based_daily_prorata
Depreciation based on daily prorata
2024-05-15 08:40:16 +05:30
Nabin Hait
7d86881579 style: new line before function 2024-05-15 08:18:05 +05:30
Khushi Rawat
d22df324ec fix: removed same named function 2024-05-15 01:10:54 +05:30
Nabin Hait
4a4c674553 Merge pull request #41467 from khushi8112/unlink-asset-reference-issue
Asset cancelation issue
2024-05-14 22:41:45 +05:30
Khushi Rawat
7b264e5e11 refactor: code optimization 2024-05-14 20:12:01 +05:30
Khushi Rawat
c0c8c1bb02 fix: pro rata based depreciation with opening accumulated depreciation 2024-05-14 20:12:01 +05:30
Khushi Rawat
d40b55468c test: made minor change in existing test 2024-05-14 20:12:01 +05:30
Khushi Rawat
fccd37d32d fix: incorrect total days calculation 2024-05-14 20:12:01 +05:30
Khushi Rawat
b8a98a273b fix: daily prorata based depreciation bug in wdv method 2024-05-14 20:11:52 +05:30
Nabin Hait
99d417bbc2 Merge pull request #41457 from khushi8112/comparison-between-none-type-and-date-time-instances
fix: filtered out data having none values in date field
2024-05-14 20:10:52 +05:30
Khushi Rawat
f337392f3e fix(wip): daily depreciation bug 2024-05-14 20:10:42 +05:30
Khushi Rawat
e843683ad1 style: code optimization 2024-05-14 20:03:58 +05:30
Khushi Rawat
a36b7fb95a style: code optimization 2024-05-14 19:52:57 +05:30
Nabin Hait
16751ec935 Merge pull request #41420 from khushi8112/get-prorata-depreciation-based-on-total-days-per-year
Get prorata depreciation based on total days per year
2024-05-14 19:24:30 +05:30
Nabin Hait
0736154074 Merge pull request #41089 from khushi8112/rename-purchase-receipt-amount-field-to-purchase-amount
Refactor: Rename purchase receipt amount field to purchase amount
2024-05-14 18:16:39 +05:30
Khushi Rawat
fa2b6c4490 fix: Asset cancelation issue 2024-05-14 17:56:06 +05:30
Khushi Rawat
3bd455ac85 fix: filtered out data having none values in date field 2024-05-14 14:24:18 +05:30
Deepesh Garg
d6fe220fab fix: Demo data clearing 2024-05-14 10:27:56 +05:30
Deepesh Garg
e3f539325e Merge pull request #41412 from deepeshgarg007/party_name_ar_ap_report
fix: Duplicate party name column in AR/AP report
2024-05-14 08:22:22 +05:30
rohitwaghchaure
e3a80ebdf3 fix: zero valuation rate for batched item (#41446) 2024-05-14 05:19:32 +05:30
rohitwaghchaure
3309359822 fix: 'Bill for Rejected Quantity in Purchase Invoice' feature not working (#41437) 2024-05-13 21:38:24 +05:30
rohitwaghchaure
6bd13d7452 fix: Unknown column 'tabBatch.batch_no' in 'where clause' (#41418)
fix: unknown column 'tabBatch.batch_no' in 'where clause'
2024-05-13 21:37:35 +05:30
Corentin Flr
13a3a6a82e fix(AccountsController): Use get_all to get payment requests when updating advance payment status 2024-05-13 17:11:08 +02:00
Raffael Meyer
64333373ca Merge pull request #41384 from barredterra/sales-order-actions 2024-05-13 15:40:58 +02:00
Deepesh Garg
c6fd42fe60 Merge pull request #41429 from deepeshgarg007/immutable_ledger
feat: Config to enable immutable ledger
2024-05-13 17:42:59 +05:30
Deepesh Garg
77bfea975f Merge branch 'develop' of https://github.com/frappe/erpnext into immutable_ledger 2024-05-13 17:22:27 +05:30
rohitwaghchaure
663fcb374d fix: data getting override in delivery trip (#41431)
fix: data getting override
2024-05-13 16:24:46 +05:30
rohitwaghchaure
065163146c fix: valuation issue for batch (#41425) 2024-05-13 16:03:44 +05:30
Deepesh Garg
d56f52b0ba feat: Config to enable immutable ledger 2024-05-13 15:39:22 +05:30
Deepesh Garg
32a463652e Merge pull request #40468 from Nihantra-Patel/upd_accounts_description
fix: update description of Supplier Invoice Number
2024-05-13 15:12:23 +05:30
Nihantra C. Patel
7f2062e2c5 Merge branch 'develop' into upd_accounts_description 2024-05-13 14:56:23 +05:30
Poorvi-R-Bhat
1b45ecfcae fix: Item-wise Sales and Purchase register with no item codes #41373 2024-05-13 09:35:10 +05:30
barredterra
382d0ff453 fix: migrate lead notes 2024-05-12 23:01:19 +02:00
Khushi Rawat
98e7dfe97f fix(minor): removed extra parameter 2024-05-13 00:10:43 +05:30
Khushi Rawat
6b24143f72 refactor: removed code duplicacies 2024-05-12 23:01:44 +05:30
Khushi Rawat
d3200fb67f fix(wip): depreciation calculation after asset value adjustment 2024-05-12 23:01:44 +05:30
Deepesh Garg
7501fe8ebd fix: Duplicate party name column in AR/AP report 2024-05-11 19:35:52 +05:30
Frappe PR Bot
3fa8706f57 chore: update POT file (#41326) 2024-05-10 16:29:49 +02:00
Frappe PR Bot
f92aabd0f3 fix: sync translations from crowdin (#41262) 2024-05-10 16:28:17 +02:00
rehanrehman389
628d7e6458 chore: typo in Stock Settings (#41396) 2024-05-10 15:40:02 +05:30
Khushi Rawat
360c3b36ed fix: removed unrelated code modification 2024-05-10 14:39:59 +05:30
“Khushi
31841b4ab2 refactor: renamed purchase receipt amount field to purchase amount 2024-05-10 14:17:03 +05:30
Nihantra C. Patel
ba60b5911a fix: bold total in exponential smoothing forecasting (#41393)
* fix: bold total in exponential smoothing forecasting

* fix: bold total in exponential smoothing forecasting
2024-05-10 13:12:23 +05:30
Nihantra C. Patel
501c6aa126 fix: cost center filter according to the company in project 2024-05-10 12:40:01 +05:30
Nihantra C. Patel
cfde8088b4 fix: cost center filter according to the company in project 2024-05-10 12:35:24 +05:30
Nihantra C. Patel
249e8264dd fix: cost center filter according to the company in project 2024-05-10 12:31:15 +05:30
Poorvi
c90185f533 fix: fixing Item-wise sales register 2024-05-10 11:47:57 +05:30
ruthra kumar
08899d05fb Merge pull request #41040 from Nihantra-Patel/fix_quot_prospect
fix: address filter and quotation to for prospect
2024-05-09 12:14:41 +05:30
ruthra kumar
754c7f6d1c refactor: make use of doc.quotation_to 2024-05-09 11:58:33 +05:30
Nabin Hait
92673d706c Merge pull request #41024 from khushi8112/expense-account-based-on-asset-category
fix: expense account should be fetched from related asset category
2024-05-09 01:30:45 +05:30
Raffael Meyer
9c3a105f85 fix: consistent use of "Address & Contact" (#41386) 2024-05-08 16:20:35 +00:00
barredterra
418bdc1dcc fix(Delivery Note): only show permitted actions 2024-05-08 17:55:16 +02:00
barredterra
c29d955371 fix(Sales Order): only show permitted actions 2024-05-08 16:23:46 +02:00
Khushi Rawat
272ce24016 style: code changes for better readability
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2024-05-08 19:17:09 +05:30
“Khushi
651e4696fd fix: expense account should be fetched from related asset category 2024-05-08 19:14:51 +05:30
rohitwaghchaure
5ed1b6b8fb fix: incorrect qty picked in the pick list (#41378) 2024-05-08 17:56:10 +05:30
Nabin Hait
cd5d244d2c Merge pull request #41236 from nabinhait/merge_gle_in_transaction_currency
fix: Merge debit and credit in transaction currency while merging gle with similar head
2024-05-08 17:50:56 +05:30
Nihantra C. Patel
db5ed972e5 fix: not allow template item in product bundle item 2024-05-08 10:17:49 +05:30
rohitwaghchaure
0887161f2a perf: index on item code for the Pick List Item doctype (#41357) 2024-05-07 16:29:20 +05:30
rohitwaghchaure
544fc60093 fix: filter validation for batch-wise balance history report (#41356)
fix: filter validation for batchwise balance history report
2024-05-07 16:29:08 +05:30
ruthra kumar
c50663c640 Merge pull request #41288 from ruthra-kumar/bug_in_promotional_scheme
fix: pricing rule rounding
2024-05-07 10:01:00 +05:30
ruthra kumar
c41a037174 refactor(test): test floor based rounding 2024-05-07 09:44:10 +05:30
Raffael Meyer
c710ad822c fix(Item): allow UOM conversion for non-stock items (#41267) 2024-05-06 18:50:30 +02:00
rohitwaghchaure
ebfbe94aaf fix: pick list with multiple batch issue (#41335)
fix: pick list with batchb issue
2024-05-06 13:17:07 +05:30
ruthra kumar
e51ccecd8a Merge pull request #41334 from ruthra-kumar/fix_gp_purchase_invoice_item
fix: incorrect query for Purchase Invoice rate in GP
2024-05-06 12:53:46 +05:30
ruthra kumar
bd8382c592 fix: incorrect query for Purchase Invoice rate in GP 2024-05-06 12:07:33 +05:30
Ankush Menat
6142d07f1a fix: update project URLs (#41331) 2024-05-06 06:02:57 +00:00
Deepesh Garg
ed5344d58b Merge pull request #41318 from deepeshgarg007/psoa_cost_center
fix: Cost center not getting saved in PSOA
2024-05-04 13:55:40 +05:30
Deepesh Garg
44228b754f Merge pull request #41314 from deepeshgarg007/tcs_opening
fix: Do not deduct TCS for opening invoices
2024-05-04 13:54:46 +05:30
Deepesh Garg
d19ae4ce4c Merge pull request #41279 from deepeshgarg007/order_advance
fix: GL Entries against orders as an advance
2024-05-03 19:41:24 +05:30
Deepesh Garg
58f7039630 fix: Cost center not getting saved in PSOA 2024-05-03 18:34:27 +05:30
Deepesh Garg
eac7be2d0f test: Add bank account 2024-05-03 18:30:47 +05:30
Deepesh Garg
42ef95759d test: Update failing tests 2024-05-03 17:04:37 +05:30
Deepesh Garg
eb31017058 fix: Add PO reference 2024-05-03 15:56:29 +05:30
Deepesh Garg
69d68592ad Merge pull request #41311 from deepeshgarg007/future_subscription_updates
fix: future subscription updates
2024-05-03 12:04:39 +05:30
Deepesh Garg
eb9f579b8f fix: Do not deduct TCS for opening invoices 2024-05-03 11:47:43 +05:30
Raffael Meyer
e4db0562ac fix: search for item price in stock UOM (#41075) 2024-05-03 10:06:52 +05:30
Raffael Meyer
a61148c464 feat(Item Price): make UOM mandatory (#40588) 2024-05-03 10:04:24 +05:30
Deepesh Garg
7fa22069d8 test: Add posting dates 2024-05-03 09:25:26 +05:30
Deepesh Garg
54a12c5186 Merge pull request #41260 from deepeshgarg007/pi_gl_entries_pi
fix: Purchase Invoice gain loss gl entry for periodic inventory
2024-05-03 08:54:57 +05:30
HENRY Florian
c8e92cb1b2 fix: missing Item Name on Save for Quotation created from Item (#41233)
* fix: missing Item Name on Save for Quotation created from Item

* fix: missing Item Name on Save for Quotation created from Item
2024-05-02 22:22:12 +05:30
Akhil Narang
93c6324115 Merge pull request #41299 from frappe/revert-41146-fix-add-import
Revert "fix(supplier): add back import that got removed by ruff"
2024-05-02 17:59:10 +05:30
Akhil Narang
f26be2a303 Revert "fix(supplier): add back import that got removed by ruff" 2024-05-02 17:42:33 +05:30
David Arnold
61f5ebd2dd feat: create delivery trip on draft notes (#38559)
feat: create draft delivery trips from draft delivery notes
2024-05-02 16:00:21 +05:30
Akhil Narang
22c345a24a Merge pull request #41146 from akhilnarang/fix-add-import
fix(supplier): add back import that got removed by ruff
2024-05-02 12:23:58 +05:30
ruthra kumar
9bf37426c1 fix: pricing rule rounding
Consider a pricing rule of 20:1 with recursion enabled, free items
should follow the below progression

|   Qty | Free item qty |
|-------+---------------|
|  0-19 |             0 |
| 20-39 |             1 |
| 40-59 |             2 |
2024-05-02 09:40:07 +05:30
rohitwaghchaure
1cbc200770 fix: added brand column in Warehouse wise Item Balance Age and Value … (#41280)
fix: added brand coulmn in Warehouse wise Item Balance Age and Value report
2024-05-01 15:46:43 +05:30
Deepesh Garg
8289f3c724 fix: GL Entries against orders as an advance 2024-05-01 12:17:08 +05:30
mergify[bot]
da3010a41f fix: multiple pricing rules with discount amount and discount percentage not working (backport #41211) (#41241)
fix: multiple pricing rules with discount amount and discount percentage not working (#41211)

(cherry picked from commit 54313b5db9)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-04-30 21:48:46 +05:30
ruthra kumar
ed9af7d12e Merge pull request #41268 from ruthra-kumar/validation_to_prevent_overallocation_on_reconciliation
fix: validation to prevent overallocation
2024-04-30 17:37:46 +05:30
ruthra kumar
bf755fab55 fix: validation to prevent overallocation 2024-04-30 17:19:41 +05:30
Deepesh Garg
2402447568 fix: Purchase Invoice gain loss gl entry for periodic inventory 2024-04-30 13:28:43 +05:30
Deepesh Garg
f77d5db38e Merge pull request #41258 from deepeshgarg007/psoa_ageing
fix: PSOA ageing
2024-04-30 13:10:12 +05:30
Deepesh Garg
fed2d11905 fix: PSOA ageing 2024-04-30 12:50:21 +05:30
ruthra kumar
8861a76bd0 Merge pull request #41252 from ruthra-kumar/permission_issue_on_tax_withholding_category
fix: permission issue when user permission restricts on company
2024-04-30 11:20:18 +05:30
Deepesh Garg
56f0b2628e Merge pull request #41171 from deepeshgarg007/deferred_revenue_expense_report
fix: Invoice with no GLEs in deferred report
2024-04-30 11:14:54 +05:30
ruthra kumar
7a6cc84d41 fix: permission issue when user permission restricts on company 2024-04-30 10:26:55 +05:30
Deepesh Garg
a34c99385c Merge pull request #41173 from deepeshgarg007/br_paid_amount
fix: paid amount in bank reconciliation tool
2024-04-30 10:25:03 +05:30
Deepesh Garg
94339c569e Merge pull request #41219 from deepeshgarg007/br_company_user_perm
fix: Ignore user perm in Bank Reco Tool for company
2024-04-30 10:22:27 +05:30
ruthra kumar
1df06efd97 Merge pull request #41240 from ruthra-kumar/fix_based_on_payment_term_for_single_term
fix: display term name for single term invoices in AR/AP
2024-04-30 07:09:00 +05:30
ruthra kumar
52e52e83a9 Merge pull request #41194 from ruthra-kumar/fix_incorrectly_applying_tds_when_advance_in_prev_fiscal_year
fix: TDS incorrectly applied when Advance is in previous FY
2024-04-30 06:56:49 +05:30
Frappe PR Bot
9f092dbe9f chore: update POT file (#41220) 2024-04-30 00:51:38 +02:00
Frappe PR Bot
b324a02fbb fix: sync translations from crowdin (#40965) 2024-04-30 00:50:41 +02:00
ruthra kumar
5fa4cfee04 fix: display term name for single term invoices 2024-04-29 19:31:21 +05:30
Deepesh Garg
5e48c1ac51 Merge pull request #41237 from nikkothari22/fix-party-type-label-on-accounting-preview
fix: party and party type label on accounting preview
2024-04-29 18:53:39 +05:30
Nabin Hait
e0d12ba4d0 fix: Patch to fix the incorrect debit and credit in transaction currency 2024-04-29 17:44:41 +05:30
Nikhil Kothari
f7f3b22786 fix: party and party type label on accounting preview 2024-04-29 17:31:39 +05:30
Nabin Hait
e43697d359 fix: Merge debit and credit in transaction currency while merging gle with similar head 2024-04-29 17:01:48 +05:30
Florian HENRY
72057adc94 fix: French chart of account the 4191 code must be of type Income Account 2024-04-29 10:18:02 +02:00
ruthra kumar
2f9a144023 test: TDS deduction across fiscal year 2024-04-29 12:29:05 +05:30
Deepesh Garg
9e2ecd67f9 Merge pull request #40865 from rtdany10/def-expns
fix: missing def expense if no exp in first month
2024-04-29 10:24:35 +05:30
ruthra kumar
b195f519e2 fix: incorrectly applying TDS when Advance is in previous FY 2024-04-29 08:24:20 +05:30
Deepesh Garg
9f346e7ba0 fix: Ignore user perm in Bank Reco Tool for company 2024-04-28 14:41:34 +05:30
ruthra kumar
41695e601d Merge pull request #41208 from ruthra-kumar/incorrect_receivable_account_handling_on_reconciliation_tool
fix: set receivable account based on response type
2024-04-26 14:12:02 +05:30
ruthra kumar
066859cca0 fix: handle and receivable accounts based on response type 2024-04-26 13:59:22 +05:30
rohitwaghchaure
44f9059338 Merge pull request #41165 from rohitwaghchaure/feat-allow-to-do-reposting-for-all-transactions
feat: allow to do reposting for all stock transactions (audit)
2024-04-26 13:43:34 +05:30
rohitwaghchaure
d95d00b7c8 Merge pull request #41167 from rohitwaghchaure/feat-warehouse-type-filter-for-reports
fix: warehouse type filter for stock reports
2024-04-26 13:10:25 +05:30
rohitwaghchaure
880d061164 Merge pull request #41182 from Nihantra-Patel/email_-rendering
fix: rendering the email template when user HTML
2024-04-26 13:09:53 +05:30
rohitwaghchaure
bb5f1dae75 Merge pull request #41185 from Nihantra-Patel/delivery_trip
fix: args when get the delivery note in delivery trip
2024-04-26 13:09:11 +05:30
Rushabh Mehta
1bb1b69dea Merge pull request #40716 from khushi8112/incorrect-cash-flow-report
Incorrect cash flow report
2024-04-26 12:52:57 +05:30
rohitwaghchaure
3562c2d1d1 Merge pull request #41195 from rohitwaghchaure/fixed-incorrect-basic-rate-13963
fix: basic rate for SABB
2024-04-26 12:49:46 +05:30
Khushi Rawat
46736a737f fix(minor): don't translate voucher type 2024-04-26 12:36:34 +05:30
Rushabh Mehta
5b1e860489 Merge pull request #40915 from khushi8112/company-field-should-be-fetch-from-parent-acc
fix: company field should be fetch from parent acc
2024-04-26 12:28:06 +05:30
rohitwaghchaure
8e095335be Merge pull request #41192 from rohitwaghchaure/fixed-13960
fix: duplicate column in the stock ledger report
2024-04-26 12:21:47 +05:30
Rohit Waghchaure
7fa94843aa fix: basic rate for SABB 2024-04-26 12:20:08 +05:30
Rohit Waghchaure
be7fd6bfb4 fix: duplicate column in the stock ledger report 2024-04-26 10:43:30 +05:30
ruthra kumar
90d1873ad0 Merge pull request #41183 from ruthra-kumar/disable_advance_for_non_customer_or_supplier
fix: restrict Advance in separate party to customer and supplier
2024-04-25 19:59:16 +05:30
Ankush Menat
341fb6d8f3 fix: handle stock balance unbuffered_cursor error (#41186) 2024-04-25 11:43:58 +00:00
Nihantra Patel
ca577f7aaa fix: args when get the delivery note in delivery trip 2024-04-25 16:46:29 +05:30
Nihantra Patel
2f359e201d fix: args when get the delivery note in delivery trip 2024-04-25 16:42:38 +05:30
ruthra kumar
3c1af2acf0 fix: enable advance in separate acc only for customer and Supplier 2024-04-25 13:26:15 +05:30
Nihantra C. Patel
7cb66f7fd3 fix: rendering the email template when user HTML 2024-04-25 12:01:28 +05:30
Deepesh Garg
a48966f08c fix: paid amount in bank reconciliation tool 2024-04-24 21:50:03 +05:30
Deepesh Garg
ecf07bd128 chore: remove debug flag 2024-04-24 19:44:47 +05:30
Deepesh Garg
1c613ada6f fix: Invoice with no GLEs in deferred report 2024-04-24 19:40:05 +05:30
Rohit Waghchaure
4250ac821f fix: warehouse type filter for stock reports 2024-04-24 14:41:10 +05:30
Rohit Waghchaure
aefbe21b46 feat: allow to do reposting for all transactions (audit) 2024-04-24 14:31:29 +05:30
Akhil Narang
808dbfcade fix(supplier): add back import that got removed by ruff
It isn't unused, just isn't directly called

Fixes 3effaf21ef

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-04-23 13:26:05 +05:30
Gursheen Kaur Anand
58c7922c36 Merge branch 'develop' into valuation-tax-gle-via-lcv 2024-04-21 19:15:21 +05:30
Gursheen Anand
54a58e9205 chore: resolve conflicts 2024-04-21 19:07:08 +05:30
barredterra
eb119dcb4d fix: language in sales transactions 2024-04-20 01:24:35 +02:00
Markus Lobedann
9d9331408f Merge branch 'frappe:develop' into patch-1 2024-04-18 14:51:05 +02:00
Nihantra Patel
2896e3666c fix: address filter and quotation to for prospect 2024-04-16 18:13:49 +05:30
Nihantra Patel
24a68a79df fix: address filter and quotation to for prospect 2024-04-16 18:12:20 +05:30
Nihantra Patel
fe5b88522e fix: address filter and quotation to for prospect 2024-04-16 18:06:42 +05:30
Nihantra C. Patel
39d6df7c7d fix: price list when invoice created from timesheet 2024-04-11 12:09:27 +05:30
Khushi Rawat
5f7e06ba6f Merge branch 'develop' into company-field-should-be-fetch-from-parent-acc 2024-04-09 14:36:04 +05:30
“Khushi
d791fa7460 fix: by default company field value is fetched from parent account 2024-04-09 11:18:33 +05:30
Dany Robert
01888c98bc fix: expense causing p&l test case to fail 2024-04-06 06:13:42 +00:00
Dany Robert
581af4eced chore: semgrep 2024-04-05 18:16:26 +00:00
Dany Robert
7ef4dbcaf6 fix: test case for zero deferred expense 2024-04-05 17:59:48 +00:00
Nihantra Patel
4e5bc82a17 fix: update the task status from timesheet 2024-04-05 12:27:34 +05:30
Dany Robert
5c9ce575f6 fix: missing def expense if no exp in first month 2024-04-04 16:18:20 +00:00
Markus Lobedann
a2f878e1d1 fix: 🐛 use doctype File directly instead of save_file from file_manager.py
`save_file` will change the filename and not clean up after itself after a rollback
2024-04-04 10:31:34 +02:00
Richard Case
ee140369a3 feat: significant enhancements to sales analytics report to support charts 2024-03-29 22:51:28 +00:00
David Arnold
7032a108a8 Merge branch 'develop' into feat/add-login-user-to-driver 2024-03-29 10:51:30 +01:00
“Khushi
db1f7fcf63 fix: fixed incorrect cash flow data in finacial statement report 2024-03-27 16:48:49 +05:30
Deepesh Garg
eccd5b4c5d chore: better description 2024-03-16 19:11:59 +05:30
Gursheen Kaur Anand
05e8b6c9f6 Merge branch 'develop' into valuation-tax-gle-via-lcv 2024-03-15 12:51:40 +05:30
Nihantra Patel
d721de13aa fix: update description of Supplier Invoice Number 2024-03-15 12:14:34 +05:30
David
9941469fca Merge remote-tracking branch 'upstream/develop' into feat/add-login-user-to-driver 2024-03-12 23:38:24 +01:00
David Arnold
c6a3403270 Merge remote-tracking branch 'origin/develop' into feat/add-login-user-to-driver 2024-03-02 13:16:54 +01:00
Gursheen Anand
0b36cbe307 fix: reset perpetual inventory flag after test 2024-02-29 13:04:01 +05:30
Gursheen Anand
8b3d46610e fix: parameters for PI references 2024-02-29 11:58:14 +05:30
Gursheen Anand
53642e7417 test: LCV entries after billing 2024-02-29 11:26:31 +05:30
Gursheen Anand
baa3fee1bf fix: add LCV flag to determine negative expenses 2024-02-29 09:04:24 +05:30
Nihantra C. Patel
3c9640df27 fix: print format bold for field "total" 2024-02-23 16:37:11 +05:30
David Arnold
b39f7b1c2f Merge remote-tracking branch 'origin/develop' into feat/add-login-user-to-driver 2024-01-31 21:11:03 +01:00
David Arnold
ff7e0eaba5 feat: add login user to driver if available for notifications 2024-01-30 10:31:17 +01:00
580 changed files with 273891 additions and 424721 deletions

View File

@@ -18,4 +18,4 @@ max_line_length = 110
[{*.json}]
insert_final_newline = false
indent_style = space
indent_size = 2
indent_size = 1

View File

@@ -30,11 +30,11 @@ branch_name="pot_${BASE_BRANCH}_${isodate}"
git checkout -b "${branch_name}"
echo "Commiting changes..."
git add .
git add erpnext/locale/main.pot
git commit -m "chore: update POT file"
gh auth setup-git
git push -u upstream "${branch_name}"
echo "Creating a PR..."
gh pr create --fill --base "${BASE_BRANCH}" --head "${branch_name}" -R frappe/erpnext
gh pr create --fill --base "${BASE_BRANCH}" --head "${branch_name}" --reviewer ${PR_REVIEWER} -R frappe/erpnext

View File

@@ -9,8 +9,8 @@ on:
workflow_dispatch:
jobs:
regeneratee-pot-file:
name: Release
regenerate-pot-file:
name: Regenerate POT file
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -36,3 +36,4 @@ jobs:
env:
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
BASE_BRANCH: ${{ matrix.branch }}
PR_REVIEWER: barredterra # change to your GitHub username if you copied this file

View File

@@ -29,7 +29,11 @@ jobs:
steps:
- name: Update notes
run: |
NEW_NOTES=$(gh api --method POST -H "Accept: application/vnd.github+json" /repos/frappe/erpnext/releases/generate-notes -f tag_name=$RELEASE_TAG | jq -r '.body' | sed -E '/^\* (chore|ci|test|docs|style)/d' )
NEW_NOTES=$(gh api --method POST -H "Accept: application/vnd.github+json" /repos/frappe/erpnext/releases/generate-notes -f tag_name=$RELEASE_TAG \
| jq -r '.body' \
| sed -E '/^\* (chore|ci|test|docs|style)/d' \
| sed -E 's/by @mergify //'
)
RELEASE_ID=$(gh api -H "Accept: application/vnd.github+json" /repos/frappe/erpnext/releases/tags/$RELEASE_TAG | jq -r '.id')
gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/frappe/erpnext/releases/$RELEASE_ID -f body="$NEW_NOTES"

5
.gitignore vendored
View File

@@ -14,5 +14,8 @@ __pycache__
*~
.idea/
.vscode/
.helix/
node_modules/
.backportrc.json
.backportrc.json
# Aider AI Chat
.aider*

View File

@@ -59,12 +59,14 @@ repos:
rev: v0.2.0
hooks:
- id: ruff
name: "Run ruff linter and apply fixes"
args: ["--fix"]
name: "Run ruff import sorter"
args: ["--select=I", "--fix"]
- id: ruff
name: "Run ruff linter"
- id: ruff-format
name: "Format Python code"
name: "Run ruff formatter"
ci:
autoupdate_schedule: weekly

View File

@@ -1 +1,3 @@
**/setup/setup_wizard/data/uom_data.json,erpnext.gettext.extractors.uom_data.extract
**/setup/doctype/incoterm/incoterms.csv,erpnext.gettext.extractors.incoterms.extract
**/setup/setup_wizard/data/*.txt,erpnext.gettext.extractors.lines_from_txt_file.extract
1 **/setup/setup_wizard/data/uom_data.json erpnext.gettext.extractors.uom_data.extract
2 **/setup/doctype/incoterm/incoterms.csv erpnext.gettext.extractors.incoterms.extract
3 **/setup/setup_wizard/data/*.txt erpnext.gettext.extractors.lines_from_txt_file.extract

View File

@@ -4,5 +4,7 @@ files:
pull_request_title: "fix: sync translations from crowdin"
pull_request_labels:
- translation
pull_request_reviewers:
- barredterra # change to your GitHub username if you copied this file
commit_message: "fix: %language% translations"
append_commit_message: false

View File

@@ -2,6 +2,7 @@ import functools
import inspect
import frappe
from frappe.utils.user import is_website_user
__version__ = "16.0.0-dev"
@@ -149,3 +150,13 @@ def allow_regional(fn):
return frappe.get_attr(overrides[function_path][-1])(*args, **kwargs)
return caller
def check_app_permission():
if frappe.session.user == "Administrator":
return True
if is_website_user():
return False
return True

View File

@@ -360,45 +360,45 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
)
if not amount:
return
gl_posting_date = end_date
prev_posting_date = None
# check if books nor frozen till endate:
if accounts_frozen_upto and getdate(end_date) <= getdate(accounts_frozen_upto):
gl_posting_date = get_last_day(add_days(accounts_frozen_upto, 1))
prev_posting_date = end_date
if via_journal_entry:
book_revenue_via_journal_entry(
doc,
credit_account,
debit_account,
amount,
base_amount,
gl_posting_date,
project,
account_currency,
item.cost_center,
item,
deferred_process,
submit_journal_entry,
)
else:
make_gl_entries(
doc,
credit_account,
debit_account,
against,
amount,
base_amount,
gl_posting_date,
project,
account_currency,
item.cost_center,
item,
deferred_process,
)
gl_posting_date = end_date
prev_posting_date = None
# check if books nor frozen till endate:
if accounts_frozen_upto and getdate(end_date) <= getdate(accounts_frozen_upto):
gl_posting_date = get_last_day(add_days(accounts_frozen_upto, 1))
prev_posting_date = end_date
if via_journal_entry:
book_revenue_via_journal_entry(
doc,
credit_account,
debit_account,
amount,
base_amount,
gl_posting_date,
project,
account_currency,
item.cost_center,
item,
deferred_process,
submit_journal_entry,
)
else:
make_gl_entries(
doc,
credit_account,
debit_account,
against,
amount,
base_amount,
gl_posting_date,
project,
account_currency,
item.cost_center,
item,
deferred_process,
)
# Returned in case of any errors because it tries to submit the same record again and again in case of errors
if frappe.flags.deferred_accounting_error:

View File

@@ -22,8 +22,7 @@ frappe.ui.form.on("Account", {
// hide fields if group
frm.toggle_display(["tax_rate"], cint(frm.doc.is_group) == 0);
// disable fields
frm.toggle_enable(["is_group", "company"], false);
frm.toggle_enable(["is_group", "company", "account_number"], frm.is_new());
if (cint(frm.doc.is_group) == 0) {
frm.toggle_display("freeze_account", frm.doc.__onload && frm.doc.__onload.can_freeze_account);

View File

@@ -55,8 +55,7 @@
"fieldtype": "Data",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Account Number",
"read_only": 1
"label": "Account Number"
},
{
"default": "0",
@@ -65,6 +64,8 @@
"label": "Is Group"
},
{
"fetch_from": "parent_account.company",
"fetch_if_empty": 1,
"fieldname": "company",
"fieldtype": "Link",
"in_standard_filter": 1,
@@ -72,7 +73,6 @@
"oldfieldname": "company",
"oldfieldtype": "Link",
"options": "Company",
"read_only": 1,
"remember_last_selected_value": 1,
"reqd": 1
},
@@ -124,7 +124,8 @@
"label": "Account Type",
"oldfieldname": "account_type",
"oldfieldtype": "Select",
"options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nCurrent Asset\nCurrent Liability\nDepreciation\nDirect Expense\nDirect Income\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nIndirect Expense\nIndirect Income\nLiability\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nService Received But Not Billed\nTax\nTemporary"
"options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nCurrent Asset\nCurrent Liability\nDepreciation\nDirect Expense\nDirect Income\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nIndirect Expense\nIndirect Income\nLiability\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nService Received But Not Billed\nTax\nTemporary",
"search_index": 1
},
{
"description": "Rate at which this tax is applied",
@@ -193,7 +194,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2024-03-27 13:05:55.866034",
"modified": "2024-06-27 16:23:04.444354",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",

View File

@@ -200,7 +200,7 @@ class Account(NestedSet):
msg = _(
"There are ledger entries against this account. Changing {0} to non-{1} in live system will cause incorrect output in 'Accounts {2}' report"
).format(
frappe.bold("Account Type"), doc_before_save.account_type, doc_before_save.account_type
frappe.bold(_("Account Type")), doc_before_save.account_type, doc_before_save.account_type
)
frappe.msgprint(msg)
self.add_comment("Comment", msg)

View File

@@ -222,7 +222,7 @@ frappe.treeview_settings["Account"] = {
"General Ledger",
"Balance Sheet",
"Profit and Loss Statement",
"Cash Flow Statement",
"Cash Flow",
"Accounts Payable",
"Accounts Receivable",
]) {

View File

@@ -1,531 +0,0 @@
{
"country_code": "tr",
"name": "Turkey - Tek D\u00fczen Hesap Plan\u0131",
"tree": {
"Duran Varl\u0131klar": {
"Di\u011fer Alacaklar": {
"Ba\u011fl\u0131 Ortakl\u0131klardan Alacaklar": {},
"Di\u011fer Alacak Senetleri Reeskontu(-)": {},
"Di\u011fer \u00c7e\u015fitli Alacaklar": {},
"Ortaklardan Alacaklar": {},
"Personelden Alacaklar": {},
"\u0130\u015ftiraklerden Alacaklar": {},
"\u015e\u00fcpheli Di\u011fer Alacaklar Kar\u015f\u0131l\u0131\u011f\u0131(-)": {}
},
"Di\u011fer Duran Varl\u0131klar": {
"Birikmi\u015f Amortismanlar(-)": {},
"Di\u011fer KDV": {},
"Di\u011fer \u00c7e\u015fitli Duran Varl\u0131klar": {},
"Elden \u00c7\u0131kar\u0131lacak Stoklar Ve Maddi Duran Varl\u0131klar": {},
"Gelecek Y\u0131llar \u0130htiyac\u0131 Stoklar": {},
"Gelecek Y\u0131llarda \u0130ndirilecek KDV": {},
"Pe\u015fin \u00d6denen Vergi Ve Fonlar": {},
"Stok De\u011fer D\u00fc\u015f\u00fckl\u00fc\u011f\u00fc Kar\u015f\u0131l\u0131\u011f\u0131(-)": {}
},
"Gelecek Y\u0131llara Ait Giderler ve Gelir Tahakkuklar\u0131": {
"Gelecek Y\u0131llara Ait Giderler": {},
"Gelir Tahakkuklar\u0131": {}
},
"Maddi Duran Varl\u0131klar": {
"Arazi Ve Arsalar": {},
"Binalar": {},
"Birikmi\u015f Amortismanlar(-)": {},
"Demirba\u015flar": {},
"Di\u011fer Maddi Duran Varl\u0131klar": {},
"Ta\u015f\u0131tlar": {},
"Tesis, Makine Ve Cihazlar": {},
"Verilen Avanslar": {},
"Yap\u0131lmakta Olan Yat\u0131r\u0131mlar": {},
"Yer Alt\u0131 Ve Yer \u00dcst\u00fc D\u00fczenleri": {}
},
"Maddi Olmayan Duran Varl\u0131klar": {
"Ara\u015ft\u0131rma Ve Geli\u015ftirme Giderleri": {},
"Birikmi\u015f Amortismanlar(-)": {},
"Di\u011fer Maddi Olmayan Duran Varl\u0131klar": {},
"Haklar": {},
"Kurulu\u015f Ve \u00d6rg\u00fctlenme Giderleri": {},
"Verilen Avanslar": {},
"\u00d6zel Maliyetler": {},
"\u015eerefiye": {}
},
"Mali Duran Varl\u0131klar": {
"Ba\u011fl\u0131 Menkul K\u0131ymetler": {},
"Ba\u011fl\u0131 Menkul K\u0131ymetler De\u011fer D\u00fc\u015f\u00fckl\u00fc\u011f\u00fc Kar\u015f\u0131l\u0131\u011f\u0131(-)": {},
"Ba\u011fl\u0131 Ortakl\u0131klar": {},
"Ba\u011fl\u0131 Ortakl\u0131klar Sermaye Paylar\u0131 De\u011fer D\u00fc\u015f\u00fckl\u00fc\u011f\u00fc Kar\u015f\u0131l\u0131\u011f\u0131(-)": {},
"Ba\u011fl\u0131 Ortakl\u0131klara Sermaye Taahh\u00fctleri(-)": {},
"Di\u011fer Mali Duran Varl\u0131klar": {},
"Di\u011fer Mali Duran Varl\u0131klar Kar\u015f\u0131l\u0131\u011f\u0131(-)": {},
"\u0130\u015ftirakler": {},
"\u0130\u015ftirakler Sermaye Paylar\u0131 De\u011fer D\u00fc\u015f\u00fckl\u00fc\u011f\u00fc Kar\u015f\u0131l\u0131\u011f\u0131(-)": {},
"\u0130\u015ftiraklere Sermaye Taahh\u00fctleri(-)": {}
},
"Ticari Alacaklar": {
"Alacak Senetleri": {},
"Alacak Senetleri Reeskontu(-)": {},
"Al\u0131c\u0131lar": {},
"Kazaqn\u0131lmam\u0131\u015f Finansal Kiralama Faiz Gelirleri(-)": {},
"Verilen Depozito Ve Teminatlar": {},
"\u015e\u00fcpheli Ticari Alacaklar Kar\u015f\u0131l\u0131\u011f\u0131(-)": {}
},
"root_type": "",
"\u00d6zel T\u00fckenmeye Tabi Varl\u0131klar": {
"Arama Giderleri": {},
"Birikmi\u015f T\u00fckenme Paylar\u0131(-)": {},
"Di\u011fer \u00d6zel T\u00fckenmeye Tabi Varl\u0131klar": {},
"Haz\u0131rl\u0131k Ve Geli\u015ftirme Giderleri": {},
"Verilen Avanslar": {}
}
},
"D\u00f6nen Varl\u0131klar": {
"Di\u011fer Alacaklar": {
"Ba\u011fl\u0131 Ortakl\u0131klardan Alacaklar": {},
"Di\u011fer Alacak Senetleri Reeskontu(-)": {},
"Di\u011fer \u00c7e\u015fitli Alacaklar": {},
"Ortaklardan Alacaklar": {},
"Personelden Alacaklar": {},
"\u0130\u015ftiraklerden Alacaklar": {},
"\u015e\u00fcpheli Di\u011fer Alacaklar": {},
"\u015e\u00fcpheli Di\u011fer Alacaklar Kar\u015f\u0131l\u0131\u011f\u0131(-)": {}
},
"Di\u011fer D\u00f6nen Varl\u0131klar": {
"Devreden KDV": {},
"Di\u011fer D\u00f6nen Varl\u0131klar Kar\u015f\u0131l\u0131\u011f\u0131(-)": {},
"Di\u011fer KDV": {},
"Di\u011fer \u00c7e\u015fitli D\u00f6nen Varl\u0131klar": {},
"Personel Avanslar\u0131": {},
"Pe\u015fin \u00d6denen Vergiler Ve Fonlar": {},
"Say\u0131m Ve Tesell\u00fcm Noksanlar\u0131": {},
"\u0130ndirilecek KDV": {},
"\u0130\u015f Avanslar\u0131": {}
},
"Gelecek Aylara Ait Giderler ve Gelir Tahakkuklar\u0131": {
"Gelecek Aylara Ait Giderler": {},
"Gelir Tahakkuklar\u0131": {}
},
"Haz\u0131r De\u011ferler": {
"Al\u0131nan \u00c7ekler": {},
"Bankalar": {
"account_type": "Bank"
},
"Di\u011fer Haz\u0131r De\u011ferler": {},
"Kasa": {
"account_type": "Cash"
},
"Verilen \u00c7ekler ve \u00d6deme Emirleri(-)": {}
},
"Menkul K\u0131ymetler": {
"Di\u011fer Menkul K\u0131ymetler": {},
"Hisse Senetleri": {},
"Kamu Kesimi Tahvil, Senet ve Bonolar\u0131": {},
"Menkul K\u0131ymetler De\u011fer D\u00fc\u015f\u00fckl\u00fc\u011f\u00fc Kar\u015f\u0131l\u0131\u011f\u0131(-)": {},
"\u00d6zel Kesim Tahvil Senet Ve Bonolar\u0131": {}
},
"Stoklar": {
"Mamuller": {},
"Stok De\u011fer D\u00fc\u015f\u00fckl\u00fc\u011f\u00fc Kar\u015f\u0131l\u0131\u011f\u0131(-)": {},
"Ticari Mallar": {},
"Verilen Sipari\u015f Avanslar\u0131": {},
"Yar\u0131 Mamuller": {},
"\u0130lk Madde Malzeme": {}
},
"Ticari Alacaklar": {
"Alacak Senetleri": {},
"Alacak Senetleri Reeskontu(-)": {},
"Al\u0131c\u0131lar": {},
"Di\u011fer Ticari Alacaklar": {},
"Kazan\u0131lmam\u0131\u015f Finansal Kiralama Faiz Gelirleri(-)": {},
"Verilen Depozito ve Teminatlar": {},
"\u015e\u00fcpheli Ticari Alacaklar": {},
"\u015e\u00fcpheli Ticari Alacaklar Kar\u015f\u0131l\u0131\u011f\u0131": {}
},
"Y\u0131llara Yayg\u0131n \u0130n\u015faat ve Onar\u0131m Maliyetleri": {
"Ta\u015feronlara Verilen Avanslar": {},
"Y\u0131llara Yayg\u0131n \u0130n\u015faat Ve Onar\u0131m Maliyetleri": {}
},
"root_type": ""
},
"Gelir Tablosu Hesaplar\u0131": {
"Br\u00fct Sat\u0131\u015flar": {
"Di\u011fer Gelirler": {},
"Yurt D\u0131\u015f\u0131 Sat\u0131\u015flar": {},
"Yurt \u0130\u00e7i Sat\u0131\u015flar": {}
},
"Di\u011fer Faaliyetlerden Olu\u015fan Gelir ve K\u00e2rlar": {
"Ba\u011fl\u0131 Ortakl\u0131klardan Temett\u00fc Gelirleri": {},
"Di\u011fer Ola\u011fan Gelir Ve K\u00e2rlar": {},
"Enflasyon D\u00fczeltme K\u00e2rlar\u0131": {},
"Faiz Gelirleri": {},
"Kambiyo K\u00e2rlar\u0131": {},
"Komisyon Gelirleri": {},
"Konusu Kalmayan Kar\u015f\u0131l\u0131klar": {},
"Menkul K\u0131ymet Sat\u0131\u015f K\u00e2rlar\u0131": {},
"Reeskont Faiz Gelirleri": {},
"\u0130\u015ftiraklerden Temett\u00fc Gelirleri": {}
},
"Di\u011fer Faaliyetlerden Olu\u015fan Gider ve Zararlar (-)": {
"Di\u011fer Ola\u011fan Gider Ve Zararlar(-)": {},
"Enflasyon D\u00fczeltmesi Zararlar\u0131(-)": {},
"Kambiyo Zararlar\u0131(-)": {},
"Kar\u015f\u0131l\u0131k Giderleri(-)": {},
"Komisyon Giderleri(-)": {},
"Menkul K\u0131ymet Sat\u0131\u015f Zararlar\u0131(-)": {},
"Reeskont Faiz Giderleri(-)": {}
},
"D\u00f6nem Net K\u00e2r\u0131 Ve Zarar\u0131": {
"D\u00f6nem K\u00e2r\u0131 Vergi Ve Di\u011fer Yasal Y\u00fck\u00fcml\u00fcl\u00fck Kar\u015f\u0131l\u0131klar\u0131(-)": {},
"D\u00f6nem K\u00e2r\u0131 Veya Zarar\u0131": {},
"D\u00f6nem Net K\u00e2r\u0131 Veya Zarar\u0131": {},
"Enflasyon D\u00fczeltme Hesab\u0131": {},
"Y\u0131llara Yayg\u0131n \u0130n\u015faat Ve Enflasyon D\u00fczeltme Hesab\u0131": {}
},
"Faaliyet Giderleri(-)": {
"Ara\u015ft\u0131rma Ve Geli\u015ftirme Giderleri(-)": {},
"Genel Y\u00f6netim Giderleri(-)": {},
"Pazarlama Sat\u0131\u015f Ve Da\u011f\u0131t\u0131m Giderleri(-)": {}
},
"Finansman Giderleri": {
"K\u0131sa Vadeli Bor\u00e7lanma Giderleri(-)": {},
"Uzun Vadeli Bor\u00e7lanma Giderleri(-)": {}
},
"Ola\u011fan D\u0131\u015f\u0131 Gelir Ve K\u00e2rlar": {
"Di\u011fer Ola\u011fan D\u0131\u015f\u0131 Gelir Ve K\u00e2rlar": {},
"\u00d6nceki D\u00f6nem Gelir Ve K\u00e2rlar\u0131": {}
},
"Ola\u011fan D\u0131\u015f\u0131 Gider Ve Zaralar(-)": {
"Di\u011fer Ola\u011fan D\u0131\u015f\u0131 Gider Ve Zararlar(-)": {},
"\u00c7al\u0131\u015fmayan K\u0131s\u0131m Gider Ve Zararlar\u0131(-)": {},
"\u00d6nceki D\u00f6nem Gider Ve Zararlar\u0131(-)": {}
},
"Sat\u0131\u015f \u0130ndirimleri (-)": {
"Di\u011fer \u0130ndirimler": {},
"Sat\u0131\u015f \u0130ndirimleri(-)": {},
"Sat\u0131\u015ftan \u0130adeler(-)": {}
},
"Sat\u0131\u015flar\u0131n Maliyeti(-)": {
"Di\u011fer Sat\u0131\u015flar\u0131n Maliyeti(-)": {},
"Sat\u0131lan Hizmet Maliyeti(-)": {},
"Sat\u0131lan Mamuller Maliyeti(-)": {},
"Sat\u0131lan Ticari Mallar Maliyeti(-)": {}
},
"root_type": ""
},
"K\u0131sa Vadeli Yabanc\u0131 Kaynaklar": {
"Al\u0131nan Avanslar": {
"Al\u0131nan Di\u011fer Avanslar": {
"account_type": "Payable"
},
"Al\u0131nan Sipari\u015f Avanslar\u0131": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"Bor\u00e7 ve Gider Kar\u015f\u0131l\u0131klar\u0131": {
"Di\u011fer Bor\u00e7 Ve Gider Kar\u015f\u0131l\u0131klar\u0131": {
"account_type": "Payable"
},
"D\u00f6nem K\u00e2r\u0131 Vergi Ve Di\u011fer Yasal Y\u00fck\u00fcml\u00fcl\u00fck Kar\u015f\u0131l\u0131klar\u0131": {
"account_type": "Tax"
},
"D\u00f6nem K\u00e2r\u0131n\u0131n Pe\u015fin \u00d6denen Vergi Ve Di\u011fer Y\u00fck\u00fcml\u00fcl\u00fckler(-)": {
"account_type": "Tax"
},
"K\u0131dem Tazminat\u0131 Kar\u015f\u0131l\u0131\u011f\u0131": {},
"Maliyet Giderleri Kar\u015f\u0131l\u0131\u011f\u0131": {},
"account_type": "Payable"
},
"Di\u011fer Bor\u00e7lar": {
"Ba\u011fl\u0131 Ortakl\u0131klara Bor\u00e7lar": {
"account_type": "Payable"
},
"Di\u011fer Bor\u00e7 Senetleri Reeskontu(-)": {
"account_type": "Payable"
},
"Di\u011fer \u00c7e\u015fitli Bor\u00e7lar": {
"account_type": "Payable"
},
"Ortaklara Bor\u00e7lar": {
"account_type": "Payable"
},
"Personele Bor\u00e7lar": {
"account_type": "Payable"
},
"account_type": "Payable",
"\u0130\u015ftiraklere Bor\u00e7lar": {
"account_type": "Payable"
}
},
"Di\u011fer K\u0131sa Vadeli Yabanc\u0131 Kaynaklar": {
"Di\u011fer KDV": {
"account_type": "Tax"
},
"Di\u011fer \u00c7e\u015fitli Yabanc\u0131 Kaynaklar": {},
"Hesaplanan KDV": {
"account_type": "Tax"
},
"Merkez Ve \u015eubeler Cari Hesab\u0131": {},
"Say\u0131m Ve Tesell\u00fcm Fazlalar\u0131": {},
"account_type": "Payable"
},
"Gelecek Aylara Ait Gelirler Ve Gider Tahakkuklar\u0131": {
"Gelecek Aylara Ait Gelirler": {},
"Gider Tahakkuklar\u0131": {}
},
"Mali Bor\u00e7lar": {
"Banka Kredileri": {
"account_type": "Payable"
},
"Di\u011fer Mali Bor\u00e7lar": {
"account_type": "Payable"
},
"Ertelenmi\u015f Finansal Kiralama Bor\u00e7lanma Maliyetleri(-)": {
"account_type": "Payable"
},
"Finansal Kiralama \u0130\u015flemlerinden Bor\u00e7lar": {
"account_type": "Payable"
},
"Menkul K\u0131ymetler \u0130hra\u00e7 Fark\u0131(-)": {
"account_type": "Payable"
},
"Tahvil Anapara Bor\u00e7, Taksit Ve Faizleri": {
"account_type": "Payable"
},
"Uzun Vadeli Kredilerin Anapara Taksitleri Ve Faizleri": {
"account_type": "Payable"
},
"account_type": "Payable",
"\u00c7\u0131kar\u0131lan Bonolar Ve Senetler": {
"account_type": "Payable"
},
"\u00c7\u0131kar\u0131lm\u0131\u015f Di\u011fer Menkul K\u0131ymetler": {
"account_type": "Payable"
}
},
"Ticari Bor\u00e7lar": {
"Al\u0131nan Depozito Ve Teminatlar": {
"account_type": "Payable"
},
"Bor\u00e7 Senetleri": {
"account_type": "Payable"
},
"Bor\u00e7 Senetleri Reeskontu(-)": {
"account_type": "Payable"
},
"Di\u011fer Ticari Bor\u00e7lar": {
"account_type": "Payable"
},
"Sat\u0131c\u0131lar": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"Y\u0131llara Yayg\u0131n \u0130n\u015faat Ve Onar\u0131m Hakedi\u015fleri": {
"350 Y\u0131llara Yayg\u0131n \u0130n\u015faat Ve Onar\u0131m Hakedi\u015fleri Bedelleri": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"root_type": "",
"\u00d6denecek Vergi ve Di\u011fer Y\u00fck\u00fcml\u00fcl\u00fckler": {
"Vadesi Ge\u00e7mi\u015f, Ertelenmi\u015f Veya Taksitlendirilmi\u015f Vergi Ve Di\u011fer Y\u00fck\u00fcml\u00fcl\u00fckler": {
"account_type": "Tax"
},
"account_type": "Tax",
"\u00d6denecek Di\u011fer Y\u00fck\u00fcml\u00fcl\u00fckler": {
"account_type": "Tax"
},
"\u00d6denecek Sosyal G\u00fcvenl\u00fck Kesintileri": {
"account_type": "Tax"
},
"\u00d6denecek Vergi Ve Fonlar": {
"account_type": "Tax"
}
}
},
"Maliyet Hesaplar\u0131": {
"Ara\u015ft\u0131rma Ve Geli\u015ftirme Giderleri": {},
"Direkt \u0130lk Madde Ve Malzeme Giderleri": {
"Direk \u0130lk Madde Ve Malzeme Giderleri Hesab\u0131": {},
"Direkt \u0130lk Madde Ve Malzeme Fiyat Fark\u0131": {},
"Direkt \u0130lk Madde Ve Malzeme Miktar Fark\u0131": {},
"Direkt \u0130lk Madde Ve Malzeme Yans\u0131tma Hesab\u0131": {}
},
"Direkt \u0130\u015f\u00e7ilik Giderleri": {
"Direkt \u0130\u015f\u00e7ilik Giderleri": {},
"Direkt \u0130\u015f\u00e7ilik Giderleri Yans\u0131tma Hesab\u0131": {},
"Direkt \u0130\u015f\u00e7ilik S\u00fcre Farklar\u0131": {},
"Direkt \u0130\u015f\u00e7ilik \u00dccret Farklar\u0131": {}
},
"Finansman Giderleri": {
"Finansman Giderleri": {},
"Finansman Giderleri Fark Hesab\u0131": {},
"Finansman Giderleri Yans\u0131tma Hesab\u0131": {}
},
"Genel Y\u00f6netim Giderleri": {
"Genel Y\u00f6netim Gider Farklar\u0131 Hesab\u0131": {},
"Genel Y\u00f6netim Giderleri": {},
"Genel Y\u00f6netim Giderleri Yans\u0131tma Hesab\u0131": {}
},
"Genel \u00dcretim Giderleri": {
"Genel \u00dcretim Giderleri": {},
"Genel \u00dcretim Giderleri B\u00fct\u00e7e Farklar\u0131": {},
"Genel \u00dcretim Giderleri Kapasite Farklar\u0131": {},
"Genel \u00dcretim Giderleri Verimlilik Giderleri": {},
"Genel \u00dcretim Giderleri Yans\u0131tma Hesab\u0131": {}
},
"Hizmet \u00dcretim Maliyeti": {
"Hizmet \u00dcretim Maliyeti": {},
"Hizmet \u00dcretim Maliyeti Fark Hesaplar\u0131": {},
"Hizmet \u00dcretim Maliyeti Yans\u0131tma Hesab\u0131": {}
},
"Maliyet Muhasebesi Ba\u011flant\u0131 Hesaplar\u0131": {
"Maliyet Muhasebesi Ba\u011flant\u0131 Hesab\u0131": {},
"Maliyet Muhasebesi Yans\u0131tma Hesab\u0131": {}
},
"Pazarlama, Sat\u0131\u015f Ve Da\u011f\u0131t\u0131m Giderleri": {
"Atra\u015ft\u0131rma Ve Geli\u015ftirme Giderleri": {},
"Pazarlama Sat\u0131\u015f Ve Dag\u0131t\u0131m Giderleri Yans\u0131tma Hesab\u0131": {},
"Pazarlama Sat\u0131\u015f Ve Da\u011f\u0131t\u0131m Giderleri Fark Hesab\u0131": {}
},
"root_type": ""
},
"Naz\u0131m Hesaplar": {
"root_type": ""
},
"Serbest Hesaplar": {
"root_type": ""
},
"Uzun Vadeli Yabanc\u0131 Kaynaklar": {
"Al\u0131nan Avanslar": {
"Al\u0131nan Di\u011fer Avanslar": {
"account_type": "Payable"
},
"Al\u0131nan Sipari\u015f Avanslar\u0131": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"Bor\u00e7 Ve Gider Kar\u015f\u0131l\u0131klar\u0131": {
"Di\u011fer Bor\u00e7 Ve Gider Kar\u015f\u0131l\u0131klar\u0131": {
"account_type": "Payable"
},
"K\u0131dem Tazminat\u0131 Kar\u015f\u0131l\u0131\u011f\u0131": {},
"account_type": "Payable"
},
"Di\u011fer Bor\u00e7lar": {
"Ba\u011fl\u0131 Ortakl\u0131klara Bor\u00e7lar": {
"account_type": "Payable"
},
"Di\u011fer Bor\u00e7 Senetleri Reeskontu(-)": {
"account_type": "Payable"
},
"Di\u011fer \u00c7e\u015fitli Bor\u00e7lar": {
"account_type": "Payable"
},
"Kamuya Olan Ertelenmi\u015f Veya Taksitlendirilmi\u015f Bor\u00e7lar": {
"account_type": "Payable"
},
"Ortaklara Bor\u00e7lar": {
"account_type": "Payable"
},
"account_type": "Payable",
"\u0130\u015ftiraklere Bor\u00e7lar": {
"account_type": "Payable"
}
},
"Di\u011fer Uzun Vadeli Yabanc\u0131 Kaynaklar": {
"Di\u011fer \u00c7e\u015fitli Uzun Vadeli Yabanc\u0131 Kaynaklar": {
"account_type": "Payable"
},
"Gelecek Y\u0131llara Ertelenmi\u015f Veya Terkin Edilecek KDV": {
"account_type": "Payable"
},
"Tesise Kat\u0131lma Paylar\u0131": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"Gelecek Y\u0131llara Ait Gelirler Ve Gider Tahakkuklar\u0131": {
"Gelecek Y\u0131llara Ait Gelirler": {},
"Gider Tahakkuklar\u0131": {}
},
"Mali Bor\u00e7lar": {
"Banka Kredileri": {
"account_type": "Payable"
},
"Di\u011fer Mali Bor\u00e7lar": {
"account_type": "Payable"
},
"Ertelenmi\u015f Finansal Kiralama Bor\u00e7lanma Maliyetleri(-)": {
"account_type": "Payable"
},
"Finansal Kiralama \u0130\u015flemlerinden Bor\u00e7lar": {
"account_type": "Payable"
},
"Menkul K\u0131ymetler \u0130hra\u00e7 Fark\u0131(-)": {
"account_type": "Payable"
},
"account_type": "Payable",
"\u00c7\u0131kar\u0131lm\u0131\u015f Di\u011fer Menkul K\u0131ymetler": {
"account_type": "Payable"
},
"\u00c7\u0131kar\u0131lm\u0131\u015f Tahviller": {
"account_type": "Payable"
}
},
"Ticari Bor\u00e7lar": {
"Al\u0131nan Depozito Ve Teminatlar": {
"account_type": "Payable"
},
"Bor\u00e7 Senetleri": {
"account_type": "Payable"
},
"Bor\u00e7 Senetleri Reeskontu(-)": {
"account_type": "Payable"
},
"Di\u011fer Ticari Bor\u00e7lar": {
"account_type": "Payable"
},
"Sat\u0131c\u0131lar": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"root_type": ""
},
"\u00d6z Kaynaklar": {
"D\u00f6nem Net K\u00e2r\u0131 (Zarar\u0131)": {
"D\u00f6nem Net K\u00e2r\u0131": {},
"D\u00f6nem Net Zarar\u0131(-)": {}
},
"Ge\u00e7mi\u015f Y\u0131llar K\u00e2rlar\u0131": {
"Ge\u00e7mi\u015f Y\u0131llar K\u00e2rlar\u0131": {}
},
"Ge\u00e7mi\u015f Y\u0131llar Zararlar\u0131(-)": {
"Ge\u00e7mi\u015f Y\u0131llar Zararlar\u0131(-)": {}
},
"K\u00e2r Yedekleri": {
"Di\u011fer K\u00e2r Yedekleri": {},
"Ola\u011fan\u00fcst\u00fc Yedekler": {},
"Stat\u00fc Yedekleri": {},
"Yasal Yedekler": {},
"\u00d6zel Fonlar": {}
},
"Sermaye Yedekleri": {
"Di\u011fer Sermaye Yedekleri": {},
"Hisse Senedi \u0130ptal K\u00e2rlar\u0131": {},
"Hisse Senetleri \u0130hra\u00e7 Primleri": {},
"Maddi Duran Varl\u0131k Yeniden De\u011ferlenme Art\u0131\u015flar\u0131": {},
"Maliyet Art\u0131\u015flar\u0131 Fonu": {},
"\u0130\u015ftirakler Yeniden De\u011ferleme Art\u0131\u015flar\u0131": {}
},
"root_type": "",
"\u00d6denmi\u015f Sermaye": {
"Sermaye": {},
"\u00d6denmi\u015f Sermaye(-)": {
"account_type": "Payable"
}
}
}
}
}

View File

@@ -1525,7 +1525,8 @@
"41-Clients et comptes rattach\u00e9s (PASSIF)": {
"Clients cr\u00e9diteurs": {
"Clients - Avances et acomptes re\u00e7us sur commandes": {
"account_number": "4191"
"account_number": "4191",
"account_type": "Income Account"
},
"Clients - Dettes pour emballages et mat\u00e9riels consign\u00e9s": {
"account_number": "4196"
@@ -3141,4 +3142,4 @@
"account_number": "7"
}
}
}
}

View File

@@ -3,4 +3,23 @@
frappe.ui.form.on("Accounts Settings", {
refresh: function (frm) {},
enable_immutable_ledger: function (frm) {
if (!frm.doc.enable_immutable_ledger) {
return;
}
let msg = __("Enabling this will change the way how cancelled transactions are handled.");
msg += " ";
msg += __("Please enable only if the understand the effects of enabling this.");
msg += "<br>";
msg += "Do you still want to enable immutable ledger?";
frappe.confirm(
msg,
() => {},
() => {
frm.set_value("enable_immutable_ledger", 0);
}
);
},
});

View File

@@ -12,6 +12,7 @@
"unlink_advance_payment_on_cancelation_of_order",
"column_break_13",
"delete_linked_ledger_entries",
"enable_immutable_ledger",
"invoicing_features_section",
"check_supplier_invoice_uniqueness",
"automatically_fetch_payment_terms",
@@ -54,6 +55,8 @@
"post_change_gl_entries",
"assets_tab",
"asset_settings_section",
"calculate_depr_using_total_days",
"column_break_gjcc",
"book_asset_depreciation_entry_automatically",
"closing_settings_tab",
"period_closing_settings_section",
@@ -70,7 +73,9 @@
"remarks_section",
"general_ledger_remarks_length",
"column_break_lvjk",
"receivable_payable_remarks_length"
"receivable_payable_remarks_length",
"payment_request_settings",
"create_pr_in_draft_status"
],
"fields": [
{
@@ -105,7 +110,7 @@
},
{
"default": "0",
"description": "Enabling ensure each Purchase Invoice has a unique value in Supplier Invoice No. field",
"description": "Enabling this ensures each Purchase Invoice has a unique value in Supplier Invoice No. field within a particular fiscal year",
"fieldname": "check_supplier_invoice_uniqueness",
"fieldtype": "Check",
"label": "Check Supplier Invoice Number Uniqueness"
@@ -454,6 +459,36 @@
"fieldname": "remarks_section",
"fieldtype": "Section Break",
"label": "Remarks Column Length"
},
{
"default": "0",
"description": "On enabling this cancellation entries will be posted on the actual cancellation date and reports will consider cancelled entries as well",
"fieldname": "enable_immutable_ledger",
"fieldtype": "Check",
"label": "Enable Immutable Ledger"
},
{
"fieldname": "column_break_gjcc",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "Enable this option to calculate daily depreciation by considering the total number of days in the entire depreciation period, (including leap years) while using daily pro-rata based depreciation",
"fieldname": "calculate_depr_using_total_days",
"fieldtype": "Check",
"label": "Calculate daily depreciation using total days in depreciation period"
},
{
"description": "Payment Request created from Sales Order or Purchase Order will be in Draft status. When disabled document will be in unsaved state.",
"fieldname": "payment_request_settings",
"fieldtype": "Tab Break",
"label": "Payment Request"
},
{
"default": "1",
"fieldname": "create_pr_in_draft_status",
"fieldtype": "Check",
"label": "Create in Draft Status"
}
],
"icon": "icon-cog",
@@ -461,7 +496,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2024-03-27 13:05:57.568638",
"modified": "2024-07-26 06:48:52.714630",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -33,12 +33,15 @@ class AccountsSettings(Document):
book_deferred_entries_based_on: DF.Literal["Days", "Months"]
book_deferred_entries_via_journal_entry: DF.Check
book_tax_discount_loss: DF.Check
calculate_depr_using_total_days: DF.Check
check_supplier_invoice_uniqueness: DF.Check
create_pr_in_draft_status: DF.Check
credit_controller: DF.Link | None
delete_linked_ledger_entries: DF.Check
determine_address_tax_category_from: DF.Literal["Billing Address", "Shipping Address"]
enable_common_party_accounting: DF.Check
enable_fuzzy_matching: DF.Check
enable_immutable_ledger: DF.Check
enable_party_matching: DF.Check
frozen_accounts_modifier: DF.Link | None
general_ledger_remarks_length: DF.Int

View File

@@ -38,6 +38,11 @@ frappe.ui.form.on("Bank Clearance", {
frm.add_custom_button(__("Get Payment Entries"), () => frm.trigger("get_payment_entries"));
frm.change_custom_button_type(__("Get Payment Entries"), null, "primary");
if (frm.doc.payment_entries.length) {
frm.add_custom_button(__("Update Clearance Date"), () => frm.trigger("update_clearance_date"));
frm.change_custom_button_type(__("Get Payment Entries"), null, "default");
frm.change_custom_button_type(__("Update Clearance Date"), null, "primary");
}
},
update_clearance_date: function (frm) {
@@ -45,13 +50,7 @@ frappe.ui.form.on("Bank Clearance", {
method: "update_clearance_date",
doc: frm.doc,
callback: function (r, rt) {
frm.refresh_field("payment_entries");
frm.refresh_fields();
if (!frm.doc.payment_entries.length) {
frm.change_custom_button_type(__("Get Payment Entries"), null, "primary");
frm.change_custom_button_type(__("Update Clearance Date"), null, "default");
}
frm.refresh();
},
});
},
@@ -60,17 +59,8 @@ frappe.ui.form.on("Bank Clearance", {
return frappe.call({
method: "get_payment_entries",
doc: frm.doc,
callback: function (r, rt) {
frm.refresh_field("payment_entries");
if (frm.doc.payment_entries.length) {
frm.add_custom_button(__("Update Clearance Date"), () =>
frm.trigger("update_clearance_date")
);
frm.change_custom_button_type(__("Get Payment Entries"), null, "default");
frm.change_custom_button_type(__("Update Clearance Date"), null, "primary");
}
callback: function () {
frm.refresh();
},
});
},

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, getdate
from frappe.utils import flt, fmt_money, get_link_to_form, getdate
from pypika import Order
import erpnext
@@ -96,8 +96,11 @@ class BankClearance(Document):
if d.cheque_date and getdate(d.clearance_date) < getdate(d.cheque_date):
frappe.throw(
_("Row #{0}: Clearance date {1} cannot be before Cheque Date {2}").format(
d.idx, d.clearance_date, d.cheque_date
_("Row #{0}: For {1} Clearance date {2} cannot be before Cheque Date {3}").format(
d.idx,
get_link_to_form(d.payment_document, d.payment_entry),
d.clearance_date,
d.cheque_date,
)
)

View File

@@ -59,6 +59,10 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
);
frm.add_custom_button(__("Auto Reconcile"), function () {
if (!frm.doc.bank_account) {
frappe.msgprint(__("Please select Bank Account"));
return;
}
frappe.call({
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers",
args: {

View File

@@ -26,6 +26,7 @@
{
"fieldname": "company",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Company",
"options": "Company"
},
@@ -118,7 +119,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2024-03-27 13:06:37.922473",
"modified": "2024-04-28 14:40:50.910884",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Reconciliation Tool",

View File

@@ -495,12 +495,12 @@ def check_matching(
bank_account,
company,
transaction,
document_types,
from_date,
to_date,
filter_by_reference_date,
from_reference_date,
to_reference_date,
document_types=None,
from_date=None,
to_date=None,
filter_by_reference_date=None,
from_reference_date=None,
to_reference_date=None,
):
exact_match = True if "exact_match" in document_types else False
@@ -540,14 +540,14 @@ def get_queries(
bank_account,
company,
transaction,
document_types,
from_date,
to_date,
filter_by_reference_date,
from_reference_date,
to_reference_date,
exact_match,
common_filters,
document_types=None,
from_date=None,
to_date=None,
filter_by_reference_date=None,
from_reference_date=None,
to_reference_date=None,
exact_match=None,
common_filters=None,
):
# get queries to get matching vouchers
account_from_to = "paid_to" if transaction.deposit > 0.0 else "paid_from"
@@ -580,15 +580,15 @@ def get_matching_queries(
bank_account,
company,
transaction,
document_types,
exact_match,
account_from_to,
from_date,
to_date,
filter_by_reference_date,
from_reference_date,
to_reference_date,
common_filters,
document_types=None,
exact_match=None,
account_from_to=None,
from_date=None,
to_date=None,
filter_by_reference_date=None,
from_reference_date=None,
to_reference_date=None,
common_filters=None,
):
queries = []
currency = get_account_currency(bank_account)
@@ -719,7 +719,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,
pe.paid_amount_after_tax.as_("paid_amount"),
pe.reference_no,
pe.reference_date,
pe.party,

View File

@@ -130,52 +130,66 @@ frappe.ui.form.on("Bank Statement Import", {
},
show_import_status(frm) {
let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
let successful_records = import_log.filter((log) => log.success);
let failed_records = import_log.filter((log) => !log.success);
if (successful_records.length === 0) return;
if (frm.doc.status == "Pending") return;
let message;
if (failed_records.length === 0) {
let message_args = [successful_records.length];
if (frm.doc.import_type === "Insert New Records") {
message =
successful_records.length > 1
? __("Successfully imported {0} records.", message_args)
: __("Successfully imported {0} record.", message_args);
} else {
message =
successful_records.length > 1
? __("Successfully updated {0} records.", message_args)
: __("Successfully updated {0} record.", message_args);
}
} else {
let message_args = [successful_records.length, import_log.length];
if (frm.doc.import_type === "Insert New Records") {
message =
successful_records.length > 1
? __(
"Successfully imported {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args
)
: __(
"Successfully imported {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args
);
} else {
message =
successful_records.length > 1
? __(
"Successfully updated {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args
)
: __(
"Successfully updated {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args
);
}
}
frm.dashboard.set_headline(message);
frappe.call({
method: "erpnext.accounts.doctype.bank_statement_import.bank_statement_import.get_import_status",
args: {
docname: frm.doc.name,
},
callback: function (r) {
let successful_records = cint(r.message.success);
let failed_records = cint(r.message.failed);
let total_records = cint(r.message.total_records);
if (!total_records) {
return;
}
let message;
if (failed_records === 0) {
let message_args = [successful_records];
if (frm.doc.import_type === "Insert New Records") {
message =
successful_records > 1
? __("Successfully imported {0} records.", message_args)
: __("Successfully imported {0} record.", message_args);
} else {
message =
successful_records > 1
? __("Successfully updated {0} records.", message_args)
: __("Successfully updated {0} record.", message_args);
}
} else {
let message_args = [successful_records, total_records];
if (frm.doc.import_type === "Insert New Records") {
message =
successful_records > 1
? __(
"Successfully imported {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args
)
: __(
"Successfully imported {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args
);
} else {
message =
successful_records > 1
? __(
"Successfully updated {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args
)
: __(
"Successfully updated {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
message_args
);
}
}
frm.dashboard.set_headline(message);
},
});
},
show_report_error_button(frm) {
@@ -297,7 +311,7 @@ frappe.ui.form.on("Bank Statement Import", {
// method: 'frappe.core.doctype.data_import.data_import.get_preview_from_template',
show_import_preview(frm, preview_data) {
let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
let import_log = preview_data.import_log;
if (frm.import_preview && frm.import_preview.doctype === frm.doc.reference_doctype) {
frm.import_preview.preview_data = preview_data;
@@ -336,6 +350,15 @@ frappe.ui.form.on("Bank Statement Import", {
);
},
export_import_log(frm) {
open_url_post(
"/api/method/erpnext.accounts.doctype.bank_statement_import.bank_statement_import.download_import_log",
{
data_import_name: frm.doc.name,
}
);
},
show_import_warnings(frm, preview_data) {
let columns = preview_data.columns;
let warnings = JSON.parse(frm.doc.template_warnings || "[]");
@@ -411,49 +434,50 @@ frappe.ui.form.on("Bank Statement Import", {
frm.trigger("show_import_log");
},
show_import_log(frm) {
let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
let logs = import_log;
frm.toggle_display("import_log", false);
frm.toggle_display("import_log_section", logs.length > 0);
render_import_log(frm) {
frappe.call({
method: "erpnext.accounts.doctype.bank_statement_import.bank_statement_import.get_import_logs",
args: {
docname: frm.doc.name,
},
callback: function (r) {
let logs = r.message;
if (logs.length === 0) {
frm.get_field("import_log_preview").$wrapper.empty();
return;
}
if (logs.length === 0) return;
let rows = logs
.map((log) => {
let html = "";
if (log.success) {
if (frm.doc.import_type === "Insert New Records") {
html = __("Successfully imported {0}", [
`<span class="underline">${frappe.utils.get_form_link(
frm.doc.reference_doctype,
log.docname,
true
)}<span>`,
]);
} else {
html = __("Successfully updated {0}", [
`<span class="underline">${frappe.utils.get_form_link(
frm.doc.reference_doctype,
log.docname,
true
)}<span>`,
]);
}
} else {
let messages = log.messages
.map(JSON.parse)
.map((m) => {
let title = m.title ? `<strong>${m.title}</strong>` : "";
let message = m.message ? `<div>${m.message}</div>` : "";
return title + message;
})
.join("");
let id = frappe.dom.get_unique_id();
html = `${messages}
frm.toggle_display("import_log_section", true);
let rows = logs
.map((log) => {
let html = "";
if (log.success) {
if (frm.doc.import_type === "Insert New Records") {
html = __("Successfully imported {0}", [
`<span class="underline">${frappe.utils.get_form_link(
frm.doc.reference_doctype,
log.docname,
true
)}<span>`,
]);
} else {
html = __("Successfully updated {0}", [
`<span class="underline">${frappe.utils.get_form_link(
frm.doc.reference_doctype,
log.docname,
true
)}<span>`,
]);
}
} else {
let messages = JSON.parse(log.messages || "[]")
.map((m) => {
let title = m.title ? `<strong>${m.title}</strong>` : "";
let message = m.message ? `<div>${m.message}</div>` : "";
return title + message;
})
.join("");
let id = frappe.dom.get_unique_id();
html = `${messages}
<button class="btn btn-default btn-xs" type="button" data-toggle="collapse" data-target="#${id}" aria-expanded="false" aria-controls="${id}" style="margin-top: 15px;">
${__("Show Traceback")}
</button>
@@ -462,16 +486,16 @@ frappe.ui.form.on("Bank Statement Import", {
<pre>${log.exception}</pre>
</div>
</div>`;
}
let indicator_color = log.success ? "green" : "red";
let title = log.success ? __("Success") : __("Failure");
}
let indicator_color = log.success ? "green" : "red";
let title = log.success ? __("Success") : __("Failure");
if (frm.doc.show_failed_logs && log.success) {
return "";
}
if (frm.doc.show_failed_logs && log.success) {
return "";
}
return `<tr>
<td>${log.row_indexes.join(", ")}</td>
return `<tr>
<td>${JSON.parse(log.row_indexes).join(", ")}</td>
<td>
<div class="indicator ${indicator_color}">${title}</div>
</td>
@@ -479,16 +503,16 @@ frappe.ui.form.on("Bank Statement Import", {
${html}
</td>
</tr>`;
})
.join("");
})
.join("");
if (!rows && frm.doc.show_failed_logs) {
rows = `<tr><td class="text-center text-muted" colspan=3>
if (!rows && frm.doc.show_failed_logs) {
rows = `<tr><td class="text-center text-muted" colspan=3>
${__("No failed logs")}
</td></tr>`;
}
}
frm.get_field("import_log_preview").$wrapper.html(`
frm.get_field("import_log_preview").$wrapper.html(`
<table class="table table-bordered">
<tr class="text-muted">
<th width="10%">${__("Row Number")}</th>
@@ -498,5 +522,34 @@ frappe.ui.form.on("Bank Statement Import", {
${rows}
</table>
`);
},
});
},
show_import_log(frm) {
frm.toggle_display("import_log_section", false);
if (frm.is_new() || frm.import_in_progress) {
return;
}
frappe.call({
method: "frappe.client.get_count",
args: {
doctype: "Data Import Log",
filters: {
data_import: frm.doc.name,
},
},
callback: function (r) {
let count = r.message;
if (count < 5000) {
frm.trigger("render_import_log");
} else {
frm.toggle_display("import_log_section", false);
frm.add_custom_button(__("Export Import Log"), () => frm.trigger("export_import_log"));
}
},
});
},
});

View File

@@ -11,6 +11,8 @@
"bank_account",
"bank",
"column_break_4",
"custom_delimiters",
"delimiter_options",
"google_sheets_url",
"refresh_google_sheet",
"html_5",
@@ -24,7 +26,6 @@
"section_import_preview",
"import_preview",
"import_log_section",
"statement_import_log",
"show_failed_logs",
"import_log_preview",
"reference_doctype",
@@ -194,15 +195,23 @@
"fieldtype": "Column Break"
},
{
"fieldname": "statement_import_log",
"fieldtype": "Code",
"label": "Statement Import Log",
"options": "JSON"
"default": "0",
"fieldname": "custom_delimiters",
"fieldtype": "Check",
"label": "Custom delimiters"
},
{
"default": ",;\\t|",
"depends_on": "custom_delimiters",
"description": "If your CSV uses a different delimiter, add that character here, ensuring no spaces or additional characters are included.",
"fieldname": "delimiter_options",
"fieldtype": "Data",
"label": "Delimiter options"
}
],
"hide_toolbar": 1,
"links": [],
"modified": "2024-03-27 13:06:38.098765",
"modified": "2024-06-25 17:32:07.658250",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Statement Import",

View File

@@ -31,13 +31,14 @@ class BankStatementImport(DataImport):
bank: DF.Link | None
bank_account: DF.Link
company: DF.Link
custom_delimiters: DF.Check
delimiter_options: DF.Data | None
google_sheets_url: DF.Data | None
import_file: DF.Attach | None
import_type: DF.Literal["", "Insert New Records", "Update Existing Records"]
mute_emails: DF.Check
reference_doctype: DF.Link
show_failed_logs: DF.Check
statement_import_log: DF.Code | None
status: DF.Literal["Pending", "Success", "Partial Success", "Error"]
submit_after_import: DF.Check
template_options: DF.Code | None
@@ -121,6 +122,11 @@ def download_errored_template(data_import_name):
data_import.export_errored_rows()
@frappe.whitelist()
def download_import_log(data_import_name):
return frappe.get_doc("Bank Statement Import", data_import_name).download_import_log()
def parse_data_from_template(raw_data):
data = []
@@ -242,6 +248,47 @@ def write_xlsx(data, sheet_name, wb=None, column_widths=None, file_path=None):
return True
@frappe.whitelist()
def get_import_status(docname):
import_status = {}
data_import = frappe.get_doc("Bank Statement Import", docname)
import_status["status"] = data_import.status
logs = frappe.get_all(
"Data Import Log",
fields=["count(*) as count", "success"],
filters={"data_import": docname},
group_by="success",
)
total_payload_count = 0
for log in logs:
total_payload_count += log.get("count", 0)
if log.get("success"):
import_status["success"] = log.get("count")
else:
import_status["failed"] = log.get("count")
import_status["total_records"] = total_payload_count
return import_status
@frappe.whitelist()
def get_import_logs(docname: str):
frappe.has_permission("Bank Statement Import")
return frappe.get_all(
"Data Import Log",
fields=["success", "docname", "messages", "exception", "row_indexes"],
filters={"data_import": docname},
limit_page_length=5000,
order_by="log_index",
)
@frappe.whitelist()
def upload_bank_statement(**args):
args = frappe._dict(args)

View File

@@ -68,6 +68,9 @@ class AutoMatchbyAccountIBAN:
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,

View File

@@ -47,9 +47,11 @@ def validate_columns(data):
no_of_columns = max([len(d) for d in data])
if no_of_columns > 8:
if no_of_columns != 8:
frappe.throw(
_("More columns found than expected. Please compare the uploaded file with standard template"),
_(
"Columns are not according to template. Please compare the uploaded file with standard template"
),
title=(_("Wrong Template")),
)

View File

@@ -4,7 +4,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import add_days, format_date, getdate
from frappe.utils import add_days, flt, format_date, getdate
class MainCostCenterCantBeChild(frappe.ValidationError):
@@ -60,7 +60,7 @@ class CostCenterAllocation(Document):
self.validate_child_cost_centers()
def validate_total_allocation_percentage(self):
total_percentage = sum([d.percentage for d in self.get("allocation_percentages", [])])
total_percentage = sum([flt(d.percentage) for d in self.get("allocation_percentages", [])])
if total_percentage != 100:
frappe.throw(_("Total percentage against cost centers should be 100"), WrongPercentageAllocation)

View File

@@ -13,6 +13,7 @@
"customer",
"column_break_4",
"coupon_code",
"from_external_ecomm_platform",
"pricing_rule",
"uses",
"valid_from",
@@ -61,11 +62,12 @@
"unique": 1
},
{
"depends_on": "eval !doc.from_external_ecomm_platform",
"fieldname": "pricing_rule",
"fieldtype": "Link",
"label": "Pricing Rule",
"options": "Pricing Rule",
"reqd": 1
"mandatory_depends_on": "eval: !doc.from_external_ecomm_platform",
"options": "Pricing Rule"
},
{
"fieldname": "uses",
@@ -114,13 +116,20 @@
"options": "Coupon Code",
"print_hide": 1,
"read_only": 1
},
{
"default": "0",
"fieldname": "from_external_ecomm_platform",
"fieldtype": "Check",
"label": "From External Ecomm Platform"
}
],
"links": [],
"modified": "2024-03-27 13:06:47.220931",
"modified": "2024-06-28 06:17:01.833399",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Coupon Code",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
@@ -177,4 +186,4 @@
"states": [],
"title_field": "coupon_name",
"track_changes": 1
}
}

View File

@@ -23,8 +23,9 @@ class CouponCode(Document):
coupon_type: DF.Literal["Promotional", "Gift Card"]
customer: DF.Link | None
description: DF.TextEditor | None
from_external_ecomm_platform: DF.Check
maximum_use: DF.Int
pricing_rule: DF.Link
pricing_rule: DF.Link | None
used: DF.Int
valid_from: DF.Date | None
valid_upto: DF.Date | None

View File

@@ -142,3 +142,39 @@ class TestCouponCode(unittest.TestCase):
so.submit()
self.assertEqual(frappe.db.get_value("Coupon Code", "SAVE30", "used"), 1)
def test_coupon_without_max_use(self):
from erpnext.accounts.doctype.pricing_rule.utils import (
update_coupon_code_count,
validate_coupon_code,
)
coupon = frappe.get_doc(
{
"doctype": "Coupon Code",
"coupon_name": "_Test Coupon Without Max Use",
"coupon_code": "TESTUNLIMITED",
"from_external_ecomm_platform": 1, # avoids requirement for pricing rule
"valid_from": frappe.utils.nowdate(),
"maximum_use": 0,
"used": 0,
}
)
coupon.insert(ignore_permissions=True)
# Validate initial state
self.assertEqual(coupon.used, 0)
self.assertEqual(coupon.maximum_use, 0)
# Use coupon multiple times
for _ in range(5):
validate_coupon_code(coupon.name)
update_coupon_code_count(coupon.name, "used")
coupon.reload()
# Check that the coupon is still valid and usage count increased
self.assertEqual(coupon.used, 5)
validate_coupon_code(coupon.name) # This should not raise an error
# Clean up
coupon.delete()

View File

@@ -148,7 +148,19 @@ class Dunning(AccountsController):
def on_cancel(self):
super().on_cancel()
self.ignore_linked_doctypes = ["GL Entry"]
self.ignore_linked_doctypes = [
"GL Entry",
"Stock Ledger Entry",
"Repost Item Valuation",
"Repost Payment Ledger",
"Repost Payment Ledger Items",
"Repost Accounting Ledger",
"Repost Accounting Ledger Items",
"Unreconcile Payment",
"Unreconcile Payment Entries",
"Payment Ledger Entry",
"Serial and Batch Bundle",
]
def resolve_dunning(doc, state):
@@ -181,10 +193,13 @@ def resolve_dunning(doc, state):
outstanding_ps = frappe.get_value(
"Payment Schedule", overdue_payment.payment_schedule, "outstanding"
)
resolve = False if (outstanding_ps > 0 and outstanding_inv > 0) else True
resolve = resolve and (False if (outstanding_ps > 0 and outstanding_inv > 0) else True)
dunning.status = "Resolved" if resolve else "Unresolved"
dunning.save()
new_status = "Resolved" if resolve else "Unresolved"
if dunning.status != new_status:
dunning.status = new_status
dunning.save()
def get_linked_dunnings_as_per_state(sales_invoice, state):

View File

@@ -85,18 +85,16 @@ frappe.ui.form.on("Exchange Rate Revaluation", {
},
make_jv: function (frm) {
let revaluation_journal = null;
let zero_balance_journal = null;
frappe.call({
method: "make_jv_entries",
doc: frm.doc,
freeze: true,
freeze_message: "Making Journal Entries...",
freeze_message: __("Creating Journal Entries..."),
callback: function (r) {
if (r.message) {
let response = r.message;
if (response["revaluation_jv"] || response["zero_balance_jv"]) {
frappe.msgprint(__("Journals have been created"));
frappe.msgprint(__("Journal entries have been created"));
}
}
},

View File

@@ -82,7 +82,7 @@
"icon": "fa fa-calendar",
"idx": 1,
"links": [],
"modified": "2024-01-30 12:35:38.645968",
"modified": "2024-05-27 17:29:55.560840",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Fiscal Year",
@@ -127,6 +127,10 @@
{
"read": 1,
"role": "Stock Manager"
},
{
"read": 1,
"role": "Auditor"
}
],
"show_name_in_global_search": 1,

View File

@@ -25,30 +25,6 @@ frappe.ui.form.on("Journal Entry", {
refresh: function (frm) {
erpnext.toggle_naming_series();
if (frm.doc.repost_required && frm.doc.docstatus === 1) {
frm.set_intro(
__(
"Accounting entries for this Journal Entry need to be reposted. Please click on 'Repost' button to update."
)
);
frm.add_custom_button(__("Repost Accounting Entries"), () => {
frm.call({
doc: frm.doc,
method: "repost_accounting_entries",
freeze: true,
freeze_message: __("Reposting..."),
callback: (r) => {
if (!r.exc) {
frappe.msgprint(__("Accounting Entries are reposted."));
frm.refresh();
}
},
});
})
.removeClass("btn-default")
.addClass("btn-warning");
}
if (frm.doc.docstatus > 0) {
frm.add_custom_button(
__("Ledger"),

View File

@@ -64,8 +64,7 @@
"stock_entry",
"subscription_section",
"auto_repeat",
"amended_from",
"repost_required"
"amended_from"
],
"fields": [
{
@@ -544,15 +543,6 @@
"label": "Is System Generated",
"no_copy": 1,
"read_only": 1
},
{
"default": "0",
"fieldname": "repost_required",
"fieldtype": "Check",
"hidden": 1,
"label": "Repost Required",
"print_hide": 1,
"read_only": 1
}
],
"icon": "fa fa-file-text",
@@ -567,7 +557,7 @@
"table_fieldname": "payment_entries"
}
],
"modified": "2024-03-27 13:09:58.366953",
"modified": "2024-07-18 15:32:29.413598",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",

View File

@@ -47,9 +47,7 @@ class JournalEntry(AccountsController):
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.journal_entry_account.journal_entry_account import (
JournalEntryAccount,
)
from erpnext.accounts.doctype.journal_entry_account.journal_entry_account import JournalEntryAccount
accounts: DF.Table[JournalEntryAccount]
amended_from: DF.Link | None
@@ -194,15 +192,13 @@ class JournalEntry(AccountsController):
self.update_asset_value()
self.update_inter_company_jv()
self.update_invoice_discounting()
self.update_booked_depreciation()
def on_update_after_submit(self):
if hasattr(self, "repost_required"):
self.needs_repost = self.check_if_fields_updated(
fields_to_check=[], child_tables={"accounts": []}
)
if self.needs_repost:
self.validate_for_repost()
self.db_set("repost_required", self.needs_repost)
self.needs_repost = self.check_if_fields_updated(fields_to_check=[], child_tables={"accounts": []})
if self.needs_repost:
self.validate_for_repost()
self.repost_accounting_entries()
def on_cancel(self):
# References for this Journal are removed on the `on_cancel` event in accounts_controller
@@ -225,6 +221,7 @@ class JournalEntry(AccountsController):
self.unlink_inter_company_jv()
self.unlink_asset_adjustment_entry()
self.update_invoice_discounting()
self.update_booked_depreciation(1)
def get_title(self):
return self.pay_to_recd_from or self.accounts[0].account
@@ -442,6 +439,25 @@ class JournalEntry(AccountsController):
if status:
inv_disc_doc.set_status(status=status)
def update_booked_depreciation(self, cancel=0):
for d in self.get("accounts"):
if (
self.voucher_type == "Depreciation Entry"
and d.reference_type == "Asset"
and d.reference_name
and frappe.get_cached_value("Account", d.account, "root_type") == "Expense"
and d.debit
):
asset = frappe.get_doc("Asset", d.reference_name)
for fb_row in asset.get("finance_books"):
if fb_row.finance_book == self.finance_book:
if cancel:
fb_row.total_number_of_booked_depreciations -= 1
else:
fb_row.total_number_of_booked_depreciations += 1
fb_row.db_update()
break
def unlink_advance_entry_reference(self):
for d in self.get("accounts"):
if d.is_advance == "Yes" and d.reference_type in ("Sales Invoice", "Purchase Invoice"):
@@ -457,7 +473,7 @@ class JournalEntry(AccountsController):
self.voucher_type == "Depreciation Entry"
and d.reference_type == "Asset"
and d.reference_name
and d.account_type == "Depreciation"
and frappe.get_cached_value("Account", d.account, "root_type") == "Expense"
and d.debit
):
asset = frappe.get_doc("Asset", d.reference_name)
@@ -1034,6 +1050,17 @@ class JournalEntry(AccountsController):
def build_gl_map(self):
gl_map = []
company_currency = erpnext.get_company_currency(self.company)
if self.multi_currency:
for row in self.get("accounts"):
if row.account_currency != company_currency:
self.currency = row.account_currency
self.conversion_rate = row.exchange_rate
break
else:
self.currency = company_currency
for d in self.get("accounts"):
if d.debit or d.credit or (self.voucher_type == "Exchange Gain Or Loss"):
r = [d.user_remark, self.remark]

View File

@@ -454,12 +454,9 @@ class TestJournalEntry(unittest.TestCase):
# Change cost center for bank account - _Test Cost Center for BS Account
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
jv.accounts[1].cost_center = "_Test Cost Center for BS Account - _TC"
# Ledger reposted implicitly upon 'Update After Submit'
jv.save()
# Check if repost flag gets set on update after submit
self.assertTrue(jv.repost_required)
jv.repost_accounting_entries()
# Check GL entries after reposting
jv.load_from_db()
self.expected_gle[0]["cost_center"] = "_Test Cost Center for BS Account - _TC"
@@ -481,6 +478,43 @@ class TestJournalEntry(unittest.TestCase):
for field in self.fields:
self.assertEqual(self.expected_gle[i][field], gl_entries[i][field])
def test_negative_debit_and_credit_with_same_account_head(self):
from erpnext.accounts.general_ledger import process_gl_map
# Create JV with defaut cost center - _Test Cost Center
frappe.db.set_single_value("Accounts Settings", "merge_similar_account_heads", 0)
jv = make_journal_entry("_Test Bank - _TC", "_Test Bank - _TC", 100 * -1, save=True)
jv.append(
"accounts",
{
"account": "_Test Cash - _TC",
"debit": 100 * -1,
"credit": 100 * -1,
"debit_in_account_currency": 100 * -1,
"credit_in_account_currency": 100 * -1,
"exchange_rate": 1,
},
)
jv.flags.ignore_validate = True
jv.save()
self.assertEqual(len(jv.accounts), 3)
gl_map = jv.build_gl_map()
for row in gl_map:
if row.account == "_Test Cash - _TC":
self.assertEqual(row.debit_in_account_currency, 100 * -1)
self.assertEqual(row.credit_in_account_currency, 100 * -1)
gl_map = process_gl_map(gl_map, False)
for row in gl_map:
if row.account == "_Test Cash - _TC":
self.assertEqual(row.debit_in_account_currency, 100)
self.assertEqual(row.credit_in_account_currency, 100)
def make_journal_entry(
account1,

View File

@@ -36,7 +36,17 @@ class LoyaltyProgram(Document):
to_date: DF.Date | None
# end: auto-generated types
pass
def validate(self):
self.validate_lowest_tier()
def validate_lowest_tier(self):
tiers = sorted(self.collection_rules, key=lambda x: x.min_spent)
if tiers and tiers[0].min_spent != 0:
frappe.throw(
_(
"The lowest tier must have a minimum spent amount of 0. Customers need to be part of a tier as soon as they are enrolled in the program."
)
)
def get_loyalty_details(
@@ -79,17 +89,17 @@ def get_loyalty_program_details_with_points(
):
lp_details = get_loyalty_program_details(customer, loyalty_program, company=company, silent=silent)
loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program)
lp_details.update(
get_loyalty_details(customer, loyalty_program.name, expiry_date, company, include_expired_entry)
loyalty_details = get_loyalty_details(
customer, loyalty_program.name, expiry_date, company, include_expired_entry
)
lp_details.update(loyalty_details)
tier_spent_level = sorted(
[d.as_dict() for d in loyalty_program.collection_rules],
key=lambda rule: rule.min_spent,
reverse=True,
)
for i, d in enumerate(tier_spent_level):
if i == 0 or (lp_details.total_spent + current_transaction_amount) <= d.min_spent:
if i == 0 or (lp_details.total_spent + current_transaction_amount) >= d.min_spent:
lp_details.tier_name = d.tier_name
lp_details.collection_factor = d.collection_factor
else:
@@ -173,6 +183,8 @@ def validate_loyalty_points(ref_doc, points_to_redeem):
if not ref_doc.loyalty_amount and ref_doc.loyalty_amount != loyalty_amount:
ref_doc.loyalty_amount = loyalty_amount
if not ref_doc.loyalty_points and ref_doc.loyalty_points != points_to_redeem:
ref_doc.loyalty_points = points_to_redeem
if ref_doc.doctype == "Sales Invoice":
ref_doc.loyalty_program = loyalty_program

View File

@@ -7,6 +7,7 @@ import frappe
from frappe.utils import cint, flt, getdate, today
from erpnext.accounts.doctype.loyalty_program.loyalty_program import (
get_loyalty_details,
get_loyalty_program_details_with_points,
)
from erpnext.accounts.party import get_dashboard_info
@@ -38,6 +39,7 @@ class TestLoyaltyProgram(unittest.TestCase):
)
self.assertEqual(si_original.get("loyalty_program"), customer.loyalty_program)
self.assertEqual(lpe.get("loyalty_program_tier"), "Bronce") # is always in the first tier
self.assertEqual(lpe.get("loyalty_program_tier"), customer.loyalty_program_tier)
self.assertEqual(lpe.loyalty_points, earned_points)
@@ -79,6 +81,7 @@ class TestLoyaltyProgram(unittest.TestCase):
si_original = create_sales_invoice_record()
si_original.insert()
si_original.submit()
customer.reload()
earned_points = get_points_earned(si_original)
@@ -101,8 +104,8 @@ class TestLoyaltyProgram(unittest.TestCase):
si_redeem.loyalty_points = earned_points
si_redeem.insert()
si_redeem.submit()
customer.reload()
customer = frappe.get_doc("Customer", {"customer_name": "Test Loyalty Customer"})
earned_after_redemption = get_points_earned(si_redeem)
lpe_redeem = frappe.get_doc(
@@ -197,6 +200,70 @@ class TestLoyaltyProgram(unittest.TestCase):
for d in company_wise_info:
self.assertTrue(d.get("loyalty_points"))
@unittest.mock.patch("erpnext.accounts.doctype.loyalty_program.loyalty_program.get_loyalty_details")
def test_tier_selection(self, mock_get_loyalty_details):
# Create a new loyalty program with multiple tiers
loyalty_program = frappe.get_doc(
{
"doctype": "Loyalty Program",
"loyalty_program_name": "Test Tier Selection",
"auto_opt_in": 1,
"from_date": today(),
"loyalty_program_type": "Multiple Tier Program",
"conversion_factor": 1,
"expiry_duration": 10,
"company": "_Test Company",
"cost_center": "Main - _TC",
"expense_account": "Loyalty - _TC",
"collection_rules": [
{"tier_name": "Gold", "collection_factor": 1000, "min_spent": 20000},
{"tier_name": "Silver", "collection_factor": 1000, "min_spent": 10000},
{"tier_name": "Bronze", "collection_factor": 1000, "min_spent": 0},
],
}
)
loyalty_program.insert()
# Test cases with different total_spent and current_transaction_amount combinations
test_cases = [
(0, 6000, "Bronze"),
(0, 15000, "Silver"),
(0, 25000, "Gold"),
(4000, 500, "Bronze"),
(8000, 3000, "Silver"),
(18000, 3000, "Gold"),
(22000, 5000, "Gold"),
]
for total_spent, current_transaction_amount, expected_tier in test_cases:
with self.subTest(total_spent=total_spent, current_transaction_amount=current_transaction_amount):
# Mock the get_loyalty_details function to update the total_spent
def side_effect(*args, **kwargs):
result = get_loyalty_details(*args, **kwargs)
result.update({"total_spent": total_spent})
return result
mock_get_loyalty_details.side_effect = side_effect
lp_details = get_loyalty_program_details_with_points(
"Test Loyalty Customer",
loyalty_program=loyalty_program.name,
company="_Test Company",
current_transaction_amount=current_transaction_amount,
)
# Get the selected tier based on the current implementation
selected_tier = lp_details.tier_name
self.assertEqual(
selected_tier,
expected_tier,
f"Expected tier {expected_tier} for total_spent {total_spent} and current_transaction_amount {current_transaction_amount}, but got {selected_tier}",
)
# Clean up
loyalty_program.delete()
def get_points_earned(self):
def get_returned_amount():
@@ -285,7 +352,7 @@ def create_records():
"company": "_Test Company",
"cost_center": "Main - _TC",
"expense_account": "Loyalty - _TC",
"collection_rules": [{"tier_name": "Silver", "collection_factor": 1000, "min_spent": 1000}],
"collection_rules": [{"tier_name": "Bronce", "collection_factor": 1000, "min_spent": 0}],
}
).insert()
@@ -316,6 +383,7 @@ def create_records():
"cost_center": "Main - _TC",
"expense_account": "Loyalty - _TC",
"collection_rules": [
{"tier_name": "Bronze", "collection_factor": 1000, "min_spent": 0},
{"tier_name": "Silver", "collection_factor": 1000, "min_spent": 10000},
{"tier_name": "Gold", "collection_factor": 1000, "min_spent": 19000},
],

View File

@@ -20,6 +20,7 @@
{
"fieldname": "min_spent",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Minimum Total Spent"
},
{
@@ -37,7 +38,7 @@
],
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:03.536071",
"modified": "2024-09-05 07:41:25.694041",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Loyalty Program Collection",

View File

@@ -48,7 +48,7 @@
"idx": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-03-27 13:10:05.597711",
"modified": "2024-08-16 19:22:42.942264",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Mode of Payment",
@@ -74,5 +74,6 @@
"show_name_in_global_search": 1,
"sort_field": "creation",
"sort_order": "ASC",
"states": []
"states": [],
"translated_doctype": 1
}

View File

@@ -35,6 +35,11 @@ frappe.ui.form.on("Payment Entry", {
var account_types = ["Pay", "Internal Transfer"].includes(frm.doc.payment_type)
? ["Bank", "Cash"]
: [frappe.boot.party_account_types[frm.doc.party_type]];
if (frm.doc.party_type == "Shareholder") {
account_types.push("Equity");
}
return {
filters: {
account_type: ["in", account_types],
@@ -90,6 +95,9 @@ frappe.ui.form.on("Payment Entry", {
var account_types = ["Receive", "Internal Transfer"].includes(frm.doc.payment_type)
? ["Bank", "Cash"]
: [frappe.boot.party_account_types[frm.doc.party_type]];
if (frm.doc.party_type == "Shareholder") {
account_types.push("Equity");
}
return {
filters: {
account_type: ["in", account_types],
@@ -165,8 +173,25 @@ frappe.ui.form.on("Payment Entry", {
filters: filters,
};
});
},
frm.set_query("sales_taxes_and_charges_template", function () {
return {
filters: {
company: frm.doc.company,
disabled: false,
},
};
});
frm.set_query("purchase_taxes_and_charges_template", function () {
return {
filters: {
company: frm.doc.company,
disabled: false,
},
};
});
},
refresh: function (frm) {
erpnext.hide_company(frm);
frm.events.hide_unhide_fields(frm);
@@ -213,7 +238,7 @@ frappe.ui.form.on("Payment Entry", {
hide_unhide_fields: function (frm) {
var company_currency = frm.doc.company
? frappe.get_doc(":Company", frm.doc.company).default_currency
? frappe.get_doc(":Company", frm.doc.company)?.default_currency
: "";
frm.toggle_display(
@@ -280,7 +305,7 @@ frappe.ui.form.on("Payment Entry", {
set_dynamic_labels: function (frm) {
var company_currency = frm.doc.company
? frappe.get_doc(":Company", frm.doc.company).default_currency
? frappe.get_doc(":Company", frm.doc.company)?.default_currency
: "";
frm.set_currency_labels(
@@ -395,6 +420,12 @@ frappe.ui.form.on("Payment Entry", {
return {
query: "erpnext.controllers.queries.employee_query",
};
} else if (frm.doc.party_type == "Shareholder") {
return {
filters: {
company: frm.doc.company,
},
};
}
});
@@ -627,7 +658,7 @@ frappe.ui.form.on("Payment Entry", {
frm.set_value("source_exchange_rate", 1);
} else if (frm.doc.paid_from) {
if (["Internal Transfer", "Pay"].includes(frm.doc.payment_type)) {
let company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
let company_currency = frappe.get_doc(":Company", frm.doc.company)?.default_currency;
frappe.call({
method: "erpnext.setup.utils.get_exchange_rate",
args: {

View File

@@ -20,6 +20,7 @@
"party",
"party_name",
"book_advance_payments_in_separate_party_account",
"reconcile_on_advance_payment_date",
"column_break_11",
"bank_account",
"party_bank_account",
@@ -88,6 +89,7 @@
"custom_remarks",
"remarks",
"base_in_words",
"is_opening",
"column_break_16",
"letter_head",
"print_heading",
@@ -751,6 +753,7 @@
"fieldtype": "Check",
"hidden": 1,
"label": "Book Advance Payments in Separate Party Account",
"no_copy": 1,
"read_only": 1
},
{
@@ -766,6 +769,26 @@
"label": "In Words",
"print_hide": 1,
"read_only": 1
},
{
"default": "0",
"fetch_from": "company.reconcile_on_advance_payment_date",
"fieldname": "reconcile_on_advance_payment_date",
"fieldtype": "Check",
"hidden": 1,
"label": "Reconcile on Advance Payment Date",
"no_copy": 1,
"read_only": 1
},
{
"default": "No",
"depends_on": "eval: doc.book_advance_payments_in_separate_party_account == 1",
"fieldname": "is_opening",
"fieldtype": "Select",
"label": "Is Opening",
"options": "No\nYes",
"print_hide": 1,
"search_index": 1
}
],
"index_web_pages_for_search": 1,
@@ -779,7 +802,7 @@
"table_fieldname": "payment_entries"
}
],
"modified": "2024-04-11 11:25:07.366347",
"modified": "2024-05-31 17:07:06.197249",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

View File

@@ -37,7 +37,6 @@ from erpnext.accounts.utils import (
get_account_currency,
get_balance_on,
get_outstanding_invoices,
get_party_types_from_account_type,
)
from erpnext.controllers.accounts_controller import (
AccountsController,
@@ -158,14 +157,12 @@ class PaymentEntry(AccountsController):
self.setup_party_account_field()
self.set_missing_values()
self.set_liability_account()
self.validate_advance_account_currency()
self.set_missing_ref_details(force=True)
self.validate_payment_type()
self.validate_party_details()
self.set_exchange_rate()
self.validate_mandatory()
self.validate_reference_documents()
self.set_tax_withholding()
self.set_amounts()
self.validate_amounts()
self.apply_taxes()
@@ -179,6 +176,7 @@ class PaymentEntry(AccountsController):
self.validate_allocated_amount()
self.validate_paid_invoices()
self.ensure_supplier_is_not_blocked()
self.set_tax_withholding()
self.set_status()
self.set_total_in_words()
@@ -197,12 +195,15 @@ class PaymentEntry(AccountsController):
if self.docstatus > 0 or self.payment_type == "Internal Transfer":
return
self.book_advance_payments_in_separate_party_account = False
if self.party_type not in ("Customer", "Supplier"):
self.is_opening = "No"
return
if not frappe.db.get_value(
"Company", self.company, "book_advance_payments_in_separate_party_account"
):
self.is_opening = "No"
return
# Important to set this flag for the gl building logic to work properly
@@ -214,6 +215,7 @@ class PaymentEntry(AccountsController):
if (account_type == "Payable" and self.party_type == "Customer") or (
account_type == "Receivable" and self.party_type == "Supplier"
):
self.is_opening = "No"
return
if self.references:
@@ -223,6 +225,7 @@ class PaymentEntry(AccountsController):
# If there are referencers other than `allowed_types`, treat this as a normal payment entry
if reference_types - allowed_types:
self.book_advance_payments_in_separate_party_account = False
self.is_opening = "No"
return
liability_account = get_party_account(
@@ -241,22 +244,6 @@ class PaymentEntry(AccountsController):
alert=True,
)
def validate_advance_account_currency(self):
if self.book_advance_payments_in_separate_party_account is True:
company_currency = frappe.get_cached_value("Company", self.company, "default_currency")
if self.payment_type == "Receive" and self.paid_from_account_currency != company_currency:
frappe.throw(
_("Booking advances in foreign currency account: {0} ({1}) is not yet supported.").format(
frappe.bold(self.paid_from), frappe.bold(self.paid_from_account_currency)
)
)
if self.payment_type == "Pay" and self.paid_to_account_currency != company_currency:
frappe.throw(
_("Booking advances in foreign currency account: {0} ({1}) is not yet supported.").format(
frappe.bold(self.paid_to), frappe.bold(self.paid_to_account_currency)
)
)
def on_cancel(self):
self.ignore_linked_doctypes = (
"GL Entry",
@@ -858,9 +845,7 @@ class PaymentEntry(AccountsController):
if not self.apply_tax_withholding_amount:
return
order_amount = self.get_order_net_total()
net_total = flt(order_amount) + flt(self.unallocated_amount)
net_total = self.calculate_tax_withholding_net_total()
# Adding args as purchase invoice to get TDS amount
args = frappe._dict(
@@ -904,7 +889,26 @@ class PaymentEntry(AccountsController):
for d in to_remove:
self.remove(d)
def get_order_net_total(self):
def calculate_tax_withholding_net_total(self):
net_total = 0
order_details = self.get_order_wise_tax_withholding_net_total()
for d in self.references:
tax_withholding_net_total = order_details.get(d.reference_name)
if not tax_withholding_net_total:
continue
net_taxable_outstanding = max(
0, d.outstanding_amount - (d.total_amount - tax_withholding_net_total)
)
net_total += min(net_taxable_outstanding, d.allocated_amount)
net_total += self.unallocated_amount
return net_total
def get_order_wise_tax_withholding_net_total(self):
if self.party_type == "Supplier":
doctype = "Purchase Order"
else:
@@ -912,12 +916,15 @@ class PaymentEntry(AccountsController):
docnames = [d.reference_name for d in self.references if d.reference_doctype == doctype]
tax_withholding_net_total = frappe.db.get_value(
doctype, {"name": ["in", docnames]}, ["sum(base_tax_withholding_net_total)"]
return frappe._dict(
frappe.db.get_all(
doctype,
filters={"name": ["in", docnames]},
fields=["name", "base_tax_withholding_net_total"],
as_list=True,
)
)
return tax_withholding_net_total
def apply_taxes(self):
self.initialize_taxes()
self.determine_exclusive_rate()
@@ -1206,107 +1213,82 @@ class PaymentEntry(AccountsController):
self.make_advance_gl_entries(cancel=cancel)
def add_party_gl_entries(self, gl_entries):
if self.party_account:
if self.payment_type == "Receive":
against_account = self.paid_to
else:
against_account = self.paid_from
if not self.party_account:
return
party_gl_dict = self.get_gl_dict(
if self.payment_type == "Receive":
against_account = self.paid_to
else:
against_account = self.paid_from
party_account_type = frappe.db.get_value("Party Type", self.party_type, "account_type")
party_gl_dict = self.get_gl_dict(
{
"account": self.party_account,
"party_type": self.party_type,
"party": self.party,
"against": against_account,
"account_currency": self.party_account_currency,
"cost_center": self.cost_center,
},
item=self,
)
for d in self.get("references"):
# re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
gle = party_gl_dict.copy()
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
if (
d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]
and d.allocated_amount < 0
and (
(party_account_type == "Receivable" and self.payment_type == "Pay")
or (party_account_type == "Payable" and self.payment_type == "Receive")
)
):
# reversing dr_cr because because it will get reversed in gl processing due to negative amount
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
gle.update(
{
"account": self.party_account,
"party_type": self.party_type,
"party": self.party,
"against": against_account,
"account_currency": self.party_account_currency,
"cost_center": self.cost_center,
},
item=self,
dr_or_cr: allocated_amount_in_company_currency,
dr_or_cr + "_in_account_currency": d.allocated_amount,
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
"cost_center": cost_center,
}
)
gl_entries.append(gle)
if self.unallocated_amount:
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = self.unallocated_amount * exchange_rate
gle = party_gl_dict.copy()
gle.update(
{
dr_or_cr + "_in_account_currency": self.unallocated_amount,
dr_or_cr: base_unallocated_amount,
}
)
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
if self.book_advance_payments_in_separate_party_account:
gle = party_gl_dict.copy()
if self.payment_type == "Receive":
amount = self.base_paid_amount
else:
amount = self.base_received_amount
exchange_rate = self.get_exchange_rate()
amount_in_account_currency = amount * exchange_rate
gle.update(
{
dr_or_cr: amount,
dr_or_cr + "_in_account_currency": amount_in_account_currency,
"against_voucher_type": "Payment Entry",
"against_voucher": self.name,
"cost_center": self.cost_center,
}
)
gl_entries.append(gle)
else:
for d in self.get("references"):
# re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(
d.reference_doctype, d.reference_name, "cost_center"
)
gle = party_gl_dict.copy()
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(
d
)
reverse_dr_or_cr = 0
if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]:
is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return")
payable_party_types = get_party_types_from_account_type("Payable")
receivable_party_types = get_party_types_from_account_type("Receivable")
if (
is_return
and self.party_type in receivable_party_types
and (self.payment_type == "Pay")
):
reverse_dr_or_cr = 1
elif (
is_return
and self.party_type in payable_party_types
and (self.payment_type == "Receive")
):
reverse_dr_or_cr = 1
if is_return and not reverse_dr_or_cr:
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
gle.update(
{
dr_or_cr: abs(allocated_amount_in_company_currency),
dr_or_cr + "_in_account_currency": abs(d.allocated_amount),
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
"cost_center": cost_center,
}
)
gl_entries.append(gle)
if self.unallocated_amount:
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = self.unallocated_amount * exchange_rate
gle = party_gl_dict.copy()
gle.update(
{
dr_or_cr + "_in_account_currency": self.unallocated_amount,
dr_or_cr: base_unallocated_amount,
}
)
gl_entries.append(gle)
gl_entries.append(gle)
def make_advance_gl_entries(
self, entry: object | dict = None, cancel: bool = 0, update_outstanding: str = "Yes"
@@ -1321,7 +1303,7 @@ class PaymentEntry(AccountsController):
def add_advance_gl_entries(self, gl_entries: list, entry: object | dict | None):
"""
If 'entry' is passed, GL enties only for that reference is added.
If 'entry' is passed, GL entries only for that reference is added.
"""
if self.book_advance_payments_in_separate_party_account:
references = [x for x in self.get("references")]
@@ -1333,8 +1315,6 @@ class PaymentEntry(AccountsController):
"Sales Invoice",
"Purchase Invoice",
"Journal Entry",
"Sales Order",
"Purchase Order",
"Payment Entry",
):
self.add_advance_gl_for_reference(gl_entries, ref)
@@ -1343,13 +1323,21 @@ class PaymentEntry(AccountsController):
if reference.reference_doctype == "Sales Invoice":
return "credit", reference.account
if reference.reference_doctype == "Purchase Invoice":
return "debit", reference.account
if reference.reference_doctype == "Payment Entry":
# reference.account_type and reference.payment_type is only available for Reverse payments
if reference.account_type == "Receivable" and reference.payment_type == "Pay":
return "credit", self.party_account
else:
return "debit", self.party_account
return "debit", reference.account
if reference.reference_doctype == "Journal Entry":
if self.party_type == "Customer" and self.payment_type == "Receive":
return "credit", reference.account
else:
return "debit", reference.account
def add_advance_gl_for_reference(self, gl_entries, invoice):
args_dict = {
@@ -1362,17 +1350,20 @@ class PaymentEntry(AccountsController):
"voucher_detail_no": invoice.name,
}
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):
if self.reconcile_on_advance_payment_date:
posting_date = self.posting_date
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):
posting_date = self.posting_date
dr_or_cr, account = self.get_dr_and_account_for_advances(invoice)
args_dict["account"] = account
args_dict[dr_or_cr] = invoice.allocated_amount
args_dict[dr_or_cr] = self.calculate_base_allocated_amount_for_reference(invoice)
args_dict[dr_or_cr + "_in_account_currency"] = invoice.allocated_amount
args_dict.update(
{
@@ -1391,7 +1382,7 @@ class PaymentEntry(AccountsController):
args_dict[dr_or_cr + "_in_account_currency"] = 0
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
args_dict["account"] = self.party_account
args_dict[dr_or_cr] = invoice.allocated_amount
args_dict[dr_or_cr] = self.calculate_base_allocated_amount_for_reference(invoice)
args_dict[dr_or_cr + "_in_account_currency"] = invoice.allocated_amount
args_dict.update(
{
@@ -1847,7 +1838,7 @@ def get_outstanding_reference_documents(args, validate=False):
d["bill_no"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "bill_no")
# Get negative outstanding sales /purchase invoices
if args.get("party_type") != "Employee" and not args.get("voucher_no"):
if args.get("party_type") != "Employee":
negative_outstanding_invoices = get_negative_outstanding_invoices(
args.get("party_type"),
args.get("party"),

View File

@@ -82,7 +82,7 @@ class TestPaymentEntry(FrappeTestCase):
expected_gle = dict(
(d[0], d)
for d in [["_Test Receivable USD - _TC", 0, 5500, so.name], ["Cash - _TC", 5500.0, 0, None]]
for d in [["_Test Receivable USD - _TC", 0, 5500, so.name], [pe.paid_to, 5500.0, 0, None]]
)
self.validate_gl_entries(pe.name, expected_gle)
@@ -1477,6 +1477,68 @@ class TestPaymentEntry(FrappeTestCase):
self.check_gl_entries()
self.check_pl_entries()
def test_advance_as_liability_against_order(self):
from erpnext.buying.doctype.purchase_order.purchase_order import (
make_purchase_invoice as _make_purchase_invoice,
)
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
company = "_Test Company"
advance_account = create_account(
parent_account="Current Liabilities - _TC",
account_name="Advances Paid",
company=company,
account_type="Liability",
)
frappe.db.set_value(
"Company",
company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_paid_account": advance_account,
},
)
po = create_purchase_order(supplier="_Test Supplier")
pe = get_payment_entry("Purchase Order", po.name, bank_account="Cash - _TC")
pe.save().submit()
pre_reconciliation_gle = [
{"account": "Cash - _TC", "debit": 0.0, "credit": 5000.0},
{"account": advance_account, "debit": 5000.0, "credit": 0.0},
]
self.voucher_no = pe.name
self.expected_gle = pre_reconciliation_gle
self.check_gl_entries()
# Make Purchase Invoice against the order
pi = _make_purchase_invoice(po.name)
pi.append(
"advances",
{
"reference_type": pe.doctype,
"reference_name": pe.name,
"reference_row": pe.references[0].name,
"advance_amount": 5000,
"allocated_amount": 5000,
},
)
pi.save().submit()
# # assert General and Payment Ledger entries post partial reconciliation
self.expected_gle = [
{"account": pi.credit_to, "debit": 5000.0, "credit": 0.0},
{"account": "Cash - _TC", "debit": 0.0, "credit": 5000.0},
{"account": advance_account, "debit": 5000.0, "credit": 0.0},
{"account": advance_account, "debit": 0.0, "credit": 5000.0},
]
self.voucher_no = pe.name
self.check_gl_entries()
def check_pl_entries(self):
ple = frappe.qb.DocType("Payment Ledger Entry")
pl_entries = (
@@ -1667,6 +1729,68 @@ class TestPaymentEntry(FrappeTestCase):
self.check_gl_entries()
self.check_pl_entries()
def test_opening_flag_for_advance_as_liability(self):
company = "_Test Company"
advance_account = create_account(
parent_account="Current Assets - _TC",
account_name="Advances Received",
company=company,
account_type="Receivable",
)
# Enable Advance in separate party account
frappe.db.set_value(
"Company",
company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_received_account": advance_account,
},
)
# Advance Payment
adv = create_payment_entry(
party_type="Customer",
party="_Test Customer",
payment_type="Receive",
paid_from="Debtors - _TC",
paid_to="_Test Cash - _TC",
)
adv.is_opening = "Yes"
adv.save() # use save() to trigger set_liability_account()
adv.submit()
gl_with_opening_set = frappe.db.get_all(
"GL Entry", filters={"voucher_no": adv.name, "is_opening": "Yes"}
)
# 'Is Opening' can be 'Yes' for Advances in separate party account
self.assertNotEqual(gl_with_opening_set, [])
# Disable Advance in separate party account
frappe.db.set_value(
"Company",
company,
{
"book_advance_payments_in_separate_party_account": 0,
"default_advance_received_account": None,
},
)
payment = create_payment_entry(
party_type="Customer",
party="_Test Customer",
payment_type="Receive",
paid_from="Debtors - _TC",
paid_to="_Test Cash - _TC",
)
payment.is_opening = "Yes"
payment.save()
payment.submit()
gl_with_opening_set = frappe.db.get_all(
"GL Entry", filters={"voucher_no": payment.name, "is_opening": "Yes"}
)
# 'Is Opening' should always be 'No' for normal advance payments
self.assertEqual(gl_with_opening_set, [])
def create_payment_entry(**args):
payment_entry = frappe.new_doc("Payment Entry")

View File

@@ -49,7 +49,7 @@
"label": "Currency"
},
{
"depends_on": "eval: doc.payment_channel !== \"Phone\"",
"depends_on": "eval: doc.payment_channel == 'Email' || (!doc.payment_channel)",
"fieldname": "payment_request_message",
"fieldtype": "Section Break"
},
@@ -70,12 +70,12 @@
"fieldname": "payment_channel",
"fieldtype": "Select",
"label": "Payment Channel",
"options": "\nEmail\nPhone"
"options": "\nEmail\nPhone\nOther"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-03-27 13:10:09.836254",
"modified": "2024-03-29 18:53:09.836254",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Gateway Account",
@@ -97,4 +97,4 @@
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -509,7 +509,11 @@ class TestPaymentLedgerEntry(FrappeTestCase):
@change_settings(
"Accounts Settings",
{"unlink_payment_on_cancellation_of_invoice": 1, "delete_linked_ledger_entries": 1},
{
"unlink_payment_on_cancellation_of_invoice": 1,
"delete_linked_ledger_entries": 1,
"unlink_advance_payment_on_cancelation_of_order": 1,
},
)
def test_advance_payment_unlink_on_order_cancellation(self):
transaction_date = nowdate()

View File

@@ -36,7 +36,7 @@ frappe.ui.form.on("Payment Order", {
// payment Entry
if (frm.doc.docstatus === 1 && frm.doc.payment_order_type === "Payment Request") {
frm.add_custom_button(__("Create Payment Entries"), function () {
frm.add_custom_button(__("Create Journal Entries"), function () {
frm.trigger("make_payment_records");
});
}

View File

@@ -176,8 +176,12 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
},
callback: (r) => {
if (!r.exc && r.message) {
this.frm.set_value("receivable_payable_account", r.message[0]);
this.frm.set_value("default_advance_account", r.message[1]);
if (typeof r.message === "string") {
this.frm.set_value("receivable_payable_account", r.message);
} else if (Array.isArray(r.message)) {
this.frm.set_value("receivable_payable_account", r.message[0]);
this.frm.set_value("default_advance_account", r.message[1]);
}
}
this.frm.refresh();
},

View File

@@ -267,6 +267,7 @@ class PaymentReconciliation(Document):
conditions.append(doc.docstatus == 1)
conditions.append(doc[frappe.scrub(self.party_type)] == self.party)
conditions.append(doc.is_return == 1)
conditions.append(doc.outstanding_amount != 0)
if self.payment_name:
conditions.append(doc.name.like(f"%{self.payment_name}%"))

View File

@@ -109,6 +109,14 @@ class TestPaymentReconciliation(FrappeTestCase):
"account_currency": "INR",
"account_type": "Payable",
},
# 'Receivable' account for capturing advance received, under 'Liabilities' group
{
"attribute": "advance_receivable_account",
"account_name": "Advance Received",
"parent_account": "Current Liabilities - _PR",
"account_currency": "INR",
"account_type": "Receivable",
},
]
for x in accounts:
@@ -1525,6 +1533,318 @@ class TestPaymentReconciliation(FrappeTestCase):
]
self.assertEqual(pl_entries, expected_ple)
def test_advance_payment_reconciliation_date(self):
frappe.db.set_value(
"Company",
self.company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_paid_account": self.advance_payable_account,
"reconcile_on_advance_payment_date": 1,
},
)
self.supplier = "_Test Supplier"
amount = 1500
pe = self.create_payment_entry(amount=amount)
pe.posting_date = add_days(nowdate(), -1)
pe.party_type = "Supplier"
pe.party = self.supplier
pe.payment_type = "Pay"
pe.paid_from = self.cash
pe.paid_to = self.advance_payable_account
pe.save().submit()
pi = self.create_purchase_invoice(qty=10, rate=100)
self.assertNotEqual(pe.posting_date, pi.posting_date)
pr = self.create_payment_reconciliation(party_is_customer=False)
pr.default_advance_account = self.advance_payable_account
pr.from_payment_date = pe.posting_date
pr.get_unreconciled_entries()
self.assertEqual(len(pr.invoices), 1)
self.assertEqual(len(pr.payments), 1)
invoices = [invoice.as_dict() for invoice in pr.invoices]
payments = [payment.as_dict() for payment in pr.payments]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.reconcile()
# Assert Ledger Entries
gl_entries = frappe.db.get_all(
"GL Entry",
filters={"voucher_no": pe.name, "is_cancelled": 0, "posting_date": pe.posting_date},
)
self.assertEqual(len(gl_entries), 4)
pl_entries = frappe.db.get_all(
"Payment Ledger Entry",
filters={"voucher_no": pe.name, "delinked": 0, "posting_date": pe.posting_date},
)
self.assertEqual(len(pl_entries), 3)
def test_advance_payment_reconciliation_against_journal_for_customer(self):
frappe.db.set_value(
"Company",
self.company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_received_account": self.advance_receivable_account,
"reconcile_on_advance_payment_date": 0,
},
)
amount = 200.0
je = self.create_journal_entry(self.debit_to, self.bank, amount)
je.accounts[0].cost_center = self.main_cc.name
je.accounts[0].party_type = "Customer"
je.accounts[0].party = self.customer
je.accounts[1].cost_center = self.main_cc.name
je = je.save().submit()
pe = self.create_payment_entry(amount=amount).save().submit()
pr = self.create_payment_reconciliation()
pr.default_advance_account = self.advance_receivable_account
pr.get_unreconciled_entries()
self.assertEqual(len(pr.invoices), 1)
self.assertEqual(len(pr.payments), 1)
invoices = [invoice.as_dict() for invoice in pr.invoices]
payments = [payment.as_dict() for payment in pr.payments]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.reconcile()
# Assert Ledger Entries
gl_entries = frappe.db.get_all(
"GL Entry",
filters={"voucher_no": pe.name, "is_cancelled": 0},
)
self.assertEqual(len(gl_entries), 4)
pl_entries = frappe.db.get_all(
"Payment Ledger Entry",
filters={"voucher_no": pe.name, "delinked": 0},
)
self.assertEqual(len(pl_entries), 3)
gl_entries = frappe.db.get_all(
"GL Entry",
filters={"voucher_no": pe.name, "is_cancelled": 0},
fields=["account", "voucher_no", "against_voucher", "debit", "credit"],
order_by="account, against_voucher, debit",
)
expected_gle = [
{
"account": self.advance_receivable_account,
"voucher_no": pe.name,
"against_voucher": pe.name,
"debit": 0.0,
"credit": amount,
},
{
"account": self.advance_receivable_account,
"voucher_no": pe.name,
"against_voucher": pe.name,
"debit": amount,
"credit": 0.0,
},
{
"account": self.debit_to,
"voucher_no": pe.name,
"against_voucher": je.name,
"debit": 0.0,
"credit": amount,
},
{
"account": self.bank,
"voucher_no": pe.name,
"against_voucher": None,
"debit": amount,
"credit": 0.0,
},
]
self.assertEqual(gl_entries, expected_gle)
pl_entries = frappe.db.get_all(
"Payment Ledger Entry",
filters={"voucher_no": pe.name},
fields=["account", "voucher_no", "against_voucher_no", "amount"],
order_by="account, against_voucher_no, amount",
)
expected_ple = [
{
"account": self.advance_receivable_account,
"voucher_no": pe.name,
"against_voucher_no": pe.name,
"amount": -amount,
},
{
"account": self.advance_receivable_account,
"voucher_no": pe.name,
"against_voucher_no": pe.name,
"amount": amount,
},
{
"account": self.debit_to,
"voucher_no": pe.name,
"against_voucher_no": je.name,
"amount": -amount,
},
]
self.assertEqual(pl_entries, expected_ple)
def test_advance_payment_reconciliation_against_journal_for_supplier(self):
self.supplier = make_supplier("_Test Supplier")
frappe.db.set_value(
"Company",
self.company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_paid_account": self.advance_payable_account,
"reconcile_on_advance_payment_date": 0,
},
)
amount = 200.0
je = self.create_journal_entry(self.creditors, self.bank, -amount)
je.accounts[0].cost_center = self.main_cc.name
je.accounts[0].party_type = "Supplier"
je.accounts[0].party = self.supplier
je.accounts[1].cost_center = self.main_cc.name
je = je.save().submit()
pe = self.create_payment_entry(amount=amount)
pe.payment_type = "Pay"
pe.party_type = "Supplier"
pe.paid_from = self.bank
pe.paid_to = self.creditors
pe.party = self.supplier
pe.save().submit()
pr = self.create_payment_reconciliation(party_is_customer=False)
pr.default_advance_account = self.advance_payable_account
pr.get_unreconciled_entries()
self.assertEqual(len(pr.invoices), 1)
self.assertEqual(len(pr.payments), 1)
invoices = [invoice.as_dict() for invoice in pr.invoices]
payments = [payment.as_dict() for payment in pr.payments]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.reconcile()
# Assert Ledger Entries
gl_entries = frappe.db.get_all(
"GL Entry",
filters={"voucher_no": pe.name, "is_cancelled": 0},
)
self.assertEqual(len(gl_entries), 4)
pl_entries = frappe.db.get_all(
"Payment Ledger Entry",
filters={"voucher_no": pe.name, "delinked": 0},
)
self.assertEqual(len(pl_entries), 3)
gl_entries = frappe.db.get_all(
"GL Entry",
filters={"voucher_no": pe.name, "is_cancelled": 0},
fields=["account", "voucher_no", "against_voucher", "debit", "credit"],
order_by="account, against_voucher, debit",
)
expected_gle = [
{
"account": self.advance_payable_account,
"voucher_no": pe.name,
"against_voucher": pe.name,
"debit": 0.0,
"credit": amount,
},
{
"account": self.advance_payable_account,
"voucher_no": pe.name,
"against_voucher": pe.name,
"debit": amount,
"credit": 0.0,
},
{
"account": self.creditors,
"voucher_no": pe.name,
"against_voucher": je.name,
"debit": amount,
"credit": 0.0,
},
{
"account": self.bank,
"voucher_no": pe.name,
"against_voucher": None,
"debit": 0.0,
"credit": amount,
},
]
self.assertEqual(gl_entries, expected_gle)
pl_entries = frappe.db.get_all(
"Payment Ledger Entry",
filters={"voucher_no": pe.name},
fields=["account", "voucher_no", "against_voucher_no", "amount"],
order_by="account, against_voucher_no, amount",
)
expected_ple = [
{
"account": self.advance_payable_account,
"voucher_no": pe.name,
"against_voucher_no": pe.name,
"amount": -amount,
},
{
"account": self.advance_payable_account,
"voucher_no": pe.name,
"against_voucher_no": pe.name,
"amount": amount,
},
{
"account": self.creditors,
"voucher_no": pe.name,
"against_voucher_no": je.name,
"amount": -amount,
},
]
self.assertEqual(pl_entries, expected_ple)
def test_cr_note_payment_limit_filter(self):
transaction_date = nowdate()
amount = 100
for _ in range(6):
self.create_sales_invoice(qty=1, rate=amount, posting_date=transaction_date)
cr_note = self.create_sales_invoice(
qty=-1, rate=amount, posting_date=transaction_date, do_not_save=True, do_not_submit=True
)
cr_note.is_return = 1
cr_note = cr_note.save().submit()
pr = self.create_payment_reconciliation()
pr.get_unreconciled_entries()
self.assertEqual(len(pr.invoices), 6)
self.assertEqual(len(pr.payments), 6)
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}))
pr.reconcile()
pr.get_unreconciled_entries()
self.assertEqual(pr.get("invoices"), [])
self.assertEqual(pr.get("payments"), [])
self.create_sales_invoice(qty=1, rate=amount, posting_date=transaction_date)
cr_note = self.create_sales_invoice(
qty=-1, rate=amount, posting_date=transaction_date, do_not_save=True, do_not_submit=True
)
cr_note.is_return = 1
cr_note = cr_note.save().submit()
# Limit should not affect in fetching the unallocated cr_note
pr.invoice_limit = 5
pr.payment_limit = 5
pr.get_unreconciled_entries()
self.assertEqual(len(pr.invoices), 1)
self.assertEqual(len(pr.payments), 1)
def make_customer(customer_name, currency=None):
if not frappe.db.exists("Customer", customer_name):

View File

@@ -0,0 +1,119 @@
"""Compatipility methods for v1 implementations of payment gateways
"""
import json
import frappe
from frappe.utils import deprecated, flt
from erpnext.utilities import payment_app_import_guard
def _get_payment_controller(*args, **kwargs):
with payment_app_import_guard():
try:
from payments.utils import get_payment_controller
except Exception:
from payments.utils import get_payment_gateway_controller as get_payment_controller
return get_payment_controller(*args, **kwargs)
def get_request_amount(self):
data_of_completed_requests = frappe.get_all(
"Integration Request",
filters={
"reference_doctype": self.doctype,
"reference_docname": self.name,
"status": "Completed",
},
pluck="data",
)
if not data_of_completed_requests:
return self.grand_total
request_amounts = sum(json.loads(d).get("request_amount") for d in data_of_completed_requests)
return request_amounts
def request_phone_payment(self, controller):
request_amount = get_request_amount(self)
payment_record = dict(
reference_doctype="Payment Request",
reference_docname=self.name,
payment_reference=self.reference_name,
request_amount=request_amount,
sender=self.email_to,
currency=self.currency,
payment_gateway=self.payment_gateway,
)
controller.validate_transaction_currency(self.currency)
controller.request_for_payment(**payment_record)
def payment_gateway_validation(self, controller):
try:
if hasattr(controller, "on_payment_request_submission"):
return controller.on_payment_request_submission(self)
else:
return True
except Exception:
return False
def get_payment_url(self, controller):
if self.reference_doctype != "Fees":
data = frappe.db.get_value(
self.reference_doctype, self.reference_name, ["company", "customer_name"], as_dict=1
)
else:
data = frappe.db.get_value(self.reference_doctype, self.reference_name, ["student_name"], as_dict=1)
data.update({"company": frappe.defaults.get_defaults().company})
controller.validate_transaction_currency(self.currency)
if hasattr(controller, "validate_minimum_transaction_amount"):
controller.validate_minimum_transaction_amount(self.currency, self.grand_total)
return controller.get_payment_url(
**{
"amount": flt(self.grand_total, self.precision("grand_total")),
"title": data.company.encode("utf-8"),
"description": self.subject.encode("utf-8"),
"reference_doctype": "Payment Request",
"reference_docname": self.name,
"payer_email": self.email_to or frappe.session.user,
"payer_name": frappe.safe_encode(data.customer_name),
"order_id": self.name,
"currency": self.currency,
}
)
def set_payment_request_url(self, controller):
if self.payment_account and self.payment_gateway and payment_gateway_validation(self, controller):
self.payment_url = get_payment_url(self, controller)
def v1_gateway_before_submit(self, payment_gateway):
try:
controller = _get_payment_controller(payment_gateway)
except Exception:
frappe.warnings.warn(f"{payment_gateway} is not a valid gateway; this is normal during tests.")
return False
if self.payment_channel == "Phone":
request_phone_payment(self, controller)
else:
set_payment_request_url(self, controller)
if not (self.mute_email or self.flags.mute_email):
self.send_email()
self.make_communication_entry()
def v1_create_subscription(payment_provider, gateway_controller, data):
if payment_provider == "stripe":
with payment_app_import_guard():
from payments.payment_gateways.stripe_integration import create_stripe_subscription
return create_stripe_subscription(gateway_controller, data)

View File

@@ -10,6 +10,7 @@
"failed_reason",
"column_break_2",
"naming_series",
"company",
"mode_of_payment",
"party_details",
"party_type",
@@ -49,13 +50,14 @@
"message",
"message_examples",
"mute_email",
"payment_url",
"section_break_7",
"payment_gateway",
"payment_account",
"payment_channel",
"payment_order",
"amended_from"
"amended_from",
"column_break_pnyv",
"payment_url"
],
"fields": [
{
@@ -145,6 +147,7 @@
"fieldname": "grand_total",
"fieldtype": "Currency",
"label": "Amount",
"non_negative": 1,
"options": "currency"
},
{
@@ -260,7 +263,7 @@
"label": "Recipient Message And Payment Details"
},
{
"depends_on": "eval: doc.payment_channel != \"Phone\"",
"depends_on": "eval: doc.payment_channel == \"Email\" || (!doc.payment_channel)",
"fieldname": "print_format",
"fieldtype": "Select",
"label": "Print Format"
@@ -272,7 +275,7 @@
"label": "To"
},
{
"depends_on": "eval: doc.payment_channel != \"Phone\"",
"depends_on": "eval: doc.payment_channel == \"Email\" || (!doc.payment_channel)",
"fieldname": "subject",
"fieldtype": "Data",
"in_global_search": 1,
@@ -309,18 +312,18 @@
"read_only": 1
},
{
"depends_on": "eval: doc.payment_request_type == 'Inward' || doc.payment_channel != \"Phone\"",
"depends_on": "eval: doc.payment_request_type == 'Inward' || doc.payment_channel == \"Email\" || (!doc.payment_channel)",
"fieldname": "section_break_10",
"fieldtype": "Section Break"
},
{
"depends_on": "eval: doc.payment_channel != \"Phone\"",
"depends_on": "eval: doc.payment_channel == \"Email\" || (!doc.payment_channel)",
"fieldname": "message",
"fieldtype": "Text",
"label": "Message"
},
{
"depends_on": "eval: doc.payment_channel != \"Phone\"",
"depends_on": "eval: doc.payment_channel == \"Email\" || (!doc.payment_channel)",
"fieldname": "message_examples",
"fieldtype": "HTML",
"label": "Message Examples",
@@ -341,7 +344,7 @@
{
"fieldname": "payment_url",
"fieldtype": "Data",
"hidden": 1,
"label": "Payment URL",
"length": 500,
"options": "URL",
"read_only": 1
@@ -372,7 +375,7 @@
"fieldname": "payment_channel",
"fieldtype": "Select",
"label": "Payment Channel",
"options": "\nEmail\nPhone",
"options": "\nEmail\nPhone\nOther",
"read_only": 1
},
{
@@ -399,13 +402,24 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company",
"read_only": 1
},
{
"fieldname": "column_break_pnyv",
"fieldtype": "Column Break"
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2024-03-27 13:10:11.120742",
"modified": "2024-08-07 16:39:54.288002",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",
@@ -443,4 +457,4 @@
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -1,5 +1,3 @@
import json
import frappe
from frappe import _
from frappe.model.document import Document
@@ -16,15 +14,10 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import (
)
from erpnext.accounts.doctype.subscription_plan.subscription_plan import get_plan_rate
from erpnext.accounts.party import get_party_account, get_party_bank_account
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.utils import get_account_currency, get_currency_precision
from erpnext.utilities import payment_app_import_guard
def _get_payment_gateway_controller(*args, **kwargs):
with payment_app_import_guard():
from payments.utils import get_payment_gateway_controller
return get_payment_gateway_controller(*args, **kwargs)
from .payment_gateway_v1 import v1_create_subscription, v1_gateway_before_submit
class PaymentRequest(Document):
@@ -85,6 +78,7 @@ class PaymentRequest(Document):
subscription_plans: DF.Table[SubscriptionPlanDetail]
swift_number: DF.ReadOnly | None
transaction_date: DF.Date | None
company: DF.Link | None
# end: auto-generated types
def validate(self):
@@ -158,124 +152,26 @@ class PaymentRequest(Document):
# set advance payment status
ref_doc.set_advance_payment_status()
def on_submit(self):
def before_submit(self):
if self.payment_request_type == "Outward":
self.db_set("status", "Initiated")
self.status = "Initiated"
elif self.payment_request_type == "Inward":
self.db_set("status", "Requested")
self.status = "Requested"
if self.payment_request_type == "Inward":
send_mail = self.payment_gateway_validation() if self.payment_gateway else None
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if (
hasattr(ref_doc, "order_type") and ref_doc.order_type == "Shopping Cart"
) or self.flags.mute_email:
send_mail = False
if send_mail and self.payment_channel != "Phone":
self.set_payment_request_url()
self.send_email()
self.make_communication_entry()
elif self.payment_channel == "Phone":
self.request_phone_payment()
def request_phone_payment(self):
controller = _get_payment_gateway_controller(self.payment_gateway)
request_amount = self.get_request_amount()
payment_record = dict(
reference_doctype="Payment Request",
reference_docname=self.name,
payment_reference=self.reference_name,
request_amount=request_amount,
sender=self.email_to,
currency=self.currency,
payment_gateway=self.payment_gateway,
)
controller.validate_transaction_currency(self.currency)
controller.request_for_payment(**payment_record)
def get_request_amount(self):
data_of_completed_requests = frappe.get_all(
"Integration Request",
filters={
"reference_doctype": self.doctype,
"reference_docname": self.name,
"status": "Completed",
},
pluck="data",
)
if not data_of_completed_requests:
return self.grand_total
request_amounts = sum(json.loads(d).get("request_amount") for d in data_of_completed_requests)
return request_amounts
if self.payment_request_type == "Inward" and self.payment_gateway:
return v1_gateway_before_submit(self, self.payment_gateway)
def on_cancel(self):
self.check_if_payment_entry_exists()
self.set_as_cancelled()
def make_invoice(self):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if hasattr(ref_doc, "order_type") and ref_doc.order_type == "Shopping Cart":
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
si = make_sales_invoice(self.reference_name, ignore_permissions=True)
si.allocate_advances_automatically = True
si = si.insert(ignore_permissions=True)
si.submit()
def payment_gateway_validation(self):
try:
controller = _get_payment_gateway_controller(self.payment_gateway)
if hasattr(controller, "on_payment_request_submission"):
return controller.on_payment_request_submission(self)
else:
return True
except Exception:
return False
def set_payment_request_url(self):
if self.payment_account and self.payment_channel != "Phone":
self.payment_url = self.get_payment_url()
if self.payment_url:
self.db_set("payment_url", self.payment_url)
def get_payment_url(self):
if self.reference_doctype != "Fees":
data = frappe.db.get_value(
self.reference_doctype, self.reference_name, ["company", "customer_name"], as_dict=1
)
else:
data = frappe.db.get_value(
self.reference_doctype, self.reference_name, ["student_name"], as_dict=1
)
data.update({"company": frappe.defaults.get_defaults().company})
controller = _get_payment_gateway_controller(self.payment_gateway)
controller.validate_transaction_currency(self.currency)
if hasattr(controller, "validate_minimum_transaction_amount"):
controller.validate_minimum_transaction_amount(self.currency, self.grand_total)
return controller.get_payment_url(
**{
"amount": flt(self.grand_total, self.precision("grand_total")),
"title": data.company.encode("utf-8"),
"description": self.subject.encode("utf-8"),
"reference_doctype": "Payment Request",
"reference_docname": self.name,
"payer_email": self.email_to or frappe.session.user,
"payer_name": frappe.safe_encode(data.customer_name),
"order_id": self.name,
"currency": self.currency,
}
)
si = make_sales_invoice(self.reference_name, ignore_permissions=True)
si.allocate_advances_automatically = True
si = si.insert(ignore_permissions=True)
si.submit()
def set_as_paid(self):
if self.payment_channel == "Phone":
@@ -283,7 +179,8 @@ class PaymentRequest(Document):
else:
payment_entry = self.create_payment_entry()
self.make_invoice()
if self.make_sales_invoice:
self.make_invoice()
return payment_entry
@@ -343,6 +240,17 @@ class PaymentRequest(Document):
payment_entry.received_amount = amount
payment_entry.get("references")[0].allocated_amount = amount
# Update 'Paid Amount' on Forex transactions
if self.currency != ref_doc.company_currency:
if (
self.payment_request_type == "Outward"
and payment_entry.paid_from_account_currency == ref_doc.company_currency
and payment_entry.paid_from_account_currency != payment_entry.paid_to_account_currency
):
payment_entry.paid_amount = payment_entry.base_paid_amount = (
payment_entry.target_exchange_rate * payment_entry.received_amount
)
for dimension in get_accounting_dimensions():
payment_entry.update({dimension: self.get(dimension)})
@@ -369,7 +277,14 @@ class PaymentRequest(Document):
)
],
}
enqueue(method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args)
enqueue(
method=frappe.sendmail,
queue="short",
timeout=300,
is_async=True,
enqueue_after_commit=True,
**email_args,
)
def get_message(self):
"""return message with payment gateway link"""
@@ -412,15 +327,8 @@ class PaymentRequest(Document):
)
comm.insert(ignore_permissions=True)
def get_payment_success_url(self):
return self.payment_success_url
def create_subscription(self, payment_provider, gateway_controller, data):
if payment_provider == "stripe":
with payment_app_import_guard():
from payments.payment_gateways.stripe_integration import create_stripe_subscription
return create_stripe_subscription(gateway_controller, data)
def create_subscription(self, *args, **kwargs):
return v1_create_subscription(*args, **kwargs)
@frappe.whitelist(allow_guest=True)
@@ -428,7 +336,9 @@ def make_payment_request(**args):
"""Make payment request"""
args = frappe._dict(args)
if args.dt not in [
ref_doc = args.ref_doc or frappe.get_doc(args.dt, args.dn)
if ref_doc.doctype not in [
"Sales Order",
"Purchase Order",
"Sales Invoice",
@@ -436,22 +346,23 @@ def make_payment_request(**args):
"POS Invoice",
"Fees",
]:
frappe.throw(_("Payment Requests cannot be created against: {0}").format(frappe.bold(args.dt)))
frappe.throw(
_("Payment Requests cannot be created against: {0}").format(frappe.bold(ref_doc.doctype))
)
ref_doc = frappe.get_doc(args.dt, args.dn)
gateway_account = get_gateway_details(args) or frappe._dict()
grand_total = get_amount(ref_doc, gateway_account.get("payment_account"))
if not grand_total:
frappe.throw(_("Payment Entry is already created"))
if args.loyalty_points and args.dt == "Sales Order":
if args.loyalty_points and ref_doc.doctype == "Sales Order":
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
loyalty_amount = validate_loyalty_points(ref_doc, int(args.loyalty_points))
frappe.db.set_value(
"Sales Order", args.dn, "loyalty_points", int(args.loyalty_points), update_modified=False
)
frappe.db.set_value("Sales Order", args.dn, "loyalty_amount", loyalty_amount, update_modified=False)
loyalty_amount: Document = validate_loyalty_points(
ref_doc, int(args.loyalty_points)
) # sets fields on ref_doc
loyalty_amount.db_update()
grand_total = grand_total - loyalty_amount
bank_account = (
@@ -460,10 +371,10 @@ def make_payment_request(**args):
draft_payment_request = frappe.db.get_value(
"Payment Request",
{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": 0},
{"reference_doctype": ref_doc.doctype, "reference_name": ref_doc.name, "docstatus": 0},
)
existing_payment_request_amount = get_existing_payment_request_amount(args.dt, args.dn)
existing_payment_request_amount = get_existing_payment_request_amount(ref_doc.doctype, ref_doc.name)
if existing_payment_request_amount:
grand_total -= existing_payment_request_amount
@@ -494,11 +405,21 @@ def make_payment_request(**args):
"email_to": args.recipient_id or ref_doc.owner,
"subject": _("Payment Request for {0}").format(args.dn),
"message": gateway_account.get("message") or get_dummy_message(ref_doc),
"reference_doctype": args.dt,
"reference_name": args.dn,
"reference_doctype": ref_doc.doctype,
"reference_name": ref_doc.name,
"company": ref_doc.get("company"),
"party_type": args.get("party_type") or "Customer",
"party": args.get("party") or ref_doc.get("customer"),
"bank_account": bank_account,
"make_sales_invoice": (
args.make_sales_invoice # new standard
or args.order_type == "Shopping Cart" # compat for webshop app
),
"mute_email": (
args.mute_email # new standard
or args.order_type == "Shopping Cart" # compat for webshop app
or gateway_account.get("payment_channel", "Email") != "Email"
),
}
)
@@ -513,17 +434,15 @@ def make_payment_request(**args):
for dimension in get_accounting_dimensions():
pr.update({dimension: ref_doc.get(dimension)})
if args.order_type == "Shopping Cart" or args.mute_email:
pr.flags.mute_email = True
pr.insert(ignore_permissions=True)
if frappe.db.get_single_value("Accounts Settings", "create_pr_in_draft_status", cache=True):
pr.insert(ignore_permissions=True)
if args.submit_doc:
pr.submit()
if args.order_type == "Shopping Cart":
frappe.db.commit()
frappe.local.response["type"] = "redirect"
frappe.local.response["location"] = pr.get_payment_url()
frappe.local.response["location"] = pr.payment_url
if args.return_doc:
return pr
@@ -556,7 +475,10 @@ def get_amount(ref_doc, payment_account=None):
elif dt == "Fees":
grand_total = ref_doc.outstanding_amount
return grand_total
if grand_total > 0:
return flt(grand_total, get_currency_precision())
else:
frappe.throw(_("Payment Entry is already created"))
def get_existing_payment_request_amount(ref_dt, ref_dn):
@@ -586,19 +508,14 @@ def get_gateway_details(args): # nosemgrep
Return gateway and payment account of default payment gateway
"""
gateway_account = args.get("payment_gateway_account", {"is_default": 1})
if gateway_account:
return get_payment_gateway_account(gateway_account)
gateway_account = get_payment_gateway_account({"is_default": 1})
return gateway_account
return get_payment_gateway_account(gateway_account)
def get_payment_gateway_account(args):
def get_payment_gateway_account(filter):
return frappe.db.get_value(
"Payment Gateway Account",
args,
["name", "payment_gateway", "payment_account", "message"],
filter,
["name", "payment_gateway", "payment_account", "payment_channel", "message"],
as_dict=1,
)

View File

@@ -2,18 +2,27 @@
# See license.txt
import unittest
from unittest.mock import patch
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.setup.utils import get_exchange_rate
test_dependencies = ["Currency Exchange", "Journal Entry", "Contact", "Address"]
payment_gateway = {"doctype": "Payment Gateway", "gateway": "_Test Gateway"}
PAYMENT_URL = "https://example.com/payment"
payment_gateways = [
{"doctype": "Payment Gateway", "gateway": "_Test Gateway"},
{"doctype": "Payment Gateway", "gateway": "_Test Gateway Phone"},
{"doctype": "Payment Gateway", "gateway": "_Test Gateway Other"},
]
payment_method = [
{
@@ -29,13 +38,28 @@ payment_method = [
"payment_account": "_Test Bank USD - _TC",
"currency": "USD",
},
{
"doctype": "Payment Gateway Account",
"payment_gateway": "_Test Gateway Other",
"payment_account": "_Test Bank USD - _TC",
"payment_channel": "Other",
"currency": "USD",
},
{
"doctype": "Payment Gateway Account",
"payment_gateway": "_Test Gateway Phone",
"payment_account": "_Test Bank USD - _TC",
"payment_channel": "Phone",
"currency": "USD",
},
]
class TestPaymentRequest(unittest.TestCase):
class TestPaymentRequest(FrappeTestCase):
def setUp(self):
if not frappe.db.get_value("Payment Gateway", payment_gateway["gateway"], "name"):
frappe.get_doc(payment_gateway).insert(ignore_permissions=True)
for payment_gateway in payment_gateways:
if not frappe.db.get_value("Payment Gateway", payment_gateway["gateway"], "name"):
frappe.get_doc(payment_gateway).insert(ignore_permissions=True)
for method in payment_method:
if not frappe.db.get_value(
@@ -45,6 +69,28 @@ class TestPaymentRequest(unittest.TestCase):
):
frappe.get_doc(method).insert(ignore_permissions=True)
send_email = patch(
"erpnext.accounts.doctype.payment_request.payment_request.PaymentRequest.send_email",
return_value=None,
)
self.send_email = send_email.start()
self.addCleanup(send_email.stop)
get_payment_url = patch(
# this also shadows one (1) call to _get_payment_gateway_controller
"erpnext.accounts.doctype.payment_request.payment_request.PaymentRequest.get_payment_url",
return_value=PAYMENT_URL,
)
self.get_payment_url = get_payment_url.start()
self.addCleanup(get_payment_url.stop)
_get_payment_gateway_controller = patch(
"erpnext.accounts.doctype.payment_request.payment_request._get_payment_gateway_controller",
)
self._get_payment_gateway_controller = _get_payment_gateway_controller.start()
self.addCleanup(_get_payment_gateway_controller.stop)
def tearDown(self):
frappe.db.rollback()
def test_payment_request_linkings(self):
so_inr = make_sales_order(currency="INR", do_not_save=True)
so_inr.disable_rounded_total = 1
@@ -75,6 +121,99 @@ class TestPaymentRequest(unittest.TestCase):
self.assertEqual(pr.reference_name, si_usd.name)
self.assertEqual(pr.currency, "USD")
def test_payment_channels(self):
so = make_sales_order(currency="USD")
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway Other - USD",
submit_doc=True,
return_doc=True,
)
self.assertEqual(pr.payment_channel, "Other")
self.assertEqual(pr.mute_email, True)
self.assertEqual(pr.payment_url, PAYMENT_URL)
self.assertEqual(self.send_email.call_count, 0)
self.assertEqual(self._get_payment_gateway_controller.call_count, 1)
pr.cancel()
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway - USD", # email channel
submit_doc=False,
return_doc=True,
)
pr.flags.mute_email = True # but temporarily prohibit sending
pr.submit()
pr.reload()
self.assertEqual(pr.payment_channel, "Email")
self.assertEqual(pr.mute_email, False)
self.assertEqual(pr.payment_url, PAYMENT_URL)
self.assertEqual(self.send_email.call_count, 0) # hence: no increment
self.assertEqual(self._get_payment_gateway_controller.call_count, 2)
pr.cancel()
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway Phone - USD",
submit_doc=True,
return_doc=True,
)
pr.reload()
self.assertEqual(pr.payment_channel, "Phone")
self.assertEqual(pr.mute_email, True)
self.assertIsNone(pr.payment_url)
self.assertEqual(self.send_email.call_count, 0) # no increment on phone channel
self.assertEqual(self._get_payment_gateway_controller.call_count, 3)
pr.cancel()
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway - USD", # email channel
submit_doc=True,
return_doc=True,
)
pr.reload()
self.assertEqual(pr.payment_channel, "Email")
self.assertEqual(pr.mute_email, False)
self.assertEqual(pr.payment_url, PAYMENT_URL)
self.assertEqual(self.send_email.call_count, 1) # increment on normal email channel
self.assertEqual(self._get_payment_gateway_controller.call_count, 4)
pr.cancel()
so = make_sales_order(currency="USD", do_not_save=True)
# no-op; for optical consistency with how a webshop SO would look like
so.order_type = "Shopping Cart"
so.save()
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
payment_gateway_account="_Test Gateway - USD", # email channel
make_sales_invoice=True,
mute_email=True,
submit_doc=True,
return_doc=True,
)
pr.reload()
self.assertEqual(pr.payment_channel, "Email")
self.assertEqual(pr.mute_email, True)
self.assertEqual(pr.payment_url, PAYMENT_URL)
self.assertEqual(self.send_email.call_count, 1) # no increment on shopping cart
self.assertEqual(self._get_payment_gateway_controller.call_count, 5)
pr.cancel()
def test_payment_entry_against_purchase_invoice(self):
si_usd = make_purchase_invoice(
customer="_Test Supplier USD",
@@ -260,3 +399,19 @@ class TestPaymentRequest(unittest.TestCase):
# Try to make Payment Request more than SO amount, should give validation
pr2.grand_total = 900
self.assertRaises(frappe.ValidationError, pr2.save)
def test_conversion_on_foreign_currency_accounts(self):
po_doc = create_purchase_order(supplier="_Test Supplier USD", currency="USD", do_not_submit=1)
po_doc.conversion_rate = 80
po_doc.items[0].qty = 1
po_doc.items[0].rate = 10
po_doc.save().submit()
pr = make_payment_request(dt=po_doc.doctype, dn=po_doc.name, recipient_id="nabin@erpnext.com")
pr = frappe.get_doc(pr).save().submit()
pe = pr.create_payment_entry()
self.assertEqual(pe.base_paid_amount, 800)
self.assertEqual(pe.paid_amount, 800)
self.assertEqual(pe.base_received_amount, 800)
self.assertEqual(pe.received_amount, 10)

View File

@@ -136,18 +136,28 @@ class PeriodClosingVoucher(AccountsController):
def check_if_previous_year_closed(self):
last_year_closing = add_days(self.year_start_date, -1)
previous_fiscal_year = get_fiscal_year(last_year_closing, company=self.company, boolean=True)
if not previous_fiscal_year:
return
if previous_fiscal_year and not frappe.db.exists(
previous_fiscal_year_start_date = previous_fiscal_year[0][1]
if not frappe.db.exists(
"GL Entry",
{"posting_date": ("<=", last_year_closing), "company": self.company, "is_cancelled": 0},
{
"posting_date": ("between", [previous_fiscal_year_start_date, last_year_closing]),
"company": self.company,
"is_cancelled": 0,
},
):
return
if previous_fiscal_year and not frappe.db.exists(
if not frappe.db.exists(
"Period Closing Voucher",
{"posting_date": ("<=", last_year_closing), "docstatus": 1, "company": self.company},
{
"posting_date": ("between", [previous_fiscal_year_start_date, last_year_closing]),
"docstatus": 1,
"company": self.company,
},
):
frappe.throw(_("Previous Year is not closed, please close it first"))

View File

@@ -70,7 +70,7 @@ class POSClosingEntry(StatusUpdater):
for key, value in pos_occurences.items():
if len(value) > 1:
error_list.append(
_(f"{frappe.bold(key)} is added multiple times on rows: {frappe.bold(value)}")
_("{0} is added multiple times on rows: {1}").format(frappe.bold(key), frappe.bold(value))
)
if error_list:
@@ -87,19 +87,15 @@ class POSClosingEntry(StatusUpdater):
as_dict=1,
)[0]
if pos_invoice.consolidated_invoice:
invalid_row.setdefault("msg", []).append(
_("POS Invoice is {}").format(frappe.bold("already consolidated"))
)
invalid_row.setdefault("msg", []).append(_("POS Invoice is already consolidated"))
invalid_rows.append(invalid_row)
continue
if pos_invoice.pos_profile != self.pos_profile:
invalid_row.setdefault("msg", []).append(
_("POS Profile doesn't matches {}").format(frappe.bold(self.pos_profile))
_("POS Profile doesn't match {}").format(frappe.bold(self.pos_profile))
)
if pos_invoice.docstatus != 1:
invalid_row.setdefault("msg", []).append(
_("POS Invoice is not {}").format(frappe.bold("submitted"))
)
invalid_row.setdefault("msg", []).append(_("POS Invoice is not submitted"))
if pos_invoice.owner != self.user:
invalid_row.setdefault("msg", []).append(
_("POS Invoice isn't created by user {}").format(frappe.bold(self.owner))

View File

@@ -17,6 +17,10 @@ from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_inv
from erpnext.accounts.doctype.pos_opening_entry.test_pos_opening_entry import create_opening_entry
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
from erpnext.selling.page.point_of_sale.point_of_sale import get_items
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle import (
get_batch_from_bundle,
)
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
@@ -179,6 +183,94 @@ class TestPOSClosingEntry(unittest.TestCase):
accounting_dimension_department.save()
disable_dimension()
def test_merging_into_sales_invoice_for_batched_item(self):
frappe.flags.print_message = False
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import (
init_user_and_profile,
)
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import (
consolidate_pos_invoices,
)
from erpnext.stock.doctype.batch.batch import get_batch_qty
frappe.db.sql("delete from `tabPOS Invoice`")
item_doc = make_item(
"_Test Item With Batch FOR POS Merge Test",
properties={
"is_stock_item": 1,
"has_batch_no": 1,
"batch_number_series": "BATCH-PM-POS-MERGE-.####",
"create_new_batch": 1,
},
)
item_code = item_doc.name
se = make_stock_entry(
target="_Test Warehouse - _TC",
item_code=item_code,
qty=10,
basic_rate=100,
use_serial_batch_fields=0,
)
batch_no = get_batch_from_bundle(se.items[0].serial_and_batch_bundle)
test_user, pos_profile = init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name)
pos_inv = create_pos_invoice(
item_code=item_code, qty=5, rate=300, use_serial_batch_fields=1, batch_no=batch_no
)
pos_inv2 = create_pos_invoice(
item_code=item_code, qty=5, rate=300, use_serial_batch_fields=1, batch_no=batch_no
)
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)
pcv_doc = make_closing_entry_from_opening(opening_entry)
pcv_doc.submit()
piv_merge = frappe.db.get_value("POS Invoice Merge Log", {"pos_closing_entry": pcv_doc.name}, "name")
self.assertTrue(piv_merge)
piv_merge_doc = frappe.get_doc("POS Invoice Merge Log", piv_merge)
self.assertTrue(piv_merge_doc.pos_invoices[0].pos_invoice)
self.assertTrue(piv_merge_doc.pos_invoices[1].pos_invoice)
pos_inv.load_from_db()
self.assertTrue(pos_inv.consolidated_invoice)
pos_inv2.load_from_db()
self.assertTrue(pos_inv2.consolidated_invoice)
batch_qty = frappe.db.get_value("Batch", batch_no, "batch_qty")
self.assertEqual(batch_qty, 0.0)
batch_qty_with_pos = get_batch_qty(batch_no, "_Test Warehouse - _TC", item_code)
self.assertEqual(batch_qty_with_pos, 0.0)
frappe.flags.print_message = True
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)
pos_inv.reload()
pos_inv2.reload()
pos_inv.cancel()
pos_inv2.cancel()
batch_qty_with_pos = get_batch_qty(batch_no, "_Test Warehouse - _TC", item_code)
self.assertEqual(batch_qty_with_pos, 10.0)
def init_user_and_profile(**args):
user = "test@example.com"

View File

@@ -188,7 +188,7 @@ class POSInvoice(SalesInvoice):
def validate(self):
if not cint(self.is_pos):
frappe.throw(
_("POS Invoice should have {} field checked.").format(frappe.bold("Include Payment"))
_("POS Invoice should have the field {0} checked.").format(frappe.bold(_("Include Payment")))
)
# run on validate method of selling controller
@@ -228,7 +228,10 @@ class POSInvoice(SalesInvoice):
self.apply_loyalty_points()
self.check_phone_payments()
self.set_status(update=True)
self.submit_serial_batch_bundle()
self.make_bundle_for_sales_purchase_return()
for table_name in ["items", "packed_items"]:
self.make_bundle_using_old_serial_batch_fields(table_name)
self.submit_serial_batch_bundle(table_name)
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
@@ -282,10 +285,11 @@ class POSInvoice(SalesInvoice):
{"is_cancelled": 1, "voucher_no": ""},
)
frappe.get_doc("Serial and Batch Bundle", row.serial_and_batch_bundle).cancel()
row.db_set("serial_and_batch_bundle", None)
def submit_serial_batch_bundle(self):
for item in self.items:
def submit_serial_batch_bundle(self, table_name):
for item in self.get(table_name):
if item.serial_and_batch_bundle:
doc = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle)
@@ -354,10 +358,16 @@ class POSInvoice(SalesInvoice):
error_msg = []
for d in self.get("items"):
error_msg = ""
if d.get("has_serial_no") and not d.serial_and_batch_bundle:
if d.get("has_serial_no") and (
(not d.use_serial_batch_fields and not d.serial_and_batch_bundle)
or (d.use_serial_batch_fields and not d.serial_no)
):
error_msg = f"Row #{d.idx}: Please select Serial No. for item {bold(d.item_code)}"
elif d.get("has_batch_no") and not d.serial_and_batch_bundle:
elif d.get("has_batch_no") and (
(not d.use_serial_batch_fields and not d.serial_and_batch_bundle)
or (d.use_serial_batch_fields and not d.batch_no)
):
error_msg = f"Row #{d.idx}: Please select Batch No. for item {bold(d.item_code)}"
if error_msg:

View File

@@ -318,29 +318,28 @@ class TestPOSInvoice(unittest.TestCase):
pos.insert()
pos.submit()
pos.reload()
pos_return1 = make_sales_return(pos.name)
# partial return 1
pos_return1.get("items")[0].qty = -1
pos_return1.submit()
pos_return1.reload()
bundle_id = frappe.get_doc(
"Serial and Batch Bundle", pos_return1.get("items")[0].serial_and_batch_bundle
)
bundle_id.remove(bundle_id.entries[1])
bundle_id.save()
bundle_id.load_from_db()
serial_no = bundle_id.entries[0].serial_no
self.assertEqual(serial_no, serial_nos[0])
pos_return1.insert()
pos_return1.submit()
# partial return 2
pos_return2 = make_sales_return(pos.name)
pos_return2.submit()
self.assertEqual(pos_return2.get("items")[0].qty, -1)
serial_no = get_serial_nos_from_bundle(pos_return2.get("items")[0].serial_and_batch_bundle)[0]
self.assertEqual(serial_no, serial_nos[1])
@@ -781,8 +780,6 @@ class TestPOSInvoice(unittest.TestCase):
pos_inv1.submit()
pos_inv1.reload()
self.assertFalse(pos_inv1.items[0].serial_and_batch_bundle)
batches = get_auto_batch_nos(
frappe._dict({"item_code": "_BATCH ITEM Test For Reserve", "warehouse": "_Test Warehouse - _TC"})
)
@@ -958,7 +955,7 @@ def create_pos_invoice(**args):
pos_inv.set_missing_values()
bundle_id = None
if args.get("batch_no") or args.get("serial_no"):
if not args.use_serial_batch_fields and (args.get("batch_no") or args.get("serial_no")):
type_of_transaction = args.type_of_transaction or "Outward"
if pos_inv.is_return:
@@ -999,6 +996,9 @@ def create_pos_invoice(**args):
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_and_batch_bundle": bundle_id,
"use_serial_batch_fields": args.use_serial_batch_fields,
"serial_no": args.serial_no if args.use_serial_batch_fields else None,
"batch_no": args.batch_no if args.use_serial_batch_fields else None,
}
# append in pos invoice items without item_code by checking flag without_item_code
if args.without_item_code:
@@ -1024,6 +1024,8 @@ def create_pos_invoice(**args):
pos_inv.insert()
if not args.do_not_submit:
pos_inv.submit()
if args.use_serial_batch_fields:
pos_inv.reload()
else:
pos_inv.payment_schedule = []
else:

View File

@@ -37,6 +37,7 @@
"column_break_19",
"discount_percentage",
"discount_amount",
"distributed_discount_amount",
"base_rate_with_margin",
"section_break1",
"rate",
@@ -634,7 +635,6 @@
"depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
"hidden": 1,
"label": "Batch No",
"options": "Batch",
"print_hide": 1
@@ -655,7 +655,6 @@
"depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Text",
"hidden": 1,
"in_list_view": 1,
"label": "Serial No",
"oldfieldname": "serial_no",
@@ -827,7 +826,7 @@
"read_only": 1
},
{
"depends_on": "eval:doc.use_serial_batch_fields === 1",
"depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.serial_and_batch_bundle",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
@@ -849,11 +848,17 @@
{
"fieldname": "column_break_ciit",
"fieldtype": "Column Break"
},
{
"fieldname": "distributed_discount_amount",
"fieldtype": "Currency",
"label": "Distributed Discount Amount",
"options": "currency"
}
],
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:15.336778",
"modified": "2024-05-07 15:56:53.343317",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice Item",

View File

@@ -39,6 +39,7 @@ class POSInvoiceItem(SalesInvoiceItem):
description: DF.TextEditor
discount_amount: DF.Currency
discount_percentage: DF.Percent
distributed_discount_amount: DF.Currency
dn_detail: DF.Data | None
enable_deferred_revenue: DF.Check
expense_account: DF.Link | None

View File

@@ -54,7 +54,7 @@ class POSInvoiceMergeLog(Document):
for key, value in pos_occurences.items():
if len(value) > 1:
error_list.append(
_(f"{frappe.bold(key)} is added multiple times on rows: {frappe.bold(value)}")
_("{0} is added multiple times on rows: {1}").format(frappe.bold(key), frappe.bold(value))
)
if error_list:
@@ -97,16 +97,15 @@ class POSInvoiceMergeLog(Document):
return_against_status = frappe.db.get_value("POS Invoice", return_against, "status")
if return_against_status != "Consolidated":
# if return entry is not getting merged in the current pos closing and if it is not consolidated
bold_unconsolidated = frappe.bold("not Consolidated")
msg = _("Row #{}: Original Invoice {} of return invoice {} is {}.").format(
d.idx, bold_return_against, bold_pos_invoice, bold_unconsolidated
)
msg = _(
"Row #{}: The original Invoice {} of return invoice {} is not consolidated."
).format(d.idx, bold_return_against, bold_pos_invoice)
msg += " "
msg += _(
"Original invoice should be consolidated before or along with the return invoice."
"The original invoice should be consolidated before or along with the return invoice."
)
msg += "<br><br>"
msg += _("You can add original invoice {} manually to proceed.").format(
msg += _("You can add the original invoice {} manually to proceed.").format(
bold_return_against
)
frappe.throw(msg)
@@ -131,6 +130,7 @@ class POSInvoiceMergeLog(Document):
pos_invoice_docs = [frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices]
self.update_pos_invoices(pos_invoice_docs)
self.serial_and_batch_bundle_reference_for_pos_invoice()
self.cancel_linked_invoices()
def process_merging_into_sales_invoice(self, data):
@@ -191,6 +191,7 @@ class POSInvoiceMergeLog(Document):
for i in items:
if (
i.item_code == item.item_code
and not i.serial_and_batch_bundle
and not i.serial_no
and not i.batch_no
and i.uom == item.uom
@@ -312,6 +313,12 @@ class POSInvoiceMergeLog(Document):
doc.set_status(update=True)
doc.save()
def serial_and_batch_bundle_reference_for_pos_invoice(self):
for d in self.pos_invoices:
pos_invoice = frappe.get_doc("POS Invoice", d.pos_invoice)
for table_name in ["items", "packed_items"]:
pos_invoice.set_serial_and_batch_bundle(table_name)
def cancel_linked_invoices(self):
for si_name in [self.consolidated_invoice, self.consolidated_credit_note]:
if not si_name:
@@ -392,7 +399,7 @@ def unconsolidate_pos_invoices(closing_entry):
"POS Invoice Merge Log", filters={"pos_closing_entry": closing_entry.name}, pluck="name"
)
if len(merge_logs) >= 10:
if len(closing_entry.pos_transactions) >= 10:
closing_entry.set_status(update=True, status="Queued")
enqueue_job(cancel_merge_logs, merge_logs=merge_logs, closing_entry=closing_entry)
else:
@@ -481,7 +488,7 @@ def create_merge_logs(invoice_by_customer, closing_entry=None):
if closing_entry:
closing_entry.set_status(update=True, status="Failed")
if isinstance(error_message, list):
error_message = frappe.json.dumps(error_message)
error_message = json.dumps(error_message)
closing_entry.db_set("error_message", error_message)
raise

View File

@@ -74,15 +74,21 @@
"discount_amount",
"discount_percentage",
"for_price_list",
"section_break_13",
"threshold_percentage",
"priority",
"dynamic_condition_tab",
"condition",
"column_break_66",
"section_break_13",
"apply_multiple_pricing_rules",
"apply_discount_on_rate",
"column_break_66",
"threshold_percentage",
"validate_pricing_rule_section",
"validate_applied_rule",
"column_break_texp",
"rule_description",
"priority_section",
"has_priority",
"column_break_sayg",
"priority",
"help_section",
"pricing_rule_help",
"reference_section",
@@ -477,7 +483,7 @@
{
"collapsible": 1,
"fieldname": "section_break_13",
"fieldtype": "Section Break",
"fieldtype": "Tab Break",
"label": "Advanced Settings"
},
{
@@ -487,6 +493,7 @@
"label": "Threshold for Suggestion (In Percentage)"
},
{
"depends_on": "has_priority",
"description": "Higher the number, higher the priority",
"fieldname": "priority",
"fieldtype": "Select",
@@ -513,6 +520,7 @@
{
"default": "0",
"depends_on": "eval:doc.price_or_product_discount == 'Price'",
"description": "If enabled, then system will only validate the pricing rule and not apply automatically. User has to manually set the discount percentage / margin / free items to validate the pricing rule",
"fieldname": "validate_applied_rule",
"fieldtype": "Check",
"label": "Validate Applied Rule"
@@ -525,7 +533,8 @@
},
{
"fieldname": "help_section",
"fieldtype": "Section Break",
"fieldtype": "Tab Break",
"label": "Help Article",
"options": "Simple"
},
{
@@ -603,12 +612,42 @@
"fieldname": "apply_recursion_over",
"fieldtype": "Float",
"label": "Apply Recursion Over (As Per Transaction UOM)"
},
{
"fieldname": "priority_section",
"fieldtype": "Section Break",
"label": "Priority"
},
{
"fieldname": "dynamic_condition_tab",
"fieldtype": "Tab Break",
"label": "Dynamic Condition"
},
{
"fieldname": "validate_pricing_rule_section",
"fieldtype": "Section Break",
"label": "Validate Pricing Rule"
},
{
"fieldname": "column_break_texp",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_sayg",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "Enable this checkbox even if you want to set the zero priority",
"fieldname": "has_priority",
"fieldtype": "Check",
"label": "Has Priority"
}
],
"icon": "fa fa-gift",
"idx": 1,
"links": [],
"modified": "2024-03-27 13:10:17.521896",
"modified": "2024-05-17 13:16:34.496704",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",

View File

@@ -27,9 +27,7 @@ class PricingRule(Document):
from frappe.types import DF
from erpnext.accounts.doctype.pricing_rule_brand.pricing_rule_brand import PricingRuleBrand
from erpnext.accounts.doctype.pricing_rule_item_code.pricing_rule_item_code import (
PricingRuleItemCode,
)
from erpnext.accounts.doctype.pricing_rule_item_code.pricing_rule_item_code import PricingRuleItemCode
from erpnext.accounts.doctype.pricing_rule_item_group.pricing_rule_item_group import (
PricingRuleItemGroup,
)
@@ -67,6 +65,7 @@ class PricingRule(Document):
free_item_rate: DF.Currency
free_item_uom: DF.Link | None
free_qty: DF.Float
has_priority: DF.Check
is_cumulative: DF.Check
is_recursive: DF.Check
item_groups: DF.Table[PricingRuleItemGroup]
@@ -140,6 +139,7 @@ class PricingRule(Document):
self.validate_price_list_with_currency()
self.validate_dates()
self.validate_condition()
self.validate_mixed_with_recursion()
if not self.margin_type:
self.margin_rate_or_amount = 0.0
@@ -156,6 +156,12 @@ class PricingRule(Document):
frappe.throw(_("Duplicate {0} found in the table").format(self.apply_on))
def validate_mandatory(self):
if self.has_priority and not self.priority:
throw(_("Priority is mandatory"), frappe.MandatoryError, _("Please Set Priority"))
if self.priority and not self.has_priority:
self.has_priority = 1
for apply_on, field in apply_on_dict.items():
if self.apply_on == apply_on and len(self.get(field) or []) < 1:
throw(_("{0} is not added in the table").format(apply_on), frappe.MandatoryError)
@@ -180,7 +186,8 @@ class PricingRule(Document):
if not self.priority:
throw(
_("As the field {0} is enabled, the field {1} is mandatory.").format(
frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")
frappe.bold(_("Apply Discount on Discounted Rate")),
frappe.bold(_("Priority")),
)
)
@@ -188,7 +195,7 @@ class PricingRule(Document):
throw(
_(
"As the field {0} is enabled, the value of the field {1} should be more than 1."
).format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority"))
).format(frappe.bold(_("Apply Discount on Discounted Rate")), frappe.bold(_("Priority")))
)
def validate_applicable_for_selling_or_buying(self):
@@ -303,6 +310,10 @@ class PricingRule(Document):
):
frappe.throw(_("Invalid condition expression"))
def validate_mixed_with_recursion(self):
if self.mixed_conditions and self.is_recursive:
frappe.throw(_("Recursive Discounts with Mixed condition is not supported by the system"))
# --------------------------------------------------------------------------------
@@ -573,6 +584,22 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
if pricing_rule.apply_discount_on_rate and item_details.get("discount_percentage"):
# Apply discount on discounted rate
item_details[field] += (100 - item_details[field]) * (pricing_rule.get(field, 0) / 100)
elif args.price_list_rate:
value = pricing_rule.get(field, 0)
calculate_discount_percentage = False
if field == "discount_percentage":
field = "discount_amount"
value = args.price_list_rate * (value / 100)
calculate_discount_percentage = True
if field not in item_details:
item_details.setdefault(field, 0)
item_details[field] += value if pricing_rule else args.get(field, 0)
if calculate_discount_percentage and args.price_list_rate and item_details.discount_amount:
item_details.discount_percentage = flt(
(flt(item_details.discount_amount) / flt(args.price_list_rate)) * 100
)
else:
if field not in item_details:
item_details.setdefault(field, 0)

View File

@@ -6,7 +6,9 @@ import unittest
import frappe
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.controllers.sales_and_purchase_return import make_return_doc
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.get_item_details import get_item_details
@@ -929,6 +931,30 @@ class TestPricingRule(unittest.TestCase):
for doc in [si, si1]:
doc.delete()
def test_pricing_rule_for_transaction_with_condition(self):
make_item("PR Transaction Condition")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
make_pricing_rule(
selling=1,
min_qty=0,
price_or_product_discount="Product",
apply_on="Transaction",
free_item="PR Transaction Condition",
free_qty=1,
free_item_rate=10,
condition="customer=='_Test Customer 1'",
)
si = create_sales_invoice(qty=5, customer="_Test Customer 1", do_not_submit=True)
self.assertEqual(len(si.items), 2)
self.assertEqual(si.items[1].rate, 10)
si1 = create_sales_invoice(qty=5, customer="_Test Customer 2", do_not_submit=True)
self.assertEqual(len(si1.items), 1)
for doc in [si, si1]:
doc.delete()
def test_remove_pricing_rule(self):
item = make_item("Water Flask")
make_item_price("Water Flask", "_Test Price List", 100)
@@ -1102,7 +1128,253 @@ class TestPricingRule(unittest.TestCase):
so.load_from_db()
self.assertEqual(so.items[1].is_free_item, 1)
self.assertEqual(so.items[1].item_code, "_Test Item")
self.assertEqual(so.items[1].qty, 4)
self.assertEqual(so.items[1].qty, 3)
def test_apply_multiple_pricing_rules_for_discount_percentage_and_amount(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule 1",
"name": "_Test Pricing Rule 1",
"apply_on": "Item Code",
"currency": "USD",
"items": [
{
"item_code": "_Test Item",
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Discount Percentage",
"discount_percentage": 10,
"apply_multiple_pricing_rules": 1,
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule 2",
"name": "_Test Pricing Rule 2",
"apply_on": "Item Code",
"currency": "USD",
"items": [
{
"item_code": "_Test Item",
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Discount Amount",
"discount_amount": 100,
"apply_multiple_pricing_rules": 1,
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
so = make_sales_order(item_code="_Test Item", qty=1, price_list_rate=1000, do_not_submit=True)
self.assertEqual(so.items[0].discount_amount, 200)
self.assertEqual(so.items[0].rate, 800)
frappe.delete_doc_if_exists("Sales Order", so.name)
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
def test_priority_of_multiple_pricing_rules(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule 1",
"name": "_Test Pricing Rule 1",
"apply_on": "Item Code",
"currency": "USD",
"items": [
{
"item_code": "_Test Item",
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Discount Percentage",
"discount_percentage": 10,
"has_priority": 1,
"priority": 1,
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule 2",
"name": "_Test Pricing Rule 2",
"apply_on": "Item Code",
"currency": "USD",
"items": [
{
"item_code": "_Test Item",
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Discount Percentage",
"discount_percentage": 20,
"has_priority": 1,
"priority": 3,
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
so = make_sales_order(item_code="_Test Item", qty=1, price_list_rate=1000, do_not_submit=True)
self.assertEqual(so.items[0].discount_percentage, 20)
self.assertEqual(so.items[0].rate, 800)
frappe.delete_doc_if_exists("Sales Order", so.name)
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
def test_pricing_rules_with_and_without_apply_multiple(self):
item = make_item("PR Item 99")
test_records = [
{
"doctype": "Pricing Rule",
"title": "_Test discount on item group",
"name": "_Test discount on item group",
"apply_on": "Item Group",
"item_groups": [
{
"item_group": "Products",
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Discount Percentage",
"discount_percentage": 60,
"has_priority": 1,
"company": "_Test Company",
"apply_multiple_pricing_rules": True,
},
{
"doctype": "Pricing Rule",
"title": "_Test fixed rate on item code",
"name": "_Test fixed rate on item code",
"apply_on": "Item Code",
"items": [
{
"item_code": item.name,
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Rate",
"rate": 25,
"has_priority": 1,
"company": "_Test Company",
"apply_multiple_pricing_rules": False,
},
]
for item_group_priority, item_code_priority in [(2, 4), (4, 2)]:
item_group_rule = frappe.get_doc(test_records[0].copy())
item_group_rule.priority = item_group_priority
item_group_rule.insert()
item_code_rule = frappe.get_doc(test_records[1].copy())
item_code_rule.priority = item_code_priority
item_code_rule.insert()
si = create_sales_invoice(qty=5, customer="_Test Customer 1", item=item.name, do_not_submit=True)
si.save()
self.assertEqual(len(si.pricing_rules), 1)
# Item Code rule should've applied as it has higher priority
expected_rule = item_group_rule if item_group_priority > item_code_priority else item_code_rule
self.assertEqual(si.pricing_rules[0].pricing_rule, expected_rule.name)
si.delete()
item_group_rule.delete()
item_code_rule.delete()
def test_validation_on_mixed_condition_with_recursion(self):
pricing_rule = make_pricing_rule(
discount_percentage=10,
selling=1,
priority=2,
min_qty=4,
title="_Test Pricing Rule with Min Qty - 2",
)
pricing_rule.mixed_conditions = True
pricing_rule.is_recursive = True
self.assertRaises(frappe.ValidationError, pricing_rule.save)
def test_ignore_pricing_rule_for_credit_note(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
pricing_rule = make_pricing_rule(
discount_percentage=20,
selling=1,
buying=1,
priority=1,
title="_Test Pricing Rule",
)
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1)
item = si.items[0]
si.submit()
self.assertEqual(item.discount_percentage, 20)
self.assertEqual(item.rate, 80)
# change discount on pricing rule
pricing_rule.discount_percentage = 30
pricing_rule.save()
credit_note = make_return_doc(si.doctype, si.name)
credit_note.save()
self.assertEqual(credit_note.ignore_pricing_rule, 1)
self.assertEqual(credit_note.pricing_rules, [])
self.assertEqual(credit_note.items[0].discount_percentage, 20)
self.assertEqual(credit_note.items[0].rate, 80)
self.assertEqual(credit_note.items[0].pricing_rules, None)
credit_note.delete()
si.cancel()
def test_ignore_pricing_rule_for_debit_note(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
pricing_rule = make_pricing_rule(
discount_percentage=20,
buying=1,
priority=1,
title="_Test Pricing Rule",
)
pi = make_purchase_invoice(do_not_submit=True, supplier="_Test Supplier 1", qty=1)
item = pi.items[0]
pi.submit()
self.assertEqual(item.discount_percentage, 20)
self.assertEqual(item.rate, 40)
# change discount on pricing rule
pricing_rule.discount_percentage = 30
pricing_rule.save()
# create debit note from purchase invoice
debit_note = make_return_doc(pi.doctype, pi.name)
debit_note.save()
self.assertEqual(debit_note.ignore_pricing_rule, 1)
self.assertEqual(debit_note.pricing_rules, [])
self.assertEqual(debit_note.items[0].discount_percentage, 20)
self.assertEqual(debit_note.items[0].rate, 40)
self.assertEqual(debit_note.items[0].pricing_rules, None)
debit_note.delete()
pi.cancel()
test_dependencies = ["Campaign"]
@@ -1132,6 +1404,7 @@ def make_pricing_rule(**args):
"priority": args.priority or 1,
"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,
}
)

View File

@@ -6,6 +6,7 @@
import copy
import json
import math
import frappe
from frappe import _, bold
@@ -32,6 +33,9 @@ def get_pricing_rules(args, doc=None):
for apply_on in ["Item Code", "Item Group", "Brand"]:
pricing_rules.extend(_get_pricing_rules(apply_on, args, values))
if pricing_rules and pricing_rules[0].has_priority:
continue
if pricing_rules and not apply_multiple_pricing_rules(pricing_rules):
break
@@ -170,12 +174,9 @@ def _get_pricing_rules(apply_on, args, values):
def apply_multiple_pricing_rules(pricing_rules):
apply_multiple_rule = [
d.apply_multiple_pricing_rules for d in pricing_rules if d.apply_multiple_pricing_rules
]
if not apply_multiple_rule:
return False
for d in pricing_rules:
if not d.apply_multiple_pricing_rules:
return False
return True
@@ -485,7 +486,7 @@ def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules, row_item):
continue
stock_qty = row.get("qty") * (row.get("conversion_factor") or 1.0)
amount = stock_qty * (row.get("price_list_rate") or row.get("rate"))
amount = stock_qty * (flt(row.get("price_list_rate")) or flt(row.get("rate")))
pricing_rules = filter_pricing_rules_for_qty_amount(stock_qty, amount, pricing_rules, row)
if pricing_rules and pricing_rules[0]:
@@ -560,6 +561,7 @@ def apply_pricing_rule_on_transaction(doc):
if pricing_rules:
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty, doc.total, pricing_rules)
pricing_rules = filter_pricing_rule_based_on_condition(pricing_rules, doc)
if not pricing_rules:
remove_free_item(doc)
@@ -653,7 +655,7 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
if transaction_qty:
qty = flt(transaction_qty) * qty / pricing_rule.recurse_for
if pricing_rule.round_free_qty:
qty = round(qty)
qty = math.floor(qty)
free_item_data_args = {
"item_code": free_item,
@@ -729,7 +731,7 @@ def validate_coupon_code(coupon_name):
elif coupon.valid_upto:
if coupon.valid_upto < getdate(today()):
frappe.throw(_("Sorry, this coupon code's validity has expired"))
elif coupon.used >= coupon.maximum_use:
elif coupon.maximum_use and coupon.used >= coupon.maximum_use:
frappe.throw(_("Sorry, this coupon code is no longer valid"))
@@ -737,7 +739,10 @@ def update_coupon_code_count(coupon_name, transaction_type):
coupon = frappe.get_doc("Coupon Code", coupon_name)
if coupon:
if transaction_type == "used":
if coupon.used < coupon.maximum_use:
if not coupon.maximum_use:
coupon.used = coupon.used + 1
coupon.save(ignore_permissions=True)
elif coupon.used < coupon.maximum_use:
coupon.used = coupon.used + 1
coupon.save(ignore_permissions=True)
else:

View File

@@ -1,6 +1,8 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import json
import frappe
from frappe import _, qb
from frappe.model.document import Document
@@ -502,7 +504,7 @@ def is_any_doc_running(for_filter: str | dict | None = None) -> str | None:
running_doc = None
if for_filter:
if isinstance(for_filter, str):
for_filter = frappe.json.loads(for_filter)
for_filter = json.loads(for_filter)
running_doc = frappe.db.get_value(
"Process Payment Reconciliation",

View File

@@ -13,7 +13,7 @@
</div>
{% endif %}
</div>
<h2 class="text-center">{{ _("STATEMENTS OF ACCOUNTS") }}</h2>
<h2 class="text-center">{{ _("STATEMENT OF ACCOUNTS") }}</h2>
<div>
{% if filters.party[0] == filters.party_name[0] %}
<h5 style="float: left;">{{ _("Customer: ") }} <b>{{ filters.party_name[0] }}</b></h5>
@@ -22,11 +22,11 @@
<h5 style="float: left; margin-left:15px">{{ _("Customer Name: ") }} <b>{{filters.party_name[0] }}</b></h5>
{% endif %}
<h5 style="float: right;">
{{ _("Date: ") }}
<b>{{ frappe.format(filters.from_date, 'Date')}}
{{ _("to") }}
{{ frappe.format(filters.to_date, 'Date')}}</b>
</h5>
{{ _("Date: {0} to {1}").format(
frappe.format(filters.from_date, "Date"),
frappe.format(filters.to_date, 'Date')
) }}
</h5>
</div>
<br>
@@ -54,7 +54,7 @@
<br>
{% endif %}
<br>{{ _("Remarks") }}: {{ row.remarks }}
<br>{{ _("Remarks:") }} {{ row.remarks }}
{% if row.bill_no %}
<br>{{ _("Supplier Invoice No") }}: {{ row.bill_no }}
{% endif %}
@@ -83,17 +83,20 @@
</table>
<br>
{% if ageing %}
<h4 class="text-center">{{ _("Ageing Report based on ") }} {{ ageing.ageing_based_on }}
{{ _("up to " ) }} {{ frappe.format(filters.to_date, 'Date')}}
<h4 class="text-center">
{{ _("Ageing Report based on {0} up to {1}").format(
ageing.ageing_based_on,
frappe.format(filters.to_date, "Date")
) }}
</h4>
<table class="table table-bordered">
<thead>
<tr>
<th style="width: 20%">0 - 30 Days</th>
<th style="width: 20%">30 - 60 Days</th>
<th style="width: 20%">60 - 90 Days</th>
<th style="width: 20%">90 - 120 Days</th>
<th style="width: 20%">Above 120 Days</th>
<th style="width: 20%">{{ _("0 - 30 Days") }}</th>
<th style="width: 20%">{{ _("30 - 60 Days") }}</th>
<th style="width: 20%">{{ _("60 - 90 Days") }}</th>
<th style="width: 20%">{{ _("90 - 120 Days") }}</th>
<th style="width: 20%">{{ _("Above 120 Days") }}</th>
</tr>
</thead>
<tbody>

View File

@@ -16,6 +16,7 @@
"cost_center",
"territory",
"ignore_exchange_rate_revaluation_journals",
"ignore_cr_dr_notes",
"column_break_14",
"to_date",
"finance_book",
@@ -383,10 +384,16 @@
"fieldname": "ignore_exchange_rate_revaluation_journals",
"fieldtype": "Check",
"label": "Ignore Exchange Rate Revaluation Journals"
},
{
"default": "0",
"fieldname": "ignore_cr_dr_notes",
"fieldtype": "Check",
"label": "Ignore System Generated Credit / Debit Notes"
}
],
"links": [],
"modified": "2024-03-27 13:10:19.075913",
"modified": "2024-08-13 10:41:18.381165",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",

View File

@@ -54,6 +54,7 @@ class ProcessStatementOfAccounts(Document):
frequency: DF.Literal["Weekly", "Monthly", "Quarterly"]
from_date: DF.Date | None
group_by: DF.Literal["", "Group by Voucher", "Group by Voucher (Consolidated)"]
ignore_cr_dr_notes: DF.Check
ignore_exchange_rate_revaluation_journals: DF.Check
include_ageing: DF.Check
include_break: DF.Check
@@ -133,6 +134,9 @@ def get_statement_dict(doc, get_statement_dict=False):
if doc.ignore_exchange_rate_revaluation_journals:
filters.update({"ignore_err": True})
if doc.ignore_cr_dr_notes:
filters.update({"ignore_cr_dr_notes": True})
if doc.report == "General Ledger":
filters.update(get_gl_filters(doc, entry, tax_id, presentation_currency))
col, res = get_soa(filters)
@@ -158,7 +162,7 @@ def set_ageing(doc, entry):
ageing_filters = frappe._dict(
{
"company": doc.company,
"report_date": doc.to_date,
"report_date": doc.posting_date,
"ageing_based_on": doc.ageing_based_on,
"range1": 30,
"range2": 60,

View File

@@ -6,228 +6,302 @@
.print-format td {
vertical-align:middle !important;
}
</style>
</style>
<div id="header-html" class="hidden-pdf">
{% if letter_head.content %}
<div class="letter-head text-center">{{ letter_head.content }}</div>
<hr style="height:2px;border-width:0;color:black;background-color:black;">
{% endif %}
</div>
<div id="footer-html" class="visible-pdf">
{% if letter_head.footer %}
<div class="letter-head-footer">
<hr style="border-width:0;color:black;background-color:black;padding-bottom:2px;">
{{ letter_head.footer }}
</div>
{% endif %}
</div>
<h2 class="text-center" style="margin-top:0">{{ _(report.report_name) }}</h2>
<h4 class="text-center">
{{ filters.customer_name }}
</h4>
<h6 class="text-center">
{% if (filters.tax_id) %}
{{ _("Tax Id: ") }}{{ filters.tax_id }}
{% endif %}
</h6>
<h5 class="text-center">
{{ _(filters.ageing_based_on) }}
{{ _("Until") }}
{{ frappe.format(filters.report_date, 'Date') }}
</h5>
<div class="clearfix">
<div class="pull-left">
{% if(filters.payment_terms) %}
<strong>{{ _("Payment Terms") }}:</strong> {{ filters.payment_terms }}
{% endif %}
</div>
<div class="pull-right">
{% if(filters.credit_limit) %}
<strong>{{ _("Credit Limit") }}:</strong> {{ frappe.utils.fmt_money(filters.credit_limit) }}
{% endif %}
</div>
</div>
{% if(filters.show_future_payments) %}
{% set balance_row = data.slice(-1).pop() %}
{% for i in report.columns %}
{% if i.fieldname == 'age' %}
{% set elem = i %}
{% endif %}
{% endfor %}
{% set start = report.columns.findIndex(elem) %}
{% set range1 = report.columns[start].label %}
{% set range2 = report.columns[start+1].label %}
{% set range3 = report.columns[start+2].label %}
{% set range4 = report.columns[start+3].label %}
{% set range5 = report.columns[start+4].label %}
{% set range6 = report.columns[start+5].label %}
{% if(balance_row) %}
<table class="table table-bordered table-condensed">
<caption class="text-right">(Amount in {{ data[0]["currency"] ~ "" }})</caption>
<colgroup>
<col style="width: 30mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
</colgroup>
<thead>
<tr>
<th>{{ _(" ") }}</th>
<th>{{ _(range1) }}</th>
<th>{{ _(range2) }}</th>
<th>{{ _(range3) }}</th>
<th>{{ _(range4) }}</th>
<th>{{ _(range5) }}</th>
<th>{{ _(range6) }}</th>
<th>{{ _("Total") }}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ _("Total Outstanding") }}</td>
<td class="text-right">
{{ format_number(balance_row["age"], null, 2) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range1"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range2"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range3"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range4"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range5"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(flt(balance_row["outstanding"]), data[data.length-1]["currency"]) }}
</td>
</tr>
<td>{{ _("Future Payments") }}</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td class="text-right">
{{ frappe.utils.fmt_money(flt(balance_row[("future_amount")]), data[data.length-1]["currency"]) }}
</td>
<tr class="cvs-footer">
<th class="text-left">{{ _("Cheques Required") }}</th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th class="text-right">
{{ frappe.utils.fmt_money(flt(balance_row["outstanding"] - balance_row[("future_amount")]), data[data.length-1]["currency"]) }}</th>
</tr>
</tbody>
</table>
{% endif %}
<div id="header-html" class="hidden-pdf">
{% if letter_head.content %}
<div class="letter-head text-center">{{ letter_head.content }}</div>
<hr style="height:2px;border-width:0;color:black;background-color:black;">
{% endif %}
<table class="table table-bordered">
</div>
<div id="footer-html" class="visible-pdf">
{% if letter_head.footer %}
<div class="letter-head-footer">
<hr style="border-width:0;color:black;background-color:black;padding-bottom:2px;">
{{ letter_head.footer }}
</div>
{% endif %}
</div>
<h2 class="text-center" style="margin-top:0">{{ _(report.report_name) }}</h2>
<h4 class="text-center">
{{ filters.customer_name }}
</h4>
<h6 class="text-center">
{% if (filters.tax_id) %}
{{ _("Tax Id: {0}").format(filters.tax_id) }}
{% endif %}
</h6>
<h5 class="text-center">
{{ _("{0} until {1}").format(
_(filters.ageing_based_on),
frappe.format(filters.report_date, 'Date')
) }}
</h5>
<div class="clearfix">
<div class="pull-left">
{% if(filters.payment_terms) %}
<strong>{{ _("Payment Terms:") }}</strong> {{ filters.payment_terms }}
{% endif %}
</div>
<div class="pull-right">
{% if(filters.credit_limit) %}
<strong>{{ _("Credit Limit:") }}</strong> {{ frappe.utils.fmt_money(filters.credit_limit) }}
{% endif %}
</div>
</div>
{% if(filters.show_future_payments) %}
{% set balance_row = data.slice(-1).pop() %}
{% for i in report.columns %}
{% if i.fieldname == 'age' %}
{% set elem = i %}
{% endif %}
{% endfor %}
{% set start = report.columns.findIndex(elem) %}
{% set range1 = report.columns[start].label %}
{% set range2 = report.columns[start+1].label %}
{% set range3 = report.columns[start+2].label %}
{% set range4 = report.columns[start+3].label %}
{% set range5 = report.columns[start+4].label %}
{% set range6 = report.columns[start+5].label %}
{% if(balance_row) %}
<table class="table table-bordered table-condensed">
<caption class="text-right">{{ _("Amount in {0}").format(data[0]["currency"] ~ "") }}</caption>
<colgroup>
<col style="width: 30mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
<col style="width: 18mm;">
</colgroup>
<thead>
<tr>
{% if(report.report_name == "Accounts Receivable" or report.report_name == "Accounts Payable") %}
<th style="width: 10%">{{ _("Date") }}</th>
<th style="width: 4%">{{ _("Age (Days)") }}</th>
{% if(report.report_name == "Accounts Receivable" and filters.show_sales_person) %}
<th style="width: 14%">{{ _("Reference") }}</th>
<th style="width: 10%">{{ _("Sales Person") }}</th>
{% else %}
<th style="width: 24%">{{ _("Reference") }}</th>
{% endif %}
{% if not(filters.show_future_payments) %}
<th style="width: 20%">
{% if (filters.customer or filters.supplier or filters.customer_name) %}
{{ _("Remarks") }}
{% else %}
{{ _("Party") }}
{% endif %}
</th>
{% endif %}
<th style="width: 10%; text-align: right">{{ _("Invoiced Amount") }}</th>
{% if not(filters.show_future_payments) %}
<th style="width: 10%; text-align: right">{{ _("Paid Amount") }}</th>
<th style="width: 10%; text-align: right">
{% if report.report_name == "Accounts Receivable" %}
{{ _('Credit Note') }}
{% else %}
{{ _('Debit Note') }}
{% endif %}
</th>
{% endif %}
<th style="width: 10%; text-align: right">{{ _("Outstanding Amount") }}</th>
{% if(filters.show_future_payments) %}
{% if(report.report_name == "Accounts Receivable") %}
<th style="width: 12%">{{ _("Customer LPO No.") }}</th>
{% endif %}
<th style="width: 10%">{{ _("Future Payment Ref") }}</th>
<th style="width: 10%">{{ _("Future Payment Amount") }}</th>
<th style="width: 10%">{{ _("Remaining Balance") }}</th>
{% endif %}
{% else %}
<th style="width: 40%">
{% if (filters.customer or filters.supplier or filters.customer_name) %}
{{ _("Remarks")}}
{% else %}
{{ _("Party") }}
{% endif %}
</th>
<th style="width: 15%">{{ _("Total Invoiced Amount") }}</th>
<th style="width: 15%">{{ _("Total Paid Amount") }}</th>
<th style="width: 15%">
{% if report.report_name == "Accounts Receivable Summary" %}
{{ _('Credit Note Amount') }}
{% else %}
{{ _('Debit Note Amount') }}
{% endif %}
</th>
<th style="width: 15%">{{ _("Total Outstanding Amount") }}</th>
{% endif %}
<th>{{ _(" ") }}</th>
<th>{{ _(range1) }}</th>
<th>{{ _(range2) }}</th>
<th>{{ _(range3) }}</th>
<th>{{ _(range4) }}</th>
<th>{{ _(range5) }}</th>
<th>{{ _(range6) }}</th>
<th>{{ _("Total") }}</th>
</tr>
</thead>
<tbody>
{% for i in range(data|length) %}
<tr>
{% if(report.report_name == "Accounts Receivable" or report.report_name == "Accounts Payable") %}
{% if(data[i]["party"]) %}
<td>{{ (data[i]["posting_date"]) }}</td>
<td style="text-align: right">{{ data[i]["age"] }}</td>
<td>
{% if not(filters.show_future_payments) %}
{{ data[i]["voucher_type"] }}
<br>
{% endif %}
{{ data[i]["voucher_no"] }}
</td>
<tr>
<td>{{ _("Total Outstanding") }}</td>
<td class="text-right">
{{ format_number(balance_row["age"], null, 2) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range1"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range2"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range3"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range4"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(balance_row["range5"], data[data.length-1]["currency"]) }}
</td>
<td class="text-right">
{{ frappe.utils.fmt_money(flt(balance_row["outstanding"]), data[data.length-1]["currency"]) }}
</td>
</tr>
<td>{{ _("Future Payments") }}</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td class="text-right">
{{ frappe.utils.fmt_money(flt(balance_row[("future_amount")]), data[data.length-1]["currency"]) }}
</td>
<tr class="cvs-footer">
<th class="text-left">{{ _("Cheques Required") }}</th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th class="text-right">
{{ frappe.utils.fmt_money(flt(balance_row["outstanding"] - balance_row[("future_amount")]), data[data.length-1]["currency"]) }}</th>
</tr>
</tbody>
{% if(report.report_name == "Accounts Receivable" and filters.show_sales_person) %}
<td>{{ data[i]["sales_person"] }}</td>
</table>
{% endif %}
{% endif %}
<table class="table table-bordered">
<thead>
<tr>
{% if(report.report_name == "Accounts Receivable" or report.report_name == "Accounts Payable") %}
<th style="width: 10%">{{ _("Date") }}</th>
<th style="width: 4%">{{ _("Age (Days)") }}</th>
{% if(report.report_name == "Accounts Receivable" and filters.show_sales_person) %}
<th style="width: 14%">{{ _("Reference") }}</th>
<th style="width: 10%">{{ _("Sales Person") }}</th>
{% else %}
<th style="width: 24%">{{ _("Reference") }}</th>
{% endif %}
{% if not(filters.show_future_payments) %}
<th style="width: 20%">
{% if (filters.customer or filters.supplier or filters.customer_name) %}
{{ _("Remarks") }}
{% else %}
{{ _("Party") }}
{% endif %}
</th>
{% endif %}
<th style="width: 10%; text-align: right">{{ _("Invoiced Amount") }}</th>
{% if not(filters.show_future_payments) %}
<th style="width: 10%; text-align: right">{{ _("Paid Amount") }}</th>
<th style="width: 10%; text-align: right">
{% if report.report_name == "Accounts Receivable" %}
{{ _("Credit Note") }}
{% else %}
{{ _("Debit Note") }}
{% endif %}
</th>
{% endif %}
<th style="width: 10%; text-align: right">{{ _("Outstanding Amount") }}</th>
{% if(filters.show_future_payments) %}
{% if(report.report_name == "Accounts Receivable") %}
<th style="width: 12%">{{ _("Customer LPO No.") }}</th>
{% endif %}
<th style="width: 10%">{{ _("Future Payment Ref") }}</th>
<th style="width: 10%">{{ _("Future Payment Amount") }}</th>
<th style="width: 10%">{{ _("Remaining Balance") }}</th>
{% endif %}
{% else %}
<th style="width: 40%">
{% if (filters.customer or filters.supplier or filters.customer_name) %}
{{ _("Remarks")}}
{% else %}
{{ _("Party") }}
{% endif %}
</th>
<th style="width: 15%">{{ _("Total Invoiced Amount") }}</th>
<th style="width: 15%">{{ _("Total Paid Amount") }}</th>
<th style="width: 15%">
{% if report.report_name == "Accounts Receivable Summary" %}
{{ _("Credit Note Amount") }}
{% else %}
{{ _("Debit Note Amount") }}
{% endif %}
</th>
<th style="width: 15%">{{ _("Total Outstanding Amount") }}</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for i in range(data|length) %}
<tr>
{% if(report.report_name == "Accounts Receivable" or report.report_name == "Accounts Payable") %}
{% if(data[i]["party"]) %}
<td>{{ (data[i]["posting_date"]) }}</td>
<td style="text-align: right">{{ data[i]["age"] }}</td>
<td>
{% if not(filters.show_future_payments) %}
{{ data[i]["voucher_type"] }}
<br>
{% endif %}
{{ data[i]["voucher_no"] }}
</td>
{% if not (filters.show_future_payments) %}
{% if(report.report_name == "Accounts Receivable" and filters.show_sales_person) %}
<td>{{ data[i]["sales_person"] }}</td>
{% endif %}
{% if not (filters.show_future_payments) %}
<td>
{% if(not(filters.customer or filters.supplier or filters.customer_name)) %}
{{ data[i]["party"] }}
{% if(data[i]["customer_name"] and data[i]["customer_name"] != data[i]["party"]) %}
<br> {{ data[i]["customer_name"] }}
{% elif(data[i]["supplier_name"] != data[i]["party"]) %}
<br> {{ data[i]["supplier_name"] }}
{% endif %}
{% endif %}
<div>
{% if data[i]["remarks"] %}
{{ _("Remarks") }}:
{{ data[i]["remarks"] }}
{% endif %}
</div>
</td>
{% endif %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["invoiced"], currency=data[i]["currency"]) }}</td>
{% if not(filters.show_future_payments) %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["paid"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["credit_note"], currency=data[i]["currency"]) }}</td>
{% endif %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["outstanding"], currency=data[i]["currency"]) }}</td>
{% if(filters.show_future_payments) %}
{% if(report.report_name == "Accounts Receivable") %}
<td style="text-align: right">
{{ data[i]["po_no"] }}</td>
{% endif %}
<td style="text-align: right">{{ data[i]["future_ref"] }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["future_amount"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["remaining_balance"], currency=data[i]["currency"]) }}</td>
{% endif %}
{% else %}
<td></td>
{% if not(filters.show_future_payments) %}
<td></td>
{% endif %}
{% if(report.report_name == "Accounts Receivable" and filters.show_sales_person) %}
<td></td>
{% endif %}
<td></td>
<td style="text-align: right"><b>{{ _("Total") }}</b></td>
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["invoiced"], data[i]["currency"]) }}</td>
{% if not(filters.show_future_payments) %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["paid"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["credit_note"], currency=data[i]["currency"]) }} </td>
{% endif %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["outstanding"], currency=data[i]["currency"]) }}</td>
{% if(filters.show_future_payments) %}
{% if(report.report_name == "Accounts Receivable") %}
<td style="text-align: right">
{{ data[i]["po_no"] }}</td>
{% endif %}
<td style="text-align: right">{{ data[i]["future_ref"] }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["future_amount"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["remaining_balance"], currency=data[i]["currency"]) }}</td>
{% endif %}
{% endif %}
{% else %}
{% if(data[i]["party"] or "&nbsp;") %}
{% if not(data[i]["is_total_row"]) %}
<td>
{% if(not(filters.customer or filters.supplier or filters.customer_name)) %}
{% if(not(filters.customer | filters.supplier)) %}
{{ data[i]["party"] }}
{% if(data[i]["customer_name"] and data[i]["customer_name"] != data[i]["party"]) %}
<br> {{ data[i]["customer_name"] }}
@@ -235,130 +309,62 @@
<br> {{ data[i]["supplier_name"] }}
{% endif %}
{% endif %}
<div>
{% if data[i]["remarks"] %}
{{ _("Remarks") }}:
{{ data[i]["remarks"] }}
{% endif %}
</div>
<br>{{ _("Remarks") }}:
{{ data[i]["remarks"] }}
</td>
{% endif %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["invoiced"], currency=data[i]["currency"]) }}</td>
{% if not(filters.show_future_payments) %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["paid"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["credit_note"], currency=data[i]["currency"]) }}</td>
{% endif %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["outstanding"], currency=data[i]["currency"]) }}</td>
{% if(filters.show_future_payments) %}
{% if(report.report_name == "Accounts Receivable") %}
<td style="text-align: right">
{{ data[i]["po_no"] }}</td>
{% endif %}
<td style="text-align: right">{{ data[i]["future_ref"] }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["future_amount"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["remaining_balance"], currency=data[i]["currency"]) }}</td>
{% endif %}
{% else %}
<td></td>
{% if not(filters.show_future_payments) %}
<td></td>
{% endif %}
{% if(report.report_name == "Accounts Receivable" and filters.show_sales_person) %}
<td></td>
{% endif %}
<td></td>
<td style="text-align: right"><b>{{ _("Total") }}</b></td>
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["invoiced"], data[i]["currency"]) }}</td>
{% if not(filters.show_future_payments) %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["paid"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["credit_note"], currency=data[i]["currency"]) }} </td>
{% endif %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(data[i]["outstanding"], currency=data[i]["currency"]) }}</td>
{% if(filters.show_future_payments) %}
{% if(report.report_name == "Accounts Receivable") %}
<td style="text-align: right">
{{ data[i]["po_no"] }}</td>
{% endif %}
<td style="text-align: right">{{ data[i]["future_ref"] }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["future_amount"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["remaining_balance"], currency=data[i]["currency"]) }}</td>
{% endif %}
{% endif %}
{% else %}
{% if(data[i]["party"] or "&nbsp;") %}
{% if not(data[i]["is_total_row"]) %}
<td>
{% if(not(filters.customer | filters.supplier)) %}
{{ data[i]["party"] }}
{% if(data[i]["customer_name"] and data[i]["customer_name"] != data[i]["party"]) %}
<br> {{ data[i]["customer_name"] }}
{% elif(data[i]["supplier_name"] != data[i]["party"]) %}
<br> {{ data[i]["supplier_name"] }}
{% endif %}
{% endif %}
<br>{{ _("Remarks") }}:
{{ data[i]["remarks"] }}
</td>
{% else %}
<td><b>{{ _("Total") }}</b></td>
{% endif %}
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["invoiced"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["paid"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["credit_note"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["outstanding"], currency=data[i]["currency"]) }}</td>
<td><b>{{ _("Total") }}</b></td>
{% endif %}
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["invoiced"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["paid"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["credit_note"], currency=data[i]["currency"]) }}</td>
<td style="text-align: right">{{ frappe.utils.fmt_money(data[i]["outstanding"], currency=data[i]["currency"]) }}</td>
{% endif %}
</tr>
{% endfor %}
<td></td>
<td></td>
<td></td>
<td></td>
<td style="text-align: right"><b>{{ frappe.utils.fmt_money(data|sum(attribute="invoiced"), currency=data[0]["currency"]) }}</b></td>
<td style="text-align: right"><b>{{ frappe.utils.fmt_money(data|sum(attribute="paid"), currency=data[0]["currency"]) }}</b></td>
<td style="text-align: right"><b>{{ frappe.utils.fmt_money(data|sum(attribute="credit_note"), currency=data[0]["currency"]) }}</b></td>
<td style="text-align: right"><b>{{ frappe.utils.fmt_money(data|sum(attribute="outstanding"), currency=data[0]["currency"]) }}</b></td>
</tbody>
</table>
<br>
{% if ageing %}
<h4 class="text-center">{{ _("Ageing Report based on ") }} {{ ageing.ageing_based_on }}
{{ _("up to " ) }} {{ frappe.format(filters.report_date, 'Date')}}
</h4>
<table class="table table-bordered">
<thead>
<tr>
<th style="width: 25%">30 Days</th>
<th style="width: 25%">60 Days</th>
<th style="width: 25%">90 Days</th>
<th style="width: 25%">120 Days</th>
{% endif %}
</tr>
</thead>
<tbody>
<tr>
<td>{{ frappe.utils.fmt_money(ageing.range1, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range2, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range3, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range4, currency=data[0]["currency"]) }}</td>
</tr>
</tbody>
</table>
{% endif %}
{% if terms_and_conditions %}
<div>
{{ terms_and_conditions }}
</div>
{% endif %}
<p class="text-right text-muted">{{ _("Printed On ") }}{{ frappe.utils.now() }}</p>
{% endfor %}
<td></td>
<td></td>
<td></td>
<td></td>
<td style="text-align: right"><b>{{ frappe.utils.fmt_money(data|sum(attribute="invoiced"), currency=data[0]["currency"]) }}</b></td>
<td style="text-align: right"><b>{{ frappe.utils.fmt_money(data|sum(attribute="paid"), currency=data[0]["currency"]) }}</b></td>
<td style="text-align: right"><b>{{ frappe.utils.fmt_money(data|sum(attribute="credit_note"), currency=data[0]["currency"]) }}</b></td>
<td style="text-align: right"><b>{{ frappe.utils.fmt_money(data|sum(attribute="outstanding"), currency=data[0]["currency"]) }}</b></td>
</tbody>
</table>
<br>
{% if ageing %}
<h4 class="text-center">
{{ _("Ageing Report based on {0} up to {1}").format(
ageing.ageing_based_on,
frappe.format(filters.report_date, "Date")
) }}
</h4>
<table class="table table-bordered">
<thead>
<tr>
<th style="width: 25%">{{ _("0 - 30 Days") }}</th>
<th style="width: 25%">{{ _("30 - 60 Days") }}</th>
<th style="width: 25%">{{ _("60 - 90 Days") }}</th>
<th style="width: 25%">{{ _("90 - 120 Days") }}</th>
<th style="width: 20%">{{ _("Above 120 Days") }}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ frappe.utils.fmt_money(ageing.range1, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range2, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range3, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range4, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range5, currency=filters.presentation_currency) }}</td>
</tr>
</tbody>
</table>
{% endif %}
{% if terms_and_conditions %}
<div>
{{ terms_and_conditions }}
</div>
{% endif %}
<p class="text-right text-muted">{{ _("Printed on {0}").format(frappe.utils.now()) }}</p>

View File

@@ -2,6 +2,18 @@
// For license information, please see license.txt
frappe.ui.form.on("Promotional Scheme", {
setup: function (frm) {
frm.set_query("for_price_list", "price_discount_slabs", (doc) => {
return {
filters: {
selling: doc.selling,
buying: doc.buying,
currency: doc.currency,
},
};
});
},
refresh: function (frm) {
frm.trigger("set_options_for_applicable_for");
frm.trigger("toggle_reqd_apply_on");

View File

@@ -51,6 +51,7 @@ price_discount_fields = [
"discount_percentage",
"validate_applied_rule",
"apply_multiple_pricing_rules",
"for_price_list",
]
product_discount_fields = [
@@ -63,6 +64,7 @@ product_discount_fields = [
"recurse_for",
"apply_recursion_over",
"apply_multiple_pricing_rules",
"round_free_qty",
]
@@ -146,6 +148,7 @@ class PromotionalScheme(Document):
self.validate_applicable_for()
self.validate_pricing_rules()
self.validate_mixed_with_recursion()
def validate_applicable_for(self):
if self.applicable_for:
@@ -163,7 +166,7 @@ class PromotionalScheme(Document):
docnames = []
# If user has changed applicable for
if self._doc_before_save.applicable_for == self.applicable_for:
if self.get_doc_before_save() and self.get_doc_before_save().applicable_for == self.applicable_for:
return
docnames = frappe.get_all("Pricing Rule", filters={"promotional_scheme": self.name})
@@ -177,6 +180,7 @@ class PromotionalScheme(Document):
frappe.delete_doc("Pricing Rule", docname.name)
def on_update(self):
self.validate()
pricing_rules = (
frappe.get_all(
"Pricing Rule",
@@ -188,6 +192,15 @@ class PromotionalScheme(Document):
)
self.update_pricing_rules(pricing_rules)
def validate_mixed_with_recursion(self):
if self.mixed_conditions:
if self.product_discount_slabs:
for slab in self.product_discount_slabs:
if slab.is_recursive:
frappe.throw(
_("Recursive Discounts with Mixed condition is not supported by the system")
)
def update_pricing_rules(self, pricing_rules):
rules = {}
count = 0

View File

@@ -129,6 +129,25 @@ class TestPromotionalScheme(unittest.TestCase):
[pr.min_qty, pr.free_item, pr.free_qty, pr.recurse_for], [12, "_Test Item 2", 1, 12]
)
def test_validation_on_recurse_with_mixed_condition(self):
ps = make_promotional_scheme()
ps.set("price_discount_slabs", [])
ps.set(
"product_discount_slabs",
[
{
"rule_description": "12+1",
"min_qty": 12,
"free_item": "_Test Item 2",
"free_qty": 1,
"is_recursive": 1,
"recurse_for": 12,
}
],
)
ps.mixed_conditions = True
self.assertRaises(frappe.ValidationError, ps.save)
def make_promotional_scheme(**args):
args = frappe._dict(args)

View File

@@ -21,6 +21,7 @@
"rate",
"discount_amount",
"discount_percentage",
"for_price_list",
"section_break_11",
"warehouse",
"threshold_percentage",
@@ -120,6 +121,13 @@
"fieldtype": "Float",
"label": "Discount Percentage"
},
{
"depends_on": "eval:doc.rate_or_discount!=\"Rate\"",
"fieldname": "for_price_list",
"fieldtype": "Link",
"label": "For Price List",
"options": "Price List"
},
{
"fieldname": "section_break_11",
"fieldtype": "Section Break"
@@ -169,7 +177,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:22.448265",
"modified": "2024-07-23 12:33:46.574950",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme Price Discount",

View File

@@ -19,6 +19,7 @@ class PromotionalSchemePriceDiscount(Document):
disable: DF.Check
discount_amount: DF.Currency
discount_percentage: DF.Float
for_price_list: DF.Link | None
max_amount: DF.Currency
max_qty: DF.Float
min_amount: DF.Currency

View File

@@ -22,6 +22,7 @@
"column_break_9",
"free_item_uom",
"free_item_rate",
"round_free_qty",
"section_break_12",
"warehouse",
"threshold_percentage",
@@ -181,12 +182,18 @@
"fieldtype": "Float",
"label": "Apply Recursion Over (As Per Transaction UOM)",
"mandatory_depends_on": "is_recursive"
},
{
"default": "0",
"fieldname": "round_free_qty",
"fieldtype": "Check",
"label": "Round Free Qty"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:22.605892",
"modified": "2024-07-22 17:25:07.880984",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme Product Discount",
@@ -195,4 +202,4 @@
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -53,6 +53,7 @@ class PromotionalSchemeProductDiscount(Document):
"20",
]
recurse_for: DF.Float
round_free_qty: DF.Check
rule_description: DF.SmallText
same_item: DF.Check
threshold_percentage: DF.Percent

View File

@@ -11,13 +11,15 @@
{
"fieldname": "cost_center_name",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Cost Center",
"options": "Cost Center"
"options": "Cost Center",
"reqd": 1
}
],
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:23.244686",
"modified": "2024-05-03 17:16:51.666461",
"modified_by": "Administrator",
"module": "Accounts",
"name": "PSOA Cost Center",

View File

@@ -15,7 +15,7 @@ class PSOACostCenter(Document):
if TYPE_CHECKING:
from frappe.types import DF
cost_center_name: DF.Link | None
cost_center_name: DF.Link
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data

View File

@@ -77,31 +77,6 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
erpnext.accounts.ledger_preview.show_stock_ledger_preview(this.frm);
}
if (this.frm.doc.repost_required && this.frm.doc.docstatus === 1) {
this.frm.set_intro(
__(
"Accounting entries for this invoice need to be reposted. Please click on 'Repost' button to update."
)
);
this.frm
.add_custom_button(__("Repost Accounting Entries"), () => {
this.frm.call({
doc: this.frm.doc,
method: "repost_accounting_entries",
freeze: true,
freeze_message: __("Reposting..."),
callback: (r) => {
if (!r.exc) {
frappe.msgprint(__("Accounting Entries are reposted."));
me.frm.refresh();
}
},
});
})
.removeClass("btn-default")
.addClass("btn-warning");
}
if (!doc.is_return && doc.docstatus == 1 && doc.outstanding_amount != 0) {
if (doc.on_hold) {
this.frm.add_custom_button(
@@ -489,10 +464,12 @@ function hide_fields(doc) {
var item_fields_stock = ["warehouse_section", "received_qty", "rejected_qty"];
cur_frm.fields_dict["items"].grid.set_column_disp(
item_fields_stock,
cint(doc.update_stock) == 1 || cint(doc.is_return) == 1 ? true : false
);
if (cur_frm.fields_dict["items"]) {
cur_frm.fields_dict["items"].grid.set_column_disp(
item_fields_stock,
cint(doc.update_stock) == 1 || cint(doc.is_return) == 1 ? true : false
);
}
cur_frm.refresh_fields();
}
@@ -679,7 +656,7 @@ frappe.ui.form.on("Purchase Invoice", {
if (frm.doc.supplier) {
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
}
if (!frm.doc.__onload.supplier_tds) {
if (!frm.doc.__onload.enable_apply_tds) {
frm.set_df_property("apply_tds", "read_only", 1);
}
}

View File

@@ -170,7 +170,6 @@
"against_expense_account",
"column_break_63",
"unrealized_profit_loss_account",
"repost_required",
"subscription_section",
"subscription",
"auto_repeat",
@@ -364,7 +363,8 @@
"description": "Once set, this invoice will be on hold till the set date",
"fieldname": "release_date",
"fieldtype": "Date",
"label": "Release Date"
"label": "Release Date",
"search_index": 1
},
{
"fieldname": "cb_17",
@@ -1604,15 +1604,6 @@
"fieldtype": "Check",
"label": "Use Company Default Round Off Cost Center"
},
{
"default": "0",
"fieldname": "repost_required",
"fieldtype": "Check",
"hidden": 1,
"label": "Repost Required",
"options": "Account",
"read_only": 1
},
{
"default": "0",
"fieldname": "use_transaction_date_exchange_rate",
@@ -1640,7 +1631,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2024-04-11 11:28:42.802211",
"modified": "2024-07-25 19:42:36.931278",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -159,7 +159,6 @@ class PurchaseInvoice(BuyingController):
rejected_warehouse: DF.Link | None
release_date: DF.Date | None
remarks: DF.SmallText | None
repost_required: DF.Check
represents_company: DF.Link | None
return_against: DF.Link | None
rounded_total: DF.Currency
@@ -348,6 +347,22 @@ class PurchaseInvoice(BuyingController):
self.tax_withholding_category = tds_category
self.set_onload("supplier_tds", tds_category)
# If Linked Purchase Order has TDS applied, enable 'apply_tds' checkbox
if purchase_orders := [x.purchase_order for x in self.items if x.purchase_order]:
po = qb.DocType("Purchase Order")
po_with_tds = (
qb.from_(po)
.select(po.name)
.where(
po.docstatus.eq(1)
& (po.name.isin(purchase_orders))
& (po.apply_tds.eq(1))
& (po.tax_withholding_category.notnull())
)
.run()
)
self.set_onload("enable_apply_tds", True if po_with_tds else False)
super().set_missing_values(for_validate)
def validate_credit_to_acc(self):
@@ -363,16 +378,16 @@ class PurchaseInvoice(BuyingController):
if account.report_type != "Balance Sheet":
frappe.throw(
_(
"Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account."
).format(frappe.bold("Credit To")),
"Please ensure that the {0} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account."
).format(frappe.bold(_("Credit To"))),
title=_("Invalid Account"),
)
if self.supplier and account.account_type != "Payable":
frappe.throw(
_(
"Please ensure {} account {} is a Payable account. Change the account type to Payable or select a different account."
).format(frappe.bold("Credit To"), frappe.bold(self.credit_to)),
"Please ensure that the {0} account {1} is a Payable account. You can change the account type to Payable or select a different account."
).format(frappe.bold(_("Credit To")), frappe.bold(self.credit_to)),
title=_("Invalid Account"),
)
@@ -449,7 +464,7 @@ class PurchaseInvoice(BuyingController):
stock_not_billed_account = self.get_company_default("stock_received_but_not_billed")
stock_items = self.get_stock_items()
asset_received_but_not_billed = None
self.asset_received_but_not_billed = None
if self.update_stock:
self.validate_item_code()
@@ -532,26 +547,60 @@ class PurchaseInvoice(BuyingController):
frappe.msgprint(msg, title=_("Expense Head Changed"))
item.expense_account = stock_not_billed_account
elif item.is_fixed_asset and item.pr_detail:
if not asset_received_but_not_billed:
asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed")
item.expense_account = asset_received_but_not_billed
elif item.is_fixed_asset:
account_type = (
"capital_work_in_progress_account"
if is_cwip_accounting_enabled(item.asset_category)
else "fixed_asset_account"
)
asset_category_account = get_asset_category_account(
account_type, item=item.item_code, company=self.company
)
if not asset_category_account:
form_link = get_link_to_form("Asset Category", item.asset_category)
throw(
_("Please set Fixed Asset Account in {} against {}.").format(form_link, self.company),
title=_("Missing Account"),
account = None
if not item.pr_detail and item.po_detail:
receipt_item = frappe.get_cached_value(
"Purchase Receipt Item",
{
"purchase_order": item.purchase_order,
"purchase_order_item": item.po_detail,
"docstatus": 1,
},
["name", "parent"],
as_dict=1,
)
item.expense_account = asset_category_account
if receipt_item:
item.pr_detail = receipt_item.name
item.purchase_receipt = receipt_item.parent
if item.pr_detail:
if not self.asset_received_but_not_billed:
self.asset_received_but_not_billed = self.get_company_default(
"asset_received_but_not_billed"
)
# check if 'Asset Received But Not Billed' account is credited in Purchase receipt or not
arbnb_booked_in_pr = frappe.db.get_value(
"GL Entry",
{
"voucher_type": "Purchase Receipt",
"voucher_no": item.purchase_receipt,
"account": self.asset_received_but_not_billed,
},
"name",
)
if arbnb_booked_in_pr:
account = self.asset_received_but_not_billed
if not account:
account_type = (
"capital_work_in_progress_account"
if is_cwip_accounting_enabled(item.asset_category)
else "fixed_asset_account"
)
account = get_asset_category_account(
account_type, item=item.item_code, company=self.company
)
if not account:
form_link = get_link_to_form("Asset Category", item.asset_category)
throw(
_("Please set Fixed Asset Account in {} against {}.").format(
form_link, self.company
),
title=_("Missing Account"),
)
item.expense_account = account
elif not item.expense_account and for_validate:
throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name))
@@ -559,7 +608,7 @@ class PurchaseInvoice(BuyingController):
for item in self.get("items"):
validate_account_head(item.idx, item.expense_account, self.company, "Expense")
def set_against_expense_account(self):
def set_against_expense_account(self, force=False):
against_accounts = []
for item in self.get("items"):
if item.expense_account and (item.expense_account not in against_accounts):
@@ -567,6 +616,10 @@ class PurchaseInvoice(BuyingController):
self.against_expense_account = ",".join(against_accounts)
def force_set_against_expense_account(self):
self.set_against_expense_account()
frappe.db.set_value(self.doctype, self.name, "against_expense_account", self.against_expense_account)
def po_required(self):
if frappe.db.get_single_value("Buying Settings", "po_required") == "Yes":
if frappe.get_value(
@@ -582,7 +635,7 @@ class PurchaseInvoice(BuyingController):
"To submit the invoice without purchase order please set {0} as {1} in {2}"
).format(
frappe.bold(_("Purchase Order Required")),
frappe.bold("No"),
frappe.bold(_("No")),
get_link_to_form("Buying Settings", "Buying Settings", "Buying Settings"),
)
throw(msg, title=_("Mandatory Purchase Order"))
@@ -603,7 +656,7 @@ class PurchaseInvoice(BuyingController):
"To submit the invoice without purchase receipt please set {0} as {1} in {2}"
).format(
frappe.bold(_("Purchase Receipt Required")),
frappe.bold("No"),
frappe.bold(_("No")),
get_link_to_form("Buying Settings", "Buying Settings", "Buying Settings"),
)
throw(msg, title=_("Mandatory Purchase Receipt"))
@@ -649,6 +702,19 @@ class PurchaseInvoice(BuyingController):
where name=`tabPurchase Invoice Item`.parent and update_stock = 1)""",
}
)
self.status_updater.append(
{
"source_dt": "Purchase Invoice Item",
"target_dt": "Material Request Item",
"join_field": "material_request_item",
"target_field": "received_qty",
"target_parent_dt": "Material Request",
"target_parent_field": "per_received",
"target_ref_field": "stock_qty",
"source_field": "stock_qty",
"percent_join_field": "material_request",
}
)
if cint(self.is_return):
self.status_updater.append(
{
@@ -708,6 +774,7 @@ class PurchaseInvoice(BuyingController):
# Updating stock ledger should always be called after updating prevdoc status,
# because updating ordered qty in bin depends upon updated ordered qty in PO
if self.update_stock == 1:
self.make_bundle_for_sales_purchase_return()
self.make_bundle_using_old_serial_batch_fields()
self.update_stock_ledger()
@@ -729,18 +796,17 @@ class PurchaseInvoice(BuyingController):
self.process_common_party_accounting()
def on_update_after_submit(self):
if hasattr(self, "repost_required"):
fields_to_check = [
"cash_bank_account",
"write_off_account",
"unrealized_profit_loss_account",
"is_opening",
]
child_tables = {"items": ("expense_account",), "taxes": ("account_head",)}
self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables)
if self.needs_repost:
self.validate_for_repost()
self.db_set("repost_required", self.needs_repost)
fields_to_check = [
"cash_bank_account",
"write_off_account",
"unrealized_profit_loss_account",
"is_opening",
]
child_tables = {"items": ("expense_account",), "taxes": ("account_head",)}
self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables)
if self.needs_repost:
self.validate_for_repost()
self.repost_accounting_entries()
def make_gl_entries(self, gl_entries=None, from_repost=False):
update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
@@ -1063,7 +1129,7 @@ class PurchaseInvoice(BuyingController):
)
# check if the exchange rate has changed
if item.get("purchase_receipt"):
if item.get("purchase_receipt") and self.auto_accounting_for_stock:
if (
exchange_rate_map[item.purchase_receipt]
and self.conversion_rate != exchange_rate_map[item.purchase_receipt]
@@ -1147,7 +1213,7 @@ class PurchaseInvoice(BuyingController):
pr_items = frappe.get_all(
"Purchase Receipt Item",
filters={"parent": ("in", linked_purchase_receipts)},
fields=["name", "provisional_expense_account", "qty", "base_rate"],
fields=["name", "provisional_expense_account", "qty", "base_rate", "rate"],
)
default_provisional_account = self.get_company_default("default_provisional_account")
provisional_accounts = set(
@@ -1175,6 +1241,7 @@ class PurchaseInvoice(BuyingController):
"provisional_account": item.provisional_expense_account or default_provisional_account,
"qty": item.qty,
"base_rate": item.base_rate,
"rate": item.rate,
"has_provisional_entry": item.name in rows_with_provisional_entries,
}
@@ -1191,13 +1258,20 @@ class PurchaseInvoice(BuyingController):
self.posting_date,
pr_item.get("provisional_account"),
reverse=1,
item_amount=(min(item.qty, pr_item.get("qty")) * pr_item.get("base_rate")),
item_amount=(
(min(item.qty, pr_item.get("qty")) * pr_item.get("rate"))
* purchase_receipt_doc.get("conversion_rate")
),
)
def update_gross_purchase_amount_for_linked_assets(self, item):
assets = frappe.db.get_all(
"Asset",
filters={"purchase_invoice": self.name, "item_code": item.item_code},
filters={
"purchase_invoice": self.name,
"item_code": item.item_code,
"purchase_invoice_item": ("in", [item.name, ""]),
},
fields=["name", "asset_quantity"],
)
for asset in assets:
@@ -1207,7 +1281,7 @@ class PurchaseInvoice(BuyingController):
asset.name,
{
"gross_purchase_amount": purchase_amount,
"purchase_receipt_amount": purchase_amount,
"purchase_amount": purchase_amount,
},
)
@@ -1637,6 +1711,9 @@ class PurchaseInvoice(BuyingController):
self.db_set("release_date", None)
def set_tax_withholding(self):
self.set("advance_tax", [])
self.set("tax_withheld_vouchers", [])
if not self.apply_tds:
return
@@ -1678,8 +1755,6 @@ class PurchaseInvoice(BuyingController):
self.remove(d)
## Add pending vouchers on which tax was withheld
self.set("tax_withheld_vouchers", [])
for voucher_no, voucher_details in voucher_wise_amount.items():
self.append(
"tax_withheld_vouchers",
@@ -1694,7 +1769,6 @@ class PurchaseInvoice(BuyingController):
self.calculate_taxes_and_totals()
def allocate_advance_tds(self, tax_withholding_details, advance_taxes):
self.set("advance_tax", [])
for tax in advance_taxes:
allocated_amount = 0
pending_amount = flt(tax.tax_amount - tax.allocated_amount)

View File

@@ -10,13 +10,19 @@ import erpnext
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.buying.doctype.purchase_order.purchase_order import get_mapped_purchase_invoice
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice as make_pi_from_po
from erpnext.buying.doctype.purchase_order.test_purchase_order import (
create_pr_against_po,
create_purchase_order,
)
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
from erpnext.controllers.accounts_controller import InvalidQtyError, get_payment_terms
from erpnext.controllers.buying_controller import QtyMismatchError
from erpnext.exceptions import InvalidCurrency
from erpnext.projects.doctype.project.test_project import make_project
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.material_request.material_request import make_purchase_order
from erpnext.stock.doctype.material_request.test_material_request import make_material_request
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
make_purchase_invoice as create_purchase_invoice_from_receipt,
)
@@ -82,6 +88,31 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
# teardown
pi.delete()
def test_update_received_qty_in_material_request(self):
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
"""
Test if the received_qty in Material Request is updated correctly when
a Purchase Invoice with update_stock=True is submitted.
"""
mr = make_material_request(item_code="_Test Item", qty=10)
mr.save()
mr.submit()
po = make_purchase_order(mr.name)
po.supplier = "_Test Supplier"
po.save()
po.submit()
# Create a Purchase Invoice with update_stock=True
pi = make_purchase_invoice(po.name)
pi.update_stock = True
pi.insert()
pi.submit()
# Check if the received quantity is updated in Material Request
mr.reload()
self.assertEqual(mr.items[0].received_qty, 10)
def test_gl_entries_without_perpetual_inventory(self):
frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC")
pi = frappe.copy_doc(test_records[0])
@@ -1984,18 +2015,15 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
check_gl_entries(self, pi.name, expected_gle, nowdate())
pi.items[0].expense_account = "Service - _TC"
# Ledger reposted implicitly upon 'Update After Submit'
pi.save()
pi.load_from_db()
self.assertTrue(pi.repost_required)
pi.repost_accounting_entries()
expected_gle = [
["Creditors - _TC", 0.0, 1000, nowdate()],
["Service - _TC", 1000, 0.0, nowdate()],
]
check_gl_entries(self, pi.name, expected_gle, nowdate())
pi.load_from_db()
self.assertFalse(pi.repost_required)
@change_settings("Buying Settings", {"supplier_group": None})
def test_purchase_invoice_without_supplier_group(self):
@@ -2168,6 +2196,112 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
self.assertEqual(row.serial_no, "\n".join(serial_nos[:2]))
self.assertEqual(row.rejected_serial_no, serial_nos[2])
def test_make_pr_and_pi_from_po(self):
from erpnext.assets.doctype.asset.test_asset import create_asset_category
if not frappe.db.exists("Asset Category", "Computers"):
create_asset_category()
item = create_item(
item_code="_Test_Item", is_stock_item=0, is_fixed_asset=1, asset_category="Computers"
)
po = create_purchase_order(item_code=item.item_code)
pr = create_pr_against_po(po.name, 10)
pi = make_pi_from_po(po.name)
pi.insert()
pi.submit()
pr_gl_entries = frappe.db.sql(
"""select account, debit, credit
from `tabGL Entry` where voucher_type='Purchase Receipt' and voucher_no=%s
order by account asc""",
pr.name,
as_dict=1,
)
pr_expected_values = [
["Asset Received But Not Billed - _TC", 0, 5000],
["CWIP Account - _TC", 5000, 0],
]
for i, gle in enumerate(pr_gl_entries):
self.assertEqual(pr_expected_values[i][0], gle.account)
self.assertEqual(pr_expected_values[i][1], gle.debit)
self.assertEqual(pr_expected_values[i][2], gle.credit)
pi_gl_entries = frappe.db.sql(
"""select account, debit, credit
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
order by account asc""",
pi.name,
as_dict=1,
)
pi_expected_values = [
["Asset Received But Not Billed - _TC", 5000, 0],
["Creditors - _TC", 0, 5000],
]
for i, gle in enumerate(pi_gl_entries):
self.assertEqual(pi_expected_values[i][0], gle.account)
self.assertEqual(pi_expected_values[i][1], gle.debit)
self.assertEqual(pi_expected_values[i][2], gle.credit)
def test_adjust_incoming_rate_from_pi_with_multi_currency(self):
from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import (
make_landed_cost_voucher,
)
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)
# Increase the cost of the item
pr = make_purchase_receipt(
qty=10, rate=1, currency="USD", do_not_save=1, supplier="_Test Supplier USD"
)
pr.conversion_rate = 6300
pr.plc_conversion_rate = 1
pr.save()
pr.submit()
self.assertEqual(pr.conversion_rate, 6300)
self.assertEqual(pr.plc_conversion_rate, 1)
self.assertEqual(pr.base_grand_total, 6300 * 10)
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, 6300 * 10)
make_landed_cost_voucher(
company=pr.company,
receipt_document_type="Purchase Receipt",
receipt_document=pr.name,
charges=3000,
distribute_charges_based_on="Qty",
)
pi = create_purchase_invoice_from_receipt(pr.name)
for row in pi.items:
row.rate = 1.1
pi.save()
pi.submit()
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, 7230 * 10)
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 set_advance_flag(company, flag, default_account):
frappe.db.set_value(

View File

@@ -38,6 +38,7 @@
"column_break_30",
"discount_percentage",
"discount_amount",
"distributed_discount_amount",
"base_rate_with_margin",
"sec_break2",
"rate",
@@ -57,6 +58,7 @@
"base_net_rate",
"base_net_amount",
"valuation_rate",
"sales_incoming_rate",
"item_tax_amount",
"landed_cost_voucher_amount",
"rm_supp_cost",
@@ -105,6 +107,8 @@
"purchase_receipt",
"pr_detail",
"sales_invoice_item",
"material_request",
"material_request_item",
"item_weight_details",
"weight_per_unit",
"total_weight",
@@ -835,7 +839,7 @@
},
{
"collapsible": 1,
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount",
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount",
"fieldname": "section_break_26",
"fieldtype": "Section Break",
"label": "Discount and Margin"
@@ -934,12 +938,50 @@
{
"fieldname": "column_break_vbbb",
"fieldtype": "Column Break"
},
{
"fieldname": "material_request",
"fieldtype": "Link",
"label": "Material Request",
"no_copy": 1,
"options": "Material Request",
"print_hide": 1,
"read_only": 1,
"search_index": 1
},
{
"fieldname": "material_request_item",
"fieldtype": "Data",
"hidden": 1,
"label": "Material Request Item",
"no_copy": 1,
"oldfieldname": "pr_detail",
"oldfieldtype": "Data",
"print_hide": 1,
"read_only": 1,
"search_index": 1
},
{
"description": "Valuation rate for the item as per Sales Invoice (Only for Internal Transfers)",
"fieldname": "sales_incoming_rate",
"fieldtype": "Currency",
"hidden": 1,
"label": "Sales Incoming Rate",
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1
},
{
"fieldname": "distributed_discount_amount",
"fieldtype": "Currency",
"label": "Distributed Discount Amount",
"options": "currency"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:24.204495",
"modified": "2024-07-19 12:12:42.449298",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@@ -34,6 +34,7 @@ class PurchaseInvoiceItem(Document):
description: DF.TextEditor | None
discount_amount: DF.Currency
discount_percentage: DF.Percent
distributed_discount_amount: DF.Currency
enable_deferred_expense: DF.Check
expense_account: DF.Link | None
from_warehouse: DF.Link | None
@@ -52,6 +53,8 @@ class PurchaseInvoiceItem(Document):
manufacturer_part_no: DF.Data | None
margin_rate_or_amount: DF.Float
margin_type: DF.Literal["", "Percentage", "Amount"]
material_request: DF.Link | None
material_request_item: DF.Data | None
net_amount: DF.Currency
net_rate: DF.Currency
page_break: DF.Check
@@ -77,6 +80,7 @@ class PurchaseInvoiceItem(Document):
rejected_serial_no: DF.Text | None
rejected_warehouse: DF.Link | None
rm_supp_cost: DF.Currency
sales_incoming_rate: DF.Currency
sales_invoice_item: DF.Data | None
serial_and_batch_bundle: DF.Link | None
serial_no: DF.Text | None

View File

@@ -1,7 +1,5 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "format:ACC-REPOST-{#####}",
"creation": "2023-07-04 13:07:32.923675",
"default_view": "List",
"doctype": "DocType",
@@ -55,14 +53,15 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2024-03-27 13:10:32.013542",
"modified": "2024-06-03 17:30:37.012593",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Repost Accounting Ledger",
"naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
@@ -71,7 +70,9 @@
"read": 1,
"report": 1,
"role": "System Manager",
"select": 1,
"share": 1,
"submit": 1,
"write": 1
}
],

View File

@@ -167,6 +167,10 @@ def start_repost(account_repost_doc=str) -> None:
doc.make_gl_entries_on_cancel()
doc.docstatus = 1
if doc.doctype == "Sales Invoice":
doc.force_set_against_income_account()
else:
doc.force_set_against_expense_account()
doc.make_gl_entries()
elif doc.doctype in ["Payment Entry", "Journal Entry", "Expense Claim"]:

View File

@@ -17,7 +17,7 @@
"in_create": 1,
"issingle": 1,
"links": [],
"modified": "2024-03-27 13:10:32.287007",
"modified": "2024-06-06 13:56:37.908879",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Repost Accounting Ledger Settings",
@@ -30,13 +30,17 @@
"print": 1,
"read": 1,
"role": "Administrator",
"select": 1,
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"read": 1,
"role": "System Manager",
"select": 1
"select": 1,
"write": 1
}
],
"sort_field": "creation",

View File

@@ -1,6 +1,5 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2022-10-19 21:59:33.553852",
"doctype": "DocType",
"editable_grid": 1,
@@ -99,13 +98,15 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2024-03-27 13:10:32.740806",
"modified": "2024-06-03 17:31:04.472279",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Repost Payment Ledger",
"owner": "Administrator",
"permissions": [
{
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
@@ -114,7 +115,9 @@
"read": 1,
"report": 1,
"role": "System Manager",
"select": 1,
"share": 1,
"submit": 1,
"write": 1
},
{

View File

@@ -68,31 +68,6 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
if (this.frm.doc.repost_required && this.frm.doc.docstatus === 1) {
this.frm.set_intro(
__(
"Accounting entries for this invoice needs to be reposted. Please click on 'Repost' button to update."
)
);
this.frm
.add_custom_button(__("Repost Accounting Entries"), () => {
this.frm.call({
doc: this.frm.doc,
method: "repost_accounting_entries",
freeze: true,
freeze_message: __("Reposting..."),
callback: (r) => {
if (!r.exc) {
frappe.msgprint(__("Accounting Entries are reposted"));
me.frm.refresh();
}
},
});
})
.removeClass("btn-default")
.addClass("btn-warning");
}
if (this.frm.doc.is_return) {
this.frm.return_print_format = "Sales Invoice Return";
}
@@ -161,7 +136,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
const payment_is_overdue = doc.payment_schedule
.map((row) => Date.parse(row.due_date) < Date.now())
.reduce((prev, current) => prev || current);
.reduce((prev, current) => prev || current, false);
if (payment_is_overdue) {
this.frm.add_custom_button(
@@ -505,9 +480,13 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
frappe.msgprint(__("Please specify Company to proceed"));
} else {
var me = this;
const for_validate = me.frm.doc.is_return ? true : false;
return this.frm.call({
doc: me.frm.doc,
method: "set_missing_values",
args: {
for_validate: for_validate,
},
callback: function (r) {
if (!r.exc) {
if (r.message && r.message.print_format) {
@@ -592,49 +571,6 @@ cur_frm.cscript["Make Delivery Note"] = function () {
});
};
cur_frm.fields_dict.cash_bank_account.get_query = function (doc) {
return {
filters: [
["Account", "account_type", "in", ["Cash", "Bank"]],
["Account", "root_type", "=", "Asset"],
["Account", "is_group", "=", 0],
["Account", "company", "=", doc.company],
],
};
};
cur_frm.fields_dict.write_off_account.get_query = function (doc) {
return {
filters: {
report_type: "Profit and Loss",
is_group: 0,
company: doc.company,
},
};
};
// Write off cost center
//-----------------------
cur_frm.fields_dict.write_off_cost_center.get_query = function (doc) {
return {
filters: {
is_group: 0,
company: doc.company,
},
};
};
// Cost Center in Details Table
// -----------------------------
cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function (doc) {
return {
filters: {
company: doc.company,
is_group: 0,
},
};
};
cur_frm.cscript.income_account = function (doc, cdt, cdn) {
erpnext.utils.copy_value_in_all_rows(doc, cdt, cdn, "items", "income_account");
};
@@ -647,28 +583,6 @@ cur_frm.cscript.cost_center = function (doc, cdt, cdn) {
erpnext.utils.copy_value_in_all_rows(doc, cdt, cdn, "items", "cost_center");
};
cur_frm.set_query("debit_to", function (doc) {
return {
filters: {
account_type: "Receivable",
is_group: 0,
company: doc.company,
},
};
});
cur_frm.set_query("asset", "items", function (doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
filters: [
["Asset", "item_code", "=", d.item_code],
["Asset", "docstatus", "=", 1],
["Asset", "status", "in", ["Submitted", "Partially Depreciated", "Fully Depreciated"]],
["Asset", "company", "=", doc.company],
],
};
});
frappe.ui.form.on("Sales Invoice", {
setup: function (frm) {
frm.add_fetch("customer", "tax_id", "tax_id");
@@ -678,71 +592,132 @@ frappe.ui.form.on("Sales Invoice", {
frm.set_df_property("packed_items", "cannot_add_rows", true);
frm.set_df_property("packed_items", "cannot_delete_rows", true);
frm.set_query("account_for_change_amount", function () {
frm.set_query("cash_bank_account", function (doc) {
return {
filters: [
["Account", "account_type", "in", ["Cash", "Bank"]],
["Account", "root_type", "=", "Asset"],
["Account", "is_group", "=", 0],
["Account", "company", "=", doc.company],
],
};
});
frm.set_query("write_off_account", function (doc) {
return {
filters: {
account_type: ["in", ["Cash", "Bank"]],
company: frm.doc.company,
report_type: "Profit and Loss",
is_group: 0,
company: doc.company,
},
};
});
frm.set_query("write_off_cost_center", function (doc) {
return {
filters: {
is_group: 0,
company: doc.company,
},
};
});
frm.set_query("cost_center", "items", function (doc) {
return {
filters: {
company: doc.company,
is_group: 0,
},
};
});
frm.set_query("unrealized_profit_loss_account", function () {
frm.set_query("debit_to", function (doc) {
return {
filters: {
company: frm.doc.company,
account_type: "Receivable",
is_group: 0,
company: doc.company,
},
};
});
frm.set_query("asset", "items", function (doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
filters: [
["Asset", "item_code", "=", row.item_code],
["Asset", "docstatus", "=", 1],
["Asset", "status", "in", ["Submitted", "Partially Depreciated", "Fully Depreciated"]],
["Asset", "company", "=", doc.company],
],
};
});
frm.set_query("account_for_change_amount", function (doc) {
return {
filters: {
account_type: ["in", ["Cash", "Bank"]],
company: doc.company,
is_group: 0,
},
};
});
frm.set_query("unrealized_profit_loss_account", function (doc) {
return {
filters: {
company: doc.company,
is_group: 0,
root_type: "Liability",
},
};
});
frm.set_query("adjustment_against", function () {
frm.set_query("adjustment_against", function (doc) {
return {
filters: {
company: frm.doc.company,
customer: frm.doc.customer,
company: doc.company,
customer: doc.customer,
docstatus: 1,
},
};
});
frm.set_query("additional_discount_account", function () {
frm.set_query("additional_discount_account", function (doc) {
return {
filters: {
company: frm.doc.company,
company: doc.company,
is_group: 0,
report_type: "Profit and Loss",
},
};
});
frm.set_query("income_account", "items", function () {
frm.set_query("income_account", "items", function (doc) {
return {
query: "erpnext.controllers.queries.get_income_account",
filters: {
company: frm.doc.company,
company: doc.company,
disabled: 0,
},
};
});
(frm.custom_make_buttons = {
frm.custom_make_buttons = {
"Delivery Note": "Delivery",
"Sales Invoice": "Return / Credit Note",
"Payment Request": "Payment Request",
"Payment Entry": "Payment",
}),
(frm.fields_dict["timesheets"].grid.get_field("time_sheet").get_query = function (doc, cdt, cdn) {
return {
query: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet",
filters: { project: doc.project },
};
});
};
// discount account
frm.fields_dict["items"].grid.get_field("discount_account").get_query = function (doc) {
frm.set_query("time_sheet", "timesheets", function (doc, cdt, cdn) {
return {
query: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet",
filters: { project: doc.project },
};
});
frm.set_query("discount_account", "items", function (doc) {
return {
filters: {
report_type: "Profit and Loss",
@@ -750,9 +725,9 @@ frappe.ui.form.on("Sales Invoice", {
is_group: 0,
},
};
};
});
frm.fields_dict["items"].grid.get_field("deferred_revenue_account").get_query = function (doc) {
frm.set_query("deferred_revenue_account", "items", function (doc) {
return {
filters: {
root_type: "Liability",
@@ -760,7 +735,7 @@ frappe.ui.form.on("Sales Invoice", {
is_group: 0,
},
};
};
});
frm.set_query("company_address", function (doc) {
if (!doc.company) {
@@ -789,25 +764,23 @@ frappe.ui.form.on("Sales Invoice", {
};
});
// set get_query for loyalty redemption account
frm.fields_dict["loyalty_redemption_account"].get_query = function () {
frm.set_query("loyalty_redemption_account", function () {
return {
filters: {
company: frm.doc.company,
is_group: 0,
},
};
};
});
// set get_query for loyalty redemption cost center
frm.fields_dict["loyalty_redemption_cost_center"].get_query = function () {
frm.set_query("loyalty_redemption_cost_center", function () {
return {
filters: {
company: frm.doc.company,
is_group: 0,
},
};
};
});
},
// When multiple companies are set up. in case company name is changed set default company address
company: function (frm) {

View File

@@ -215,7 +215,6 @@
"is_internal_customer",
"is_discounted",
"remarks",
"repost_required",
"connections_tab"
],
"fields": [
@@ -1575,12 +1574,14 @@
"print_hide": 1
},
{
"fetch_from": "customer.language",
"fetch_if_empty": 1,
"fieldname": "language",
"fieldtype": "Data",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Print Language",
"length": 6,
"options": "Language",
"print_hide": 1,
"read_only": 1
},
@@ -2042,7 +2043,7 @@
{
"fieldname": "contact_and_address_tab",
"fieldtype": "Tab Break",
"label": "Contact & Address"
"label": "Address & Contact"
},
{
"fieldname": "payments_tab",
@@ -2126,15 +2127,6 @@
"label": "Write Off",
"width": "50%"
},
{
"default": "0",
"fieldname": "repost_required",
"fieldtype": "Check",
"hidden": 1,
"label": "Repost Required",
"no_copy": 1,
"read_only": 1
},
{
"fieldname": "incoterm",
"fieldtype": "Link",
@@ -2203,7 +2195,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2024-04-11 11:30:26.272441",
"modified": "2024-07-18 15:30:39.428519",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -136,7 +136,7 @@ class SalesInvoice(SellingController):
is_pos: DF.Check
is_return: DF.Check
items: DF.Table[SalesInvoiceItem]
language: DF.Data | None
language: DF.Link | None
letter_head: DF.Link | None
loyalty_amount: DF.Currency
loyalty_points: DF.Int
@@ -166,7 +166,6 @@ class SalesInvoice(SellingController):
project: DF.Link | None
redeem_loyalty_points: DF.Check
remarks: DF.SmallText | None
repost_required: DF.Check
represents_company: DF.Link | None
return_against: DF.Link | None
rounded_total: DF.Currency
@@ -316,17 +315,6 @@ class SalesInvoice(SellingController):
if not self.is_opening:
self.is_opening = "No"
if self.redeem_loyalty_points:
lp = frappe.get_doc("Loyalty Program", self.loyalty_program)
self.loyalty_redemption_account = (
lp.expense_account if not self.loyalty_redemption_account else self.loyalty_redemption_account
)
self.loyalty_redemption_cost_center = (
lp.cost_center
if not self.loyalty_redemption_cost_center
else self.loyalty_redemption_cost_center
)
self.set_against_income_account()
self.validate_time_sheets_are_submitted()
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount")
@@ -345,12 +333,7 @@ class SalesInvoice(SellingController):
if self.is_pos and self.is_return:
self.verify_payment_amount_is_negative()
if (
self.redeem_loyalty_points
and self.loyalty_program
and self.loyalty_points
and not self.is_consolidated
):
if self.redeem_loyalty_points and self.loyalty_points and not self.is_consolidated:
validate_loyalty_points(self, self.loyalty_points)
self.reset_default_field_value("set_warehouse", "items", "warehouse")
@@ -393,6 +376,9 @@ class SalesInvoice(SellingController):
validate_account_head(item.idx, item.income_account, self.company, "Income")
def set_tax_withholding(self):
if self.get("is_opening") == "Yes":
return
tax_withholding_details = get_party_tax_withholding_details(self)
if not tax_withholding_details:
@@ -452,6 +438,7 @@ class SalesInvoice(SellingController):
if not self.get(table_name):
continue
self.make_bundle_for_sales_purchase_return(table_name)
self.make_bundle_using_old_serial_batch_fields(table_name)
self.update_stock_ledger()
@@ -524,7 +511,7 @@ class SalesInvoice(SellingController):
)
if pos_closing_entry and pos_closing_entry[0]:
msg = _("To cancel a {} you need to cancel the POS Closing Entry {}.").format(
frappe.bold("Consolidated Sales Invoice"),
frappe.bold(_("Consolidated Sales Invoice")),
get_link_to_form("POS Closing Entry", pos_closing_entry[0]),
)
frappe.throw(msg, title=_("Not Allowed"))
@@ -565,7 +552,6 @@ class SalesInvoice(SellingController):
self.repost_future_sle_and_gle()
self.db_set("status", "Cancelled")
self.db_set("repost_required", 0)
if self.coupon_code:
update_coupon_code_count(self.coupon_code, "cancelled")
@@ -718,24 +704,23 @@ class SalesInvoice(SellingController):
data.sales_invoice = sales_invoice
def on_update_after_submit(self):
if hasattr(self, "repost_required"):
fields_to_check = [
"additional_discount_account",
"cash_bank_account",
"account_for_change_amount",
"write_off_account",
"loyalty_redemption_account",
"unrealized_profit_loss_account",
"is_opening",
]
child_tables = {
"items": ("income_account", "expense_account", "discount_account"),
"taxes": ("account_head",),
}
self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables)
if self.needs_repost:
self.validate_for_repost()
self.db_set("repost_required", self.needs_repost)
fields_to_check = [
"additional_discount_account",
"cash_bank_account",
"account_for_change_amount",
"write_off_account",
"loyalty_redemption_account",
"unrealized_profit_loss_account",
"is_opening",
]
child_tables = {
"items": ("income_account", "expense_account", "discount_account"),
"taxes": ("account_head",),
}
self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables)
if self.needs_repost:
self.validate_for_repost()
self.repost_accounting_entries()
def set_paid_amount(self):
paid_amount = 0.0
@@ -873,7 +858,7 @@ class SalesInvoice(SellingController):
if account.report_type != "Balance Sheet":
msg = (
_("Please ensure {} account is a Balance Sheet account.").format(frappe.bold("Debit To"))
_("Please ensure {} account is a Balance Sheet account.").format(frappe.bold(_("Debit To")))
+ " "
)
msg += _(
@@ -884,7 +869,7 @@ class SalesInvoice(SellingController):
if self.customer and account.account_type != "Receivable":
msg = (
_("Please ensure {} account {} is a Receivable account.").format(
frappe.bold("Debit To"), frappe.bold(self.debit_to)
frappe.bold(_("Debit To")), frappe.bold(self.debit_to)
)
+ " "
)
@@ -955,6 +940,10 @@ class SalesInvoice(SellingController):
against_acc.append(d.income_account)
self.against_income_account = ",".join(against_acc)
def force_set_against_income_account(self):
self.set_against_income_account()
frappe.db.set_value(self.doctype, self.name, "against_income_account", self.against_income_account)
def add_remarks(self):
if not self.remarks:
if self.po_no and self.po_date:
@@ -1210,6 +1199,8 @@ class SalesInvoice(SellingController):
self.make_precision_loss_gl_entry(gl_entries)
self.make_discount_gl_entries(gl_entries)
gl_entries = make_regional_gl_entries(gl_entries, self)
# merge gl entries before adding pos entries
gl_entries = merge_similar_entries(gl_entries)
@@ -1315,6 +1306,10 @@ class SalesInvoice(SellingController):
for item in self.get("items"):
if flt(item.base_net_amount, item.precision("base_net_amount")):
# Do not book income for transfer within same company
if self.is_internal_transfer():
continue
if item.is_fixed_asset:
asset = self.get_asset(item)
@@ -1373,37 +1368,33 @@ class SalesInvoice(SellingController):
self.set_asset_status(asset)
else:
# Do not book income for transfer within same company
if not self.is_internal_transfer():
income_account = (
item.income_account
if (not item.enable_deferred_revenue or self.is_return)
else item.deferred_revenue_account
)
income_account = (
item.income_account
if (not item.enable_deferred_revenue or self.is_return)
else item.deferred_revenue_account
)
amount, base_amount = self.get_amount_and_base_amount(
item, enable_discount_accounting
)
amount, base_amount = self.get_amount_and_base_amount(item, enable_discount_accounting)
account_currency = get_account_currency(income_account)
gl_entries.append(
self.get_gl_dict(
{
"account": income_account,
"against": self.customer,
"credit": flt(base_amount, item.precision("base_net_amount")),
"credit_in_account_currency": (
flt(base_amount, item.precision("base_net_amount"))
if account_currency == self.company_currency
else flt(amount, item.precision("net_amount"))
),
"cost_center": item.cost_center,
"project": item.project or self.project,
},
account_currency,
item=item,
)
account_currency = get_account_currency(income_account)
gl_entries.append(
self.get_gl_dict(
{
"account": income_account,
"against": self.customer,
"credit": flt(base_amount, item.precision("base_net_amount")),
"credit_in_account_currency": (
flt(base_amount, item.precision("base_net_amount"))
if account_currency == self.company_currency
else flt(amount, item.precision("net_amount"))
),
"cost_center": item.cost_center,
"project": item.project or self.project,
},
account_currency,
item=item,
)
)
# expense account gl entries
if cint(self.update_stock) and erpnext.is_perpetual_inventory_enabled(self.company):
@@ -1437,7 +1428,7 @@ class SalesInvoice(SellingController):
asset.set_status("Sold" if self.docstatus == 1 else None)
def make_loyalty_point_redemption_gle(self, gl_entries):
if cint(self.redeem_loyalty_points):
if cint(self.redeem_loyalty_points and self.loyalty_points and not self.is_consolidated):
gl_entries.append(
self.get_gl_dict(
{
@@ -1478,6 +1469,10 @@ class SalesInvoice(SellingController):
if skip_change_gl_entries and payment_mode.account == self.account_for_change_amount:
payment_mode.base_amount -= flt(self.change_amount)
against_voucher = self.name
if self.is_return and self.return_against and not self.update_outstanding_for_self:
against_voucher = self.return_against
if payment_mode.base_amount:
# POS, make payment entries
gl_entries.append(
@@ -1491,7 +1486,7 @@ class SalesInvoice(SellingController):
"credit_in_account_currency": payment_mode.base_amount
if self.party_account_currency == self.company_currency
else payment_mode.amount,
"against_voucher": self.name,
"against_voucher": against_voucher,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center,
},
@@ -1765,7 +1760,8 @@ class SalesInvoice(SellingController):
loyalty_program=self.loyalty_program,
include_expired_entry=True,
)
frappe.db.set_value("Customer", self.customer, "loyalty_program_tier", lp_details.tier_name)
customer = frappe.get_doc("Customer", self.customer)
customer.db_set("loyalty_program_tier", lp_details.tier_name)
def get_returned_amount(self):
from frappe.query_builder.functions import Sum
@@ -2070,7 +2066,7 @@ def make_delivery_note(source_name, target_doc=None):
"postprocess": update_item,
"condition": lambda doc: doc.delivered_by_supplier != 1,
},
"Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "add_if_empty": True},
"Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "reset_value": True},
"Sales Team": {
"doctype": "Sales Team",
"field_map": {"incentives": "incentives"},
@@ -2183,6 +2179,11 @@ def make_inter_company_purchase_invoice(source_name, target_doc=None):
return make_inter_company_transaction("Sales Invoice", source_name, target_doc)
@erpnext.allow_regional
def make_regional_gl_entries(gl_entries, doc):
return gl_entries
def make_inter_company_transaction(doctype, source_name, target_doc=None):
if doctype in ["Sales Invoice", "Sales Order"]:
source_doc = frappe.get_doc(doctype, source_name)
@@ -2640,6 +2641,10 @@ def create_dunning(source_name, target_doc=None, ignore_permissions=False):
target.closing_text = letter_text.get("closing_text")
target.language = letter_text.get("language")
# update outstanding
if source.payment_schedule and len(source.payment_schedule) == 1:
target.overdue_payments[0].outstanding = source.get("outstanding_amount")
target.validate()
return get_mapped_doc(

View File

@@ -2,8 +2,10 @@
# License: GNU General Public License v3. See license.txt
import copy
import json
import frappe
from frappe import qb
from frappe.model.dynamic_links import get_dynamic_link_map
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, flt, getdate, nowdate, today
@@ -1783,6 +1785,49 @@ class TestSalesInvoice(FrappeTestCase):
self.assertTrue(gle)
def test_gle_in_transaction_currency(self):
# create multi currency sales invoice with 2 items with same income account
si = create_sales_invoice(
customer="_Test Customer USD",
debit_to="_Test Receivable USD - _TC",
currency="USD",
conversion_rate=50,
do_not_submit=True,
)
# add 2nd item with same income account
si.append(
"items",
{
"item_code": "_Test Item",
"qty": 1,
"rate": 80,
"income_account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC",
},
)
si.submit()
gl_entries = frappe.db.sql(
"""select transaction_currency, transaction_exchange_rate,
debit_in_transaction_currency, credit_in_transaction_currency
from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s and account = 'Sales - _TC'
order by account asc""",
si.name,
as_dict=1,
)
expected_gle = {
"transaction_currency": "USD",
"transaction_exchange_rate": 50,
"debit_in_transaction_currency": 0,
"credit_in_transaction_currency": 180,
}
for gle in gl_entries:
for field in expected_gle:
self.assertEqual(expected_gle[field], gle[field])
def test_invoice_exchange_rate(self):
si = create_sales_invoice(
customer="_Test Customer USD",
@@ -2176,13 +2221,14 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(si.total_taxes_and_charges, 229)
self.assertEqual(si.rounding_adjustment, -0.20)
expected_values = [
["_Test Account Service Tax - _TC", 0.0, 114.50],
["_Test Account VAT - _TC", 0.0, 114.50],
[si.debit_to, 1501, 0.0],
["Round Off - _TC", 0.20, 0.0],
["Sales - _TC", 0.0, 1272.20],
]
round_off_account = frappe.get_cached_value("Company", "_Test Company", "round_off_account")
expected_values = {
"_Test Account Service Tax - _TC": [0.0, 114.50],
"_Test Account VAT - _TC": [0.0, 114.50],
si.debit_to: [1501, 0.0],
round_off_account: [0.20, 0.0],
"Sales - _TC": [0.0, 1272.20],
}
gl_entries = frappe.db.sql(
"""select account, sum(debit) as debit, sum(credit) as credit
@@ -2193,10 +2239,10 @@ class TestSalesInvoice(FrappeTestCase):
as_dict=1,
)
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[i][0], gle.account)
self.assertEqual(expected_values[i][1], gle.debit)
self.assertEqual(expected_values[i][2], gle.credit)
for gle in gl_entries:
expected_account_values = expected_values[gle.account]
self.assertEqual(expected_account_values[0], gle.debit)
self.assertEqual(expected_account_values[1], gle.credit)
def test_rounding_adjustment_3(self):
from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import (
@@ -2245,6 +2291,7 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(si.total_taxes_and_charges, 480.86)
self.assertEqual(si.rounding_adjustment, -0.02)
round_off_account = frappe.get_cached_value("Company", "_Test Company", "round_off_account")
expected_values = dict(
(d[0], d)
for d in [
@@ -2252,7 +2299,7 @@ class TestSalesInvoice(FrappeTestCase):
["_Test Account Service Tax - _TC", 0.0, 240.43],
["_Test Account VAT - _TC", 0.0, 240.43],
["Sales - _TC", 0.0, 4007.15],
["Round Off - _TC", 0.01, 0.0],
[round_off_account, 0.01, 0.0],
]
)
@@ -2281,8 +2328,9 @@ class TestSalesInvoice(FrappeTestCase):
as_dict=1,
)
self.assertEqual(round_off_gle.cost_center, "_Test Cost Center 2 - _TC")
self.assertEqual(round_off_gle.location, "Block 1")
if round_off_gle:
self.assertEqual(round_off_gle.cost_center, "_Test Cost Center 2 - _TC")
self.assertEqual(round_off_gle.location, "Block 1")
disable_dimension()
@@ -2906,13 +2954,9 @@ class TestSalesInvoice(FrappeTestCase):
si.items[0].income_account = "Service - _TC"
si.additional_discount_account = "_Test Account Sales - _TC"
si.taxes[0].account_head = "TDS Payable - _TC"
# Ledger reposted implicitly upon 'Update After Submit'
si.save()
si.load_from_db()
self.assertTrue(si.repost_required)
si.repost_accounting_entries()
expected_gle = [
["_Test Account Sales - _TC", 22.0, 0.0, nowdate()],
["Debtors - _TC", 88, 0.0, nowdate()],
@@ -2922,9 +2966,6 @@ class TestSalesInvoice(FrappeTestCase):
check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
si.load_from_db()
self.assertFalse(si.repost_required)
def test_asset_depreciation_on_sale_with_pro_rata(self):
"""
Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on its date of sale.
@@ -3056,6 +3097,84 @@ class TestSalesInvoice(FrappeTestCase):
party_link.delete()
frappe.db.set_single_value("Accounts Settings", "enable_common_party_accounting", 0)
def test_sales_invoice_against_supplier_usd_with_dimensions(self):
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
make_customer,
)
from erpnext.accounts.doctype.party_link.party_link import create_party_link
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
# create a customer
customer = make_customer(customer="_Test Common Supplier USD")
cust_doc = frappe.get_doc("Customer", customer)
cust_doc.default_currency = "USD"
cust_doc.save()
# create a supplier
supplier = create_supplier(supplier_name="_Test Common Supplier USD").name
supp_doc = frappe.get_doc("Supplier", supplier)
supp_doc.default_currency = "USD"
supp_doc.save()
# create a party link between customer & supplier
party_link = create_party_link("Supplier", supplier, customer)
# enable common party accounting
frappe.db.set_single_value("Accounts Settings", "enable_common_party_accounting", 1)
# create a dimension and make it mandatory
if not frappe.get_all("Accounting Dimension", filters={"document_type": "Department"}):
dim = frappe.get_doc(
{
"doctype": "Accounting Dimension",
"document_type": "Department",
"dimension_defaults": [{"company": "_Test Company", "mandatory_for_bs": True}],
}
)
dim.save()
else:
dim = frappe.get_doc(
"Accounting Dimension",
frappe.get_all("Accounting Dimension", filters={"document_type": "Department"})[0],
)
dim.disabled = False
dim.dimension_defaults = []
dim.append("dimension_defaults", {"company": "_Test Company", "mandatory_for_bs": True})
dim.save()
# create a sales invoice
si = create_sales_invoice(
customer=customer, parent_cost_center="_Test Cost Center - _TC", do_not_submit=True
)
si.department = "All Departments"
si.save().submit()
# check outstanding of sales invoice
si.reload()
self.assertEqual(si.status, "Paid")
self.assertEqual(flt(si.outstanding_amount), 0.0)
# check creation of journal entry
jv = frappe.get_all(
"Journal Entry Account",
{
"account": si.debit_to,
"party_type": "Customer",
"party": si.customer,
"reference_type": si.doctype,
"reference_name": si.name,
"department": "All Departments",
},
pluck="credit_in_account_currency",
)
self.assertTrue(jv)
self.assertEqual(jv[0], si.grand_total)
dim.disabled = True
dim.save()
party_link.delete()
frappe.db.set_single_value("Accounts Settings", "enable_common_party_accounting", 0)
def test_payment_statuses(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
@@ -3605,6 +3724,65 @@ class TestSalesInvoice(FrappeTestCase):
check_gl_entries(self, pe.name, expected_gle, nowdate(), voucher_type="Payment Entry")
set_advance_flag(company="_Test Company", flag=0, default_account="")
def test_loyalty_points_redemption_with_shopping_cart(self):
from erpnext.accounts.doctype.loyalty_program.test_loyalty_program import (
create_records,
create_sales_invoice_record,
)
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
# Set up loyalty program
create_records()
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty")
create_sales_invoice_record(10).insert().submit()
# Create a sales order
so = make_sales_order(qty=10, do_not_save=True, customer="Test Loyalty Customer")
so.name = "_T-Sales Order LP-0001"
so.order_type = "Shopping Cart"
so.loyalty_points = 50
so.loyalty_amount = 50
so.insert()
so.submit()
# Create sales invoice from the sales order
si = make_sales_invoice(so.name)
from frappe.model.trace import traced_field_context
with traced_field_context(si.__class__, "loyalty_program", forbidden_values=[None]):
si.insert()
si.submit()
# Check if loyalty points are applied correctly
self.assertEqual(si.loyalty_program, "Test Single Loyalty")
self.assertEqual(si.loyalty_points, 50)
self.assertEqual(si.loyalty_amount, 50)
# Check GL entries for loyalty points redemption
gl_entries = frappe.get_all(
"GL Entry",
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
fields=["account", "debit", "credit"],
)
loyalty_account = frappe.db.get_value("Loyalty Program", "Test Single Loyalty", "expense_account")
expected_gl_entries = [
{"account": si.debit_to, "debit": si.grand_total, "credit": 0},
{"account": si.items[0].income_account, "debit": 0, "credit": si.net_total},
{"account": loyalty_account, "debit": 50, "credit": 0},
]
for entry in expected_gl_entries:
self.assertTrue(
any(
gl_entry.account == entry["account"]
and gl_entry.debit == entry["debit"]
and gl_entry.credit == entry["credit"]
for gl_entry in gl_entries
)
)
def test_pulling_advance_based_on_debit_to(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
@@ -3690,9 +3868,9 @@ class TestSalesInvoice(FrappeTestCase):
map_docs(
method="erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
source_names=frappe.json.dumps([dn1.name, dn2.name]),
source_names=json.dumps([dn1.name, dn2.name]),
target_doc=si,
args=frappe.json.dumps({"customer": dn1.customer, "merge_taxes": 1, "filtered_children": []}),
args=json.dumps({"customer": dn1.customer, "merge_taxes": 1, "filtered_children": []}),
)
si.save().submit()
@@ -3731,6 +3909,40 @@ class TestSalesInvoice(FrappeTestCase):
]
self.assertEqual(expected, actual)
def test_pos_returns_without_update_outstanding_for_self(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(qty=10, do_not_save=True)
pos.is_pos = 1
pos.pos_profile = pos_profile.name
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 500}
)
pos.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 500})
pos.save().submit()
pos_return = make_sales_return(pos.name)
pos_return.update_outstanding_for_self = False
pos_return.save().submit()
gle = qb.DocType("GL Entry")
res = (
qb.from_(gle)
.select(gle.against_voucher)
.distinct()
.where(
gle.is_cancelled.eq(0) & gle.voucher_no.eq(pos_return.name) & gle.against_voucher.notnull()
)
.run(as_list=1)
)
self.assertEqual(len(res), 1)
self.assertEqual(res[0][0], pos_return.return_against)
def set_advance_flag(company, flag, default_account):
frappe.db.set_value(

View File

@@ -37,6 +37,7 @@
"column_break_19",
"discount_percentage",
"discount_amount",
"distributed_discount_amount",
"base_rate_with_margin",
"section_break1",
"rate",
@@ -253,7 +254,7 @@
},
{
"collapsible": 1,
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount",
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount",
"fieldname": "discount_and_margin",
"fieldtype": "Section Break",
"label": "Discount and Margin"
@@ -870,7 +871,8 @@
"label": "Purchase Order",
"options": "Purchase Order",
"print_hide": 1,
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "column_break_92",
@@ -921,12 +923,18 @@
{
"fieldname": "column_break_ytgd",
"fieldtype": "Column Break"
},
{
"fieldname": "distributed_discount_amount",
"fieldtype": "Currency",
"label": "Distributed Discount Amount",
"options": "currency"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:10:36.139679",
"modified": "2024-06-02 06:14:40.009020",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

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