Compare commits

..

431 Commits

Author SHA1 Message Date
Ankush Menat
b189fc46b0 fix: submit JVs synchronously if in background job 2024-03-11 13:17:00 +05:30
Deepesh Garg
58e1548640 Merge pull request #40248 from ernestoruiz89/patch-5
chore: Add translate function to text "after"
2024-03-10 22:33:28 +05:30
Deepesh Garg
b660d98f20 Merge pull request #40349 from pps190/fix-rename-tax-rule
fix: allow tax rule to be renamed
2024-03-10 21:14:38 +05:30
Deepesh Garg
dee49e6078 Merge pull request #40344 from pps190/fix-get-default-company
fix: get_user_default_as_list args order
2024-03-10 21:14:08 +05:30
Ankush Menat
f4d69f16c0 Merge pull request #40206 from barredterra/bulk-format-js
ci: add prettier to pre-commit
2024-03-10 20:01:49 +05:30
Deepesh Garg
c5b94df188 Merge pull request #40195 from Nihantra-Patel/fix_timesheet_invoice
fix: skip timesheet on return time
2024-03-10 19:59:03 +05:30
Ankush Menat
0b100782e2 chore: update blame ignore 2024-03-10 19:46:53 +05:30
Ankush Menat
ec74a5e566 style: format js files 2024-03-10 19:45:40 +05:30
barredterra
2c16036ef3 ci: add prettier to pre-commit 2024-03-10 19:45:18 +05:30
Deepesh Garg
1f4c86136f Merge pull request #39886 from barredterra/refactor-sales-invoice-item
refactor(Sales Invoice): move methods into child row controller
2024-03-10 19:44:16 +05:30
Deepesh Garg
b0fcb014c1 Merge pull request #40294 from barredterra/fix-bisect-accounting-statements
fix: define dates before usage
2024-03-10 19:30:29 +05:30
Deepesh Garg
65c8605b88 Merge pull request #40325 from deepeshgarg007/psoa_sender_email
fix: Sender email in process statements of accounts
2024-03-10 19:26:05 +05:30
Deepesh Garg
4c6d28a299 Merge pull request #40323 from deepeshgarg007/project_sales_filter
fix: Filter for projects in Sales Cycle
2024-03-10 19:25:48 +05:30
Deepesh Garg
962b51d6d5 Merge pull request #40355 from deepeshgarg007/blanket_order_rate
fix: Blanket order rate getting changed on converting to order
2024-03-10 18:44:11 +05:30
Deepesh Garg
9702a65a0f fix: Blanket order rate getting changed on converting to order 2024-03-10 17:39:20 +05:30
ruthra kumar
d69c593f93 Merge pull request #39681 from ruthra-kumar/fix_gl_logic_in_advance_as_liability
fix: incorrect advance paid in Sales/Purchase Order
2024-03-10 16:38:43 +05:30
s-aga-r
1e09f584d5 Merge pull request #40273 from s-aga-r/FIX-40272
fix: MR Default Supplier search query
2024-03-10 11:39:59 +05:30
Devin Slauenwhite
0d6afda6b8 fix: allow tax rule to be renamed 2024-03-09 08:09:16 -05:00
Devin Slauenwhite
ac1961b687 fix: get_user_default_as_list args order 2024-03-08 18:09:11 -05:00
s-aga-r
c0a1f298a1 fix: MR Default Supplier search query 2024-03-08 20:32:00 +05:30
Frappe PR Bot
55b9664115 fix: sync translations from crowdin (#40287) 2024-03-07 13:35:21 +01:00
Nihantra C. Patel
68baa3612a fix: load ignored doctype and include Mode of Payment Account (#40334) 2024-03-07 17:43:00 +05:30
rohitwaghchaure
01856a6e9d fix: use serial/batch field for rejected items (#40327) 2024-03-07 14:14:19 +05:30
Deepesh Garg
65a2f3d12c fix: Sender email in process statements of accounts 2024-03-07 10:08:51 +05:30
Deepesh Garg
d0e0b66b2f fix: Filter for projects in Sales Cycle 2024-03-07 09:14:56 +05:30
Raffael Meyer
4b38139b44 Merge pull request #40317 from barredterra/parcel-mandatory-fields 2024-03-06 19:24:47 +01:00
barredterra
898c6e30eb fix(Shipment Parcel): make length, width and height non-mandatory
It's tedious to enter all these values and some shipping providers only need to know the weigth and quantity. Companies can alwas cutomize the values to be mandatory, but the reverse is not possible. I'll make sure that the erpnext-shipping app does not break because of this (or fix any problems).
2024-03-06 16:52:19 +01:00
rohitwaghchaure
cef6291311 fix: use serial batch fields for subcontracting receipt (#40311) 2024-03-06 19:43:36 +05:30
Corentin Flr
a93d14b3f7 fix(accounts): Allow setting Number of new Cost Center (#40212) 2024-03-06 19:33:15 +05:30
rohitwaghchaure
48da952fd7 fix: not able to cancel purchase receipt for old subcontracting flow (#40298) 2024-03-06 12:51:04 +05:30
rohitwaghchaure
e178ffc3c1 fix: stock ledger balance qty for the batch (#40274) 2024-03-06 12:50:44 +05:30
rohitwaghchaure
1eaa386657 fix: batch no not copied while making Material Consumption entry (#40290) 2024-03-06 12:50:26 +05:30
barredterra
171b8af3ee fix: define dates before usage 2024-03-05 15:56:42 +01:00
Raffael Meyer
031465f5ec Merge pull request #40286 from barredterra/crowdin-pr-title
chore: set PR title for translation updates
2024-03-05 15:15:12 +01:00
Raffael Meyer
f44a841af7 ci: auto-generate potfile (#40288) 2024-03-05 18:06:31 +05:30
barredterra
28ac53a704 chore: set PR title for translation updates 2024-03-05 11:27:46 +01:00
Frappe PR Bot
bdc0175fe3 chore: sync translations from crowdin 2024-03-05 11:24:35 +01:00
ruthra kumar
e58c2dd43d Merge pull request #40278 from ruthra-kumar/filter_on_party_type_as_well_on_tcs
fix: incorrect TCS on customer and suppliers with same name
2024-03-05 15:22:41 +05:30
Harsh Khatri
092999f2a6 fix: update status of Email Campaign (#39776) 2024-03-05 09:44:32 +00:00
ruthra kumar
e52c4c8f22 refactor(test): make sure party has USD account
1. Don't reset 'party_account_currency' of SO/PO  upon Payment Entry
cancellation. This happens when there are no payments against a SO/PO
2024-03-05 14:56:29 +05:30
ruthra kumar
d9a0494fc3 fix: advance paid amount and ledger entries against SO/PO 2024-03-05 14:56:29 +05:30
ruthra kumar
cb2529cec8 refactor(test): use get_party_account for reference details section 2024-03-05 14:56:29 +05:30
ruthra kumar
158112896e refactor(test): reference details will have account 2024-03-05 14:56:29 +05:30
ruthra kumar
9d9b83362a fix: incorrect advance paid in Sales/Purchase Order 2024-03-05 14:56:29 +05:30
ruthra kumar
9904a9868c fix: incorrect TCS on customer and suppliers with same name 2024-03-05 14:55:51 +05:30
rohitwaghchaure
34051bc04f chore: fixed fetch from (#40270) 2024-03-05 13:44:02 +05:30
Nihantra C. Patel
8e2f9787c1 fix: report path from the Item and Putaway Rule list (#40190) 2024-03-04 19:43:33 +05:30
rohitwaghchaure
6379238893 perf: serial and batch bundle valuation (reposting) (#40255)
perf: serial and batch bundle valuation
2024-03-04 12:04:41 +05:30
Gursheen Kaur Anand
031b99f373 Merge pull request #40250 from GursheenK/company-filter-in-cost-center-allocation
fix(minor): company filter in cost center allocation
2024-03-03 18:13:48 +05:30
Gursheen Anand
51909077bd feat: add company filter to child table field 2024-03-03 18:08:23 +05:30
Ernesto Ruiz
d0140412cd chore: Add translate function to text "after" 2024-03-02 15:46:43 -06:00
rohitwaghchaure
e7d707797a fix: rate change on changing of the qty (#40241) 2024-03-02 16:44:07 +05:30
ruthra kumar
f2f5c1a0eb Merge pull request #40220 from ruthra-kumar/exc_gain_loss_on_journal_against_journals
refactor: Gain/Loss Journal creation for Journals against Journals
2024-03-02 15:36:27 +05:30
ruthra kumar
ceee93e0e8 Merge pull request #40149 from ruthra-kumar/filter_on_party_while_fetching_exc_rate_on_je
fix: incorrect exchange rate if JE has multi parties
2024-03-02 13:51:20 +05:30
ruthra kumar
ed95d41a51 test: exchange rate fetch on JE with multiple forex parties 2024-03-02 13:18:31 +05:30
ruthra kumar
eaac02655b fix: don't override reference exchange rate 2024-03-02 13:18:27 +05:30
rohitwaghchaure
72ac56b6c4 fix: do not allow to cancel incomplete reposting (#40224) 2024-03-02 12:59:59 +05:30
ruthra kumar
e017421708 Merge pull request #38561 from blaggacao/feat/add-delivery-cutoff-date-on-so
feat(delivery): add cutoff item date for so delivery items
2024-03-02 12:55:00 +05:30
Nihantra C. Patel
13b05aa7fb fix: uom wise price in sales or purchase transaction (#40216)
fix: uom wise price
2024-03-02 05:18:30 +05:30
rohitwaghchaure
a5232d9c10 fix: serial no valuation rate (#40221) 2024-03-01 22:26:54 +05:30
ruthra kumar
8a5078b826 test: gain/loss on Journals against Journals 2024-03-01 20:10:57 +05:30
ruthra kumar
5b67631d40 fix: allow gain/loss for Journals against Journals 2024-03-01 17:46:42 +05:30
ruthra kumar
0aa72f841d fix: make use of 'flt' to prevent really low precision exc gain/loss 2024-03-01 17:36:56 +05:30
David Arnold
b8dac84a90 feat: add selling setting for cutoff date 2024-03-01 12:12:07 +01:00
Nihantra Patel
79c492cc4b fix: skip timesheet on return time and revert code 2024-03-01 09:26:49 +05:30
Nihantra C. Patel
a8eb5e5c85 Merge branch 'frappe:develop' into fix_timesheet_invoice 2024-03-01 09:17:34 +05:30
Raffael Meyer
863abc3ee5 Merge pull request #40203 from barredterra/filter-project-department 2024-02-29 18:28:59 +01:00
Deepesh Garg
93c2762f7b Merge pull request #39701 from GursheenK/check-paid-amount-for-orders-before-request
fix: check order paid amount before payment request
2024-02-29 21:24:16 +05:30
Rushabh Mehta
c067ac16a7 Merge pull request #39584 from GursheenK/provisional-accounting-reverse-amt
fix: use receipt amount for reverse provisional entry
2024-02-29 21:16:05 +05:30
barredterra
5e736f0d06 fix(Project): filter department by company 2024-02-29 16:44:46 +01:00
ruthra kumar
983f71975a Merge pull request #40197 from ruthra-kumar/ignore_self_on_gl_account_valiation
fix: ignore self on GL account validation for Bank Account
2024-02-29 19:54:32 +05:30
Raffael Meyer
b235f48067 Merge pull request #39936 from barredterra/label-context 2024-02-29 15:09:49 +01:00
ruthra kumar
9d3614597c Merge pull request #40196 from ruthra-kumar/use_debit_or_credit_to_account_while_fetching_advance
fix: include debit_to or credit_to account while fetching advance on Sales/Purchase Invoice
2024-02-29 17:51:04 +05:30
ruthra kumar
3c19186654 fix: ignore self on GL account validation for Bank Account 2024-02-29 17:39:29 +05:30
ruthra kumar
646e9ca0dd test: advance pulling logic on Sales/Purchase Invoice 2024-02-29 17:31:08 +05:30
ruthra kumar
3327599c9d fix: include Debit To/Credit To account while fetching advance 2024-02-29 17:18:42 +05:30
Nihantra Patel
dd70fb5f7e fix: skip timesheet link on return time 2024-02-29 15:31:53 +05:30
Gursheen Kaur Anand
ac2b53bf15 Merge pull request #40176 from GursheenK/validating-po-in-so-ux
fix(minor): make warning for previously existing SO an alert
2024-02-29 11:32:44 +05:30
Raffael Meyer
5c47087f20 feat: add persian language (#40178)
* chore: remove locale dir from .gitignore

* feat: add persian language
2024-02-29 05:28:57 +00:00
Rucha Mahabal
29f91a7919 fix(setup): avoid duplicate entry for Analytics role (#40183) 2024-02-29 05:23:30 +00:00
Gursheen Kaur Anand
f6fdfd2c01 Merge pull request #40174 from GursheenK/common-free-item-promotional-scheme
fix: promotional scheme remove free item if pricing rule matches
2024-02-29 10:18:27 +05:30
Gursheen Anand
24dcd64c16 fix: make warning for previously existing SO an alert 2024-02-28 18:01:27 +05:30
Frappe PR Bot
9dcdd5b5ef chore: New Crowdin updates (#40052)
* New translations main.pot (French)

* New translations main.pot (Spanish)

* New translations main.pot (Arabic)

* New translations main.pot (German)

* New translations main.pot (French)

* New translations main.pot (Spanish)

* New translations main.pot (Arabic)

* New translations main.pot (German)

* New translations main.pot (German)

* New translations main.pot (German)

* New translations main.pot (German)

* New translations main.pot (German)

* New translations main.pot (German)

* New translations main.pot (German)
2024-02-28 16:32:43 +05:30
Gursheen Anand
fea20db262 fix: remove free item row only if pricing rule matches 2024-02-28 12:47:41 +05:30
rohitwaghchaure
043d9e3986 fix: Email Template None not found (#40167) 2024-02-27 22:30:01 +05:30
Deepesh Garg
dde4d9e53c Merge pull request #40162 from vorasmit/ic-deps
fix: add flags for repost to ensure correct accounting from India Compliance App
2024-02-27 22:08:09 +05:30
Deepesh Garg
36a0569df2 Merge pull request #40137 from ljain112/fix-tax-breakup
fix: default taxable value for item not found in item list
2024-02-27 22:07:39 +05:30
rohitwaghchaure
f8ba560394 fix: Supplier users not able to see RFQ on the Portal (#40161) 2024-02-27 21:05:19 +05:30
Smit Vora
93170a56a9 fix: add flags for repost to ensure correct accounting from India Compliance App 2024-02-27 20:28:18 +05:30
rohitwaghchaure
6f5815e44f fix: parent warehouse checks in the production plan for sub-assemblies (#40150) 2024-02-27 16:46:47 +05:30
Nabin Hait
0c52eb913b Merge pull request #40102 from GursheenK/update_billed_amount_for_purchases
feat: toggle updation of billed amount in previous purchase docs
2024-02-27 15:49:22 +05:30
Gursheen Kaur Anand
519682bb0e Merge pull request #40095 from GursheenK/unique-gl-account-for-plaid-bank-accounts
fix: unique GL account for plaid bank accounts
2024-02-27 15:38:03 +05:30
ruthra kumar
694c17487d fix: incorrect exchange rate if JE has multi parties 2024-02-27 15:34:34 +05:30
Gursheen Kaur Anand
5b8b40c13b Merge pull request #40143 from GursheenK/hide-company-typeerror
fix(minor): type error for missing form object in hide_company util
2024-02-27 13:14:02 +05:30
Gursheen Anand
ceeb8fc9e5 fix: use frm instead of cur_frm 2024-02-27 13:05:29 +05:30
Gursheen Kaur Anand
b193fafe49 Merge pull request #37477 from GursheenK/editable-journal-entries
feat: editable journal entries
2024-02-27 12:59:18 +05:30
Sajad Alimoradi
c310da7b29 fix: Translate 'mode of payments' in the 'point of sale'. (#39467)
- Due to a language change, the name of 'mode of payments' was not translated in the placeholder.
2024-02-27 07:15:20 +00:00
Rushabh Mehta
d6b29d1cd7 Merge pull request #39719 from niyazrazak/patch-18
feat: project field in installation note
2024-02-27 12:44:39 +05:30
Gursheen Kaur Anand
303433c0ae Merge branch 'develop' into editable-journal-entries 2024-02-27 12:43:32 +05:30
Gursheen Anand
20fa3da950 fix: type error for missing frm obj 2024-02-27 11:18:58 +05:30
rohitwaghchaure
bc9c480246 fix: use serial batch fields for packed items (#40140) 2024-02-26 23:57:52 +05:30
rohitwaghchaure
8aa2b7c183 fix: currency symbol in landed cost voucher and material request (#40138) 2024-02-26 22:48:10 +05:30
rohitwaghchaure
08caa7cfa1 fix: Data too long for column 'serial_no' at row 1 (#40098) 2024-02-26 18:49:56 +05:30
ljain112
5885978fc2 fix: default taxable value for item not found in item list 2024-02-26 18:41:33 +05:30
ruthra kumar
122373fcd3 Merge pull request #40133 from ruthra-kumar/reset_advance_amount_on_unreconciliation
fix: reset advance amount on unreconciliation of Sales/Purchase Orders
2024-02-26 17:51:36 +05:30
ruthra kumar
1f01ff3487 test: advance paid update on sales/purchase order unreconciliation 2024-02-26 17:32:25 +05:30
ruthra kumar
c9e2f03a3a fix: on unreconciliation, update advance paid 2024-02-26 17:08:56 +05:30
ruthra kumar
924b08e395 Merge pull request #40113 from ruthra-kumar/patch_for_dimension_creation_in_reconciliation_tool
refactor: patch to setup dimensions in Reconciliation tool
2024-02-26 11:58:51 +05:30
ruthra kumar
461fb183fc refactor: patch to setup dimensions in Reconciliation tool 2024-02-26 11:34:37 +05:30
Gursheen Kaur Anand
c9ff769d28 Merge pull request #40062 from GursheenK/sales-person-target-contributions
fix: sales person / partner achieved targets in report
2024-02-26 10:37:14 +05:30
Gursheen Kaur Anand
3658c4754f Merge pull request #40105 from GursheenK/tax-amount-label
fix(minor): tax amount label according to party type
2024-02-26 10:33:32 +05:30
Gursheen Anand
9c8d103d8a fix: amount label according to party type 2024-02-25 21:32:24 +05:30
Gursheen Anand
6d40844894 test: pr billed amount against debit note 2024-02-25 20:03:33 +05:30
Gursheen Anand
81dbfe189e test: po billed amount against debit note 2024-02-25 19:40:28 +05:30
rohitwaghchaure
75f8464724 fix: capacity planning issue in the job card (#40092)
* fix: capacity planning issue in the job card

* test: test case to test capacity planning for workstation
2024-02-25 19:06:52 +05:30
ruthra kumar
e240ccd305 Merge pull request #40096 from ruthra-kumar/fix_fiscal_year_exception_on_demo_data_setup
fix: Fiscal Year exception on demo data setup
2024-02-25 15:42:04 +05:30
ruthra kumar
3c3c57c674 fix: Fiscal Year exception on demo data setup 2024-02-25 15:26:16 +05:30
Gursheen Anand
c42444ab3b fix: remove config for default bank account in test 2024-02-25 13:18:30 +05:30
Gursheen Anand
bf6e32a960 fix: unique gl account for plaid bank accounts 2024-02-25 13:17:41 +05:30
Gursheen Anand
9f6535472d feat: update billed amount in PO and PR 2024-02-25 11:59:44 +05:30
ruthra kumar
7cb07425b1 Merge pull request #40073 from ruthra-kumar/update_payments_section_on_item_removal
refactor: update payments section on item removal
2024-02-25 09:26:52 +05:30
rohitwaghchaure
4c9048fb39 fix: do not make MR against raw materials of available sub assemblies (#40085) 2024-02-24 17:04:55 +05:30
rohitwaghchaure
f4222be027 Merge pull request #40081 from rohitwaghchaure/fixed-10401
fix: Cannot read properties of undefined
2024-02-24 15:57:21 +05:30
Rohit Waghchaure
44ed52c5cf fix: Cannot read properties of undefined 2024-02-24 15:33:59 +05:30
rohitwaghchaure
8aaddb0f9e Merge pull request #40079 from rohitwaghchaure/fixed-linter-issue
chore: change label name
2024-02-24 13:09:57 +05:30
Rohit Waghchaure
635174f1ce fix: change label name 2024-02-24 12:51:52 +05:30
ruthra kumar
406793a6ff refactor: update payments section on item removal 2024-02-23 17:29:08 +05:30
Gursheen Anand
7566c1ee78 test: sales person target variance 2024-02-23 15:05:36 +05:30
ruthra kumar
97c3e27c60 Merge pull request #39830 from Nihantra-Patel/fix_check_credit_limit
fix: check_credit_limit on_update_after_submit of Sales Order
2024-02-23 14:20:36 +05:30
ruthra kumar
467c0898e9 test: credit limit on update after submit 2024-02-23 14:03:09 +05:30
Gursheen Kaur Anand
26ec697a0b Merge pull request #40040 from GursheenK/skip-discount-validation-for-rate-adjustment-entries
fix: skip max discount validation for rate adjustment
2024-02-23 12:56:38 +05:30
Gursheen Kaur Anand
3294282880 Merge pull request #40035 from GursheenK/delete-ple-on-deletion-of-transactions
fix: delete PLE containing invoice in against
2024-02-23 12:36:14 +05:30
Gursheen Anand
a823f16dff feat: show contributed qty in transaction summary 2024-02-23 12:17:54 +05:30
Gursheen Anand
339698d172 fix: only consider contributed qty towards achieved targets 2024-02-23 12:14:54 +05:30
ruthra kumar
dd23ddcd6c Merge pull request #40011 from ruthra-kumar/cr_dr_note_with_payments
fix: Ledger entries for Cr/Dr notes with POS Payments
2024-02-23 06:01:37 +05:30
ruthra kumar
20eff568b1 Merge pull request #39831 from Nihantra-Patel/fix_payment_period_si
fix: remove cancelled payment entry from Payment Period Based On Invoice Date
2024-02-23 06:00:02 +05:30
ruthra kumar
3634c4c284 refactor: skip popup for POS invoices 2024-02-23 05:45:04 +05:30
Raffael Meyer
2e0aaf3521 Merge pull request #40051 from barredterra/transaction-due-date-translatability 2024-02-22 18:43:19 +01:00
barredterra
6249965605 feat: clear payment terms and schedule 2024-02-22 18:39:17 +01:00
Raffael Meyer
a9f8af2fd1 Merge pull request #40050 from barredterra/transaction-due-date-translatability 2024-02-22 18:32:03 +01:00
barredterra
6d43d46fbc fix: translatability 2024-02-22 18:30:20 +01:00
ruthra kumar
4288713abe test: ledger entries of Cr Note of POS Invoice 2024-02-22 20:46:07 +05:30
ruthra kumar
b03c683898 Merge pull request #39828 from Nihantra-Patel/fix_translate_sales_pip_report
fix: translate Sales Pipeline Analytics report
2024-02-22 20:24:00 +05:30
Nihantra C. Patel
c5050c935b fix: translatable columns in Sales Pipeline Analytics report 2024-02-22 20:08:11 +05:30
Gursheen Anand
e2d16955dd fix: skip SO & DN validation for debit note 2024-02-22 16:24:42 +05:30
Gursheen Anand
5a3b133d65 fix: skip max discount validation for rate adjustment 2024-02-22 16:09:29 +05:30
Gursheen Anand
146c5b3e16 fix: only check for delinked PLEs 2024-02-22 16:00:52 +05:30
Gursheen Anand
c1e1fd8829 fix: delete PLE containing invoice in against 2024-02-22 15:12:02 +05:30
rohitwaghchaure
da184d709b fix: negative stock error while making stock reconciliation (#40016)
fix: negative stock error while making stock reco
2024-02-22 09:22:58 +05:30
rohitwaghchaure
864d7ae04c fix: incorrect item name in MR (#40018) 2024-02-22 09:22:30 +05:30
rohitwaghchaure
0b04d04da3 fix: remove microsecond from posting datetime (#40017) 2024-02-22 09:22:05 +05:30
Gursheen Kaur Anand
6707425baa Merge pull request #40005 from GursheenK/communication_date_for_party_dashboard
fix: communication_date in party dashboards
2024-02-22 09:08:22 +05:30
Gursheen Kaur Anand
6cfb8fe439 Merge pull request #39999 from GursheenK/pricing_rule_type_error
fix: TypeError for item pricing rules
2024-02-22 09:06:27 +05:30
rohitwaghchaure
45b25e09c1 fix: negative stock error while submitting stock reconciliation (#40012)
fix: negative stock error while submitting stok reco
2024-02-21 23:01:15 +05:30
Ankush Menat
38e88db2c9 fix: timesheet per billed state edge case (#40010)
If value is 100.0000x then it won't set status correctly but will set it the next time it's loaded from db.
2024-02-21 15:27:26 +00:00
Gursheen Anand
87df7ff717 fix: accommodate for changed orderby statement 2024-02-21 18:44:29 +05:30
rohitwaghchaure
4c061d61fa Merge pull request #39800 from rohitwaghchaure/persistent-indexing
perf: new column Posting Datetime in SLE to optimize stock ledger related queries
2024-02-21 18:39:27 +05:30
Rohit Waghchaure
a73ba2c0d2 chore: remove microsecond from posting_datetime 2024-02-21 18:14:20 +05:30
Gursheen Anand
ecd83b12ab fix: check for pricing rules on item 2024-02-21 16:39:28 +05:30
rohitwaghchaure
408ea0432b Merge pull request #39998 from rohitwaghchaure/fixed-10262
fix: Completed Work Orders report not working
2024-02-21 16:30:08 +05:30
Rohit Waghchaure
11f4cb914a fix: Completed Work Orders report not working 2024-02-21 14:36:14 +05:30
Nabin Hait
66bf6e4041 Merge pull request #39983 from nabinhait/asset-cancel-deletion
fix: Issues regarding asset cancellation and deletion
2024-02-21 11:14:27 +05:30
rohitwaghchaure
f37f7ca5c3 Merge branch 'develop' into persistent-indexing 2024-02-21 11:02:23 +05:30
Nabin Hait
85471533e9 fix: removed unwanted patch 2024-02-21 08:44:03 +05:30
rohitwaghchaure
4b24fcd221 fix: set batch created from bundle to batch field in stock transaction (#39966)
* fix: set batch created from bundle to batch field in stock transaction

* fix: validation for serial and batch no
2024-02-20 23:45:07 +05:30
ruthra kumar
68a23730f3 fix: Cr/Dr notes with POS Payments 2024-02-20 21:53:33 +05:30
Nabin Hait
17f85de6fb fix: Issues regarding asset cancellation and deletion 2024-02-20 18:10:34 +05:30
rohitwaghchaure
8e7d47b3a7 fix: 'NoneType' object is not iterable (#39977) 2024-02-20 15:19:06 +05:30
rohitwaghchaure
133f8bd92a fix: show active bom in the dropdown while making stock entry and MR (#39974) 2024-02-20 12:35:35 +05:30
rohitwaghchaure
d4264f7ba1 fix: reposting failed status not updated (#39970) 2024-02-20 12:13:18 +05:30
rohitwaghchaure
fa1113f912 Merge pull request #39967 from rohitwaghchaure/fixed-subcontracting-pr-10107
fix: float division by zero
2024-02-20 06:30:57 +05:30
Rohit Waghchaure
e8ae4ed61d fix: float division by zero 2024-02-19 22:18:57 +05:30
rohitwaghchaure
a4cbfabe0e fix: do not empty serial batch fields (#39948) 2024-02-19 10:25:36 +05:30
ruthra kumar
9cb83d2198 Merge pull request #39914 from ruthra-kumar/total_row_when_filtered_on_party
refactor: add total row if only one party is being filtered
2024-02-19 08:25:20 +05:30
ruthra kumar
e25b4e24df Merge pull request #39942 from ruthra-kumar/filter_warehouse_on_group
fix: group node in warehouse filter in Item-wise Sales Register
2024-02-19 08:24:49 +05:30
ruthra kumar
4f23d88f62 Merge pull request #39943 from ruthra-kumar/disclaimer_on_credit_debit_notes
refactor: use popup to inform on additional reconciliation step for Cr/Dr Notes
2024-02-19 07:13:08 +05:30
barredterra
0bbf45cd8b refactor: make_gle_for_change_amount 2024-02-17 20:46:52 +01:00
barredterra
2ff06af154 refactor: validate_serial_numbers 2024-02-17 20:29:38 +01:00
barredterra
9c0755d3de refactor: set_income_account_for_fixed_assets 2024-02-17 20:08:49 +01:00
barredterra
701671b2bd refactor: validate_dropship_item 2024-02-17 19:50:34 +01:00
barredterra
4d7d7dac01 refactor(Sales Invoice): validate_delivery_note 2024-02-17 19:40:02 +01:00
Rohit Waghchaure
f04676aaed test: test cases to test clash timestamp entries 2024-02-17 15:01:18 +05:30
ruthra kumar
0d260faa00 refactor: use popup to inform on additional reconciliation step 2024-02-17 07:19:32 +05:30
ruthra kumar
44538bd02a fix: group node in warehouse filter in Item-wise Sales Register 2024-02-17 06:41:00 +05:30
barredterra
75230ece9a refactor: set actual and projected qty in Packed Item and Sales Invoice Item 2024-02-16 23:50:32 +01:00
barredterra
f99f7fd2cf refactor(Sales Invoice): convert to guard clause 2024-02-16 23:17:41 +01:00
barredterra
cc83af0dd4 refactor: move code for unlinking sales invoice to Timesheet 2024-02-16 23:14:50 +01:00
Raffael Meyer
028d31a6f9 Merge pull request #39938 from barredterra/issue-communication 2024-02-16 20:13:58 +01:00
barredterra
3f1d008741 fix(Issue): create communication
Ignore permisions and mandatory. Required, for example, when Issue is created by Customer via portal.
2024-02-16 19:58:58 +01:00
barredterra
0b3ecd24e2 feat: pass doctype as context when translating label 2024-02-16 16:29:40 +01:00
rohitwaghchaure
506fefa186 Merge pull request #39934 from rohitwaghchaure/fixed-batch-filter-in-stock-ledger
fix: batch filter not working in stock ledger report
2024-02-16 20:16:43 +05:30
Rohit Waghchaure
a995e87567 fix: batch filter not working in stock ledger report 2024-02-16 19:43:34 +05:30
rohitwaghchaure
fa4ea7c96d Merge pull request #39930 from rohitwaghchaure/fixed-use-serial-batch-fields-for-se
fix: use serial batch fields not enabled for new stock entry
2024-02-16 15:48:52 +05:30
Rohit Waghchaure
dc9115a586 fix: use serial batch fields not enabled for new stock entry 2024-02-16 15:46:58 +05:30
Raffael Meyer
f3bd53193d Merge pull request #39926 from barredterra/bt-precision 2024-02-15 20:03:31 +01:00
barredterra
8a702a6338 fix(Bank Transaction): precision for (un)allocated_amount 2024-02-15 19:48:54 +01:00
rohitwaghchaure
8360339119 Merge pull request #39916 from rohitwaghchaure/fixed-pr-issue-9877
fix: not able to make purchase receipt
2024-02-15 17:32:57 +05:30
rohitwaghchaure
799794cafb Merge pull request #39905 from rohitwaghchaure/fixed-item-reference-9906
fix: party item code in Blanket Order
2024-02-15 14:58:49 +05:30
Rohit Waghchaure
2fb0499923 fix: not able to make purchase receipt 2024-02-15 14:58:34 +05:30
rohitwaghchaure
230a7d8d53 chore: fix linter issue 2024-02-15 14:28:06 +05:30
ruthra kumar
b1dfa2537b refactor: add total row if only one party is being filtered 2024-02-15 12:53:27 +05:30
Rohit Waghchaure
1a8f7f9403 fix: party item code in Blanket Order 2024-02-14 18:45:11 +05:30
rohitwaghchaure
d0df5df4a6 fix: production plan issue with sales order (#39901) 2024-02-14 16:39:33 +05:30
rohitwaghchaure
6239fd704b fix: landed cost voucher not submitting because of incorrect reference (#39898) 2024-02-14 15:29:20 +05:30
Rohit Gunjegaonkar
b124081065 fix: use correct field name in accounts controller (#39884)
Changes to get advance payments in SI or PI from JV's
2024-02-14 12:08:36 +05:30
Raffael Meyer
4bef6707ec Merge pull request #38649 from pps190/ux-delivery_date-schedule_date 2024-02-14 01:56:29 +01:00
barredterra
76023f1fdc refactor(Sales Invoice Item): validate cost center 2024-02-14 01:14:42 +01:00
Raffael Meyer
f1f8f59bdb Merge pull request #39868 from barredterra/fix-stock-value-diff 2024-02-14 00:50:58 +01:00
Raffael Meyer
24ba26fef3 Merge pull request #39857 from kunhimohamed/company_terms 2024-02-14 00:27:59 +01:00
kunhi
e6949d71f6 fix: update_dimension is required and not need party account method 2024-02-13 22:49:39 +04:00
kunhi
e3bd8d10b0 fix: no need call for company method in sales invoice js 2024-02-13 22:32:10 +04:00
Rohit Waghchaure
d80ca523a4 perf: new column posting datetime in SLE to optimize stock ledger related queries 2024-02-13 11:42:39 +05:30
Nihantra C. Patel
22291d32e6 fix: corrective_operation_cost in Job Card (#39829) 2024-02-13 00:48:38 +05:30
barredterra
5df5851798 fix: calculate stock_value_diff
`d.item_tax_amount` is already in base currency.
2024-02-12 17:05:03 +01:00
s-aga-r
1d1cb86c75 Merge pull request #39862 from s-aga-r/FIX-9779
fix: validate duplicate SBB
2024-02-12 19:59:36 +05:30
s-aga-r
1c2a7801b7 Merge pull request #39835 from s-aga-r/FIX-9623
fix: create SBB for `transfer_qty` in SE
2024-02-12 18:18:46 +05:30
s-aga-r
55e66db315 test: duplicate SBB 2024-02-12 18:16:29 +05:30
s-aga-r
094ecc1f62 fix: validate duplicate SBB 2024-02-12 18:15:42 +05:30
s-aga-r
2b1e0d3bd0 Merge pull request #39846 from s-aga-r/FIX-9699
perf: production plan submission
2024-02-12 15:28:37 +05:30
kunhi
d97b6d38ef fix: fetch company terms 2024-02-12 12:18:37 +04:00
rohitwaghchaure
b966c06a4f perf: cached get_last_purchase_details to fix performance issue (#39854) 2024-02-12 12:49:09 +05:30
Nijith anil
2ee642fb2c fix(ux): sales invoice link in error message (#39841)
fix: sales invoice link in error message

Co-authored-by: Nijith anil <nijithanil501@email.com>
2024-02-11 18:12:01 +05:30
Deepesh Garg
4b1c851da1 fix: Brazilian COA for demo data creation (#39839)
fix: Brazilian COA
2024-02-11 17:18:57 +05:30
s-aga-r
39067c7614 feat: get RM costs from consumption entry in manufacture SE (#39822) 2024-02-11 17:10:57 +05:30
s-aga-r
aa1c69dd7a perf: production plan submission 2024-02-11 16:34:30 +05:30
rohitwaghchaure
e5824fc3f1 fix: stock entry for use serial batch fields (#39843) 2024-02-11 11:10:21 +05:30
s-aga-r
d59caf08e6 fix: create SBB for transfer_qty in SE 2024-02-09 19:13:03 +05:30
Nihantra C. Patel
186cc3d748 fix: remove cancelled payment entry from PPBOID report 2024-02-09 16:27:52 +05:30
Nihantra C. Patel
a2a8a8f2e0 fix: remove cancelled payment entry from Payment Period Based On Invoice Date 2024-02-09 16:13:44 +05:30
Nihantra C. Patel
17452b7693 fix: check_credit_limit on_update_after_submit of Sales Order 2024-02-09 15:18:45 +05:30
Gursheen Anand
8c85404191 fix: test for repost accounting in JVs 2024-02-09 13:11:51 +05:30
rohitwaghchaure
159a123dc7 fix: warehouse issue in pick list (#39826) 2024-02-09 11:14:54 +05:30
s-aga-r
1568af2a7b Merge pull request #39816 from s-aga-r/FIX-9595
fix(ux): set rate as price list rate on uom change in MR
2024-02-08 17:54:19 +05:30
s-aga-r
1745371cd6 chore: linter 2024-02-08 16:44:31 +05:30
Gursheen Anand
ecdc4c8e9b feat: add patch for making repostable dimension fields editable 2024-02-08 16:36:30 +05:30
s-aga-r
5cf0759b0c fix: set rate as price list rate on uom change 2024-02-08 16:34:26 +05:30
s-aga-r
61a29eb5fb fix: add price list rate field in MR Item 2024-02-08 16:33:48 +05:30
Gursheen Anand
8bb83e267c fix: allow editable accounting dimensions for repostable doctypes 2024-02-08 16:09:28 +05:30
Gursheen Anand
781bdd2ec9 fix: disable editable account heads 2024-02-08 15:35:10 +05:30
Gursheen Anand
2d78dba66f chore: rebase 2024-02-08 15:20:50 +05:30
mergify[bot]
2c8e4c1ab3 fix: do not consider rejected warehouses in pick list (backport #39539) (#39804)
* fix: do not consider rejected warehouses in pick list (#39539)

* fix: do not picked rejected materials

* test: test case for pick list without rejected materials

(cherry picked from commit f6725e4342)

# Conflicts:
#	erpnext/selling/doctype/sales_order/test_sales_order.py
#	erpnext/stock/doctype/pick_list/pick_list.json
#	erpnext/stock/doctype/pick_list/pick_list.py

* chore: fix conflicts

* chore: fix conflicts

* chore: fix conflicts

* chore: fixed test case

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-02-08 13:54:08 +05:30
ruthra kumar
22a187c3be Merge pull request #39783 from ruthra-kumar/cancel_cr_dr_note_jes_on_cancel
fix: cancelling cr/dr notes should update the linked Invoice status
2024-02-07 20:25:53 +05:30
ruthra kumar
2f676ced5c refactor(test): Forex Credit Note cancellation against Invoice 2024-02-07 19:59:33 +05:30
s-aga-r
e9251c3775 Merge pull request #39785 from s-aga-r/FIX-9505
fix: incorrect planned qty in PP
2024-02-07 19:02:31 +05:30
Ankush Menat
294f562fb9 build: Pin frappe requirements to ^16.0.0 (#39782) 2024-02-07 18:30:35 +05:30
s-aga-r
81e82b0595 Merge pull request #39780 from s-aga-r/FIX-9577
fix: add permissions to SRE
2024-02-07 18:14:08 +05:30
s-aga-r
a8ebc94a36 fix: incorrect planned qty in PP 2024-02-07 18:13:34 +05:30
ruthra kumar
33efe0d12d refactor(test): assert Invoice status as well 2024-02-07 17:33:55 +05:30
ruthra kumar
31a8c3bdc4 test: Invoice status on Cr/Dr note cancellation 2024-02-07 17:21:29 +05:30
ruthra kumar
0549535603 refactor: cancel Cr/Dr JE's on Sales/Purchase return cancel 2024-02-07 16:35:07 +05:30
s-aga-r
50f54d983d fix: add permissions to SRE 2024-02-07 16:06:28 +05:30
Gursheen Kaur Anand
146147316d Merge pull request #39757 from GursheenK/duplicates-in-tax-category-map
fix: duplicates in tax category map
2024-02-07 15:11:59 +05:30
rohitwaghchaure
ab9d6576d0 Merge pull request #39769 from rohitwaghchaure/fixed-inventory-dimension-validation-8004
fix: do not throw validation for canceled SLE
2024-02-06 23:11:50 +05:30
Rohit Waghchaure
32ccf3524a fix: do not throw validation for cancelled sle 2024-02-06 22:48:13 +05:30
rohitwaghchaure
d6d91257b6 Merge pull request #39764 from rohitwaghchaure/fixed-remove-file-from-disk-9515
fix: remove file from the disk after the completion of reposting
2024-02-06 21:26:28 +05:30
s-aga-r
40ce0c851d Merge pull request #39765 from s-aga-r/FIX-9412
fix: set rate for PO created against BO
2024-02-06 21:18:48 +05:30
Rohit Waghchaure
76b57a4338 test: test case to check removed attached file 2024-02-06 21:09:58 +05:30
s-aga-r
0e5b4e5f07 fix: set rate for PO created against BO 2024-02-06 19:21:51 +05:30
Rohit Waghchaure
fb330d1b5a fix: remove file from the disk after the completion of reposting 2024-02-06 19:13:48 +05:30
Ankush Menat
9636458ae1 ci: codecov changes (#39760)
- don't report coverage on individual PRs, instead do it daily
- update tokens for reporting
2024-02-06 10:21:46 +00:00
rohitwaghchaure
4671f65cbd Merge pull request #39718 from rohitwaghchaure/create-bundle-using-old-fields
fix: use old serial / batch fields to make serial batch bundle
2024-02-06 15:47:08 +05:30
Gursheen Anand
9383f5da94 test: single account for multiple tax categories 2024-02-06 15:03:12 +05:30
Rohit Waghchaure
01650120d4 test: test case to check use serial / batch fields feature 2024-02-06 14:31:19 +05:30
Gursheen Kaur Anand
943dcb6dea Merge branch 'frappe:develop' into duplicates-in-tax-category-map 2024-02-06 14:17:40 +05:30
Gursheen Anand
3a26823c62 refactor: fetch rate once tax category is set 2024-02-06 14:01:06 +05:30
Gursheen Anand
e55611497b fix: duplicate for tax category in map 2024-02-06 13:56:41 +05:30
Ankush Menat
798a0510e6 refactor: change server_action args (#39756)
args are now flat, no need to accept them as dict

ref: https://github.com/frappe/frappe/pull/24782
2024-02-06 08:04:28 +00:00
Gursheen Kaur Anand
e38b46300c Merge pull request #39349 from GursheenK/JVs-in-withholding-report
fix: TDS accounts GLE query for withholding category report
2024-02-06 13:00:13 +05:30
s-aga-r
41f58476e1 Merge pull request #39746 from s-aga-r/FIX-9365
fix: show warehouse title field in sales docs
2024-02-06 12:03:33 +05:30
Ankush Menat
56e5611337 chore: update CI badges (#39753) 2024-02-06 06:01:11 +00:00
ruthra kumar
2e509f69d4 Merge pull request #39694 from ruthra-kumar/enforce_separate_account_for_each_bank_account
refactor: enforce unique GL Account for each 'Bank Account'
2024-02-06 09:29:12 +05:30
s-aga-r
ee14faaa39 fix: show warehouse title field in sales docs 2024-02-05 22:08:59 +05:30
s-aga-r
ae4ebcd987 Merge pull request #39733 from s-aga-r/FIX-9458
fix: update company in serial no doc
2024-02-05 21:54:02 +05:30
rohitwaghchaure
1bfbbfe393 Merge pull request #39742 from rohitwaghchaure/fixed-performance-issue-9247
perf: timeout while submitting the purchase receipt entry
2024-02-05 21:01:17 +05:30
Rohit Waghchaure
1fa6233377 perf: timeout while submitting the purchase receipt entry 2024-02-05 19:46:51 +05:30
Rohit Waghchaure
c1e869f040 test: fixed test cases 2024-02-05 19:39:58 +05:30
s-aga-r
3b671d5875 Merge pull request #39725 from s-aga-r/FIX-9411
fix: Blanket Order Ordered Quantity
2024-02-05 16:07:50 +05:30
Gursheen Anand
c5770f2ecc test: partial billing for provisional accounting 2024-02-05 15:58:06 +05:30
Gursheen Anand
ff3ca50a4b test: overbilling for provisional accounting 2024-02-05 15:55:17 +05:30
Gursheen Anand
cc96d2b50c fix: over billing qty along with rate 2024-02-05 15:52:46 +05:30
s-aga-r
4d614c1589 Merge pull request #39688 from s-aga-r/FIX-9169
fix: remove applied pricing rule on qty change
2024-02-05 15:40:44 +05:30
s-aga-r
27d6c8b6d5 test: BO on PO Close/Open 2024-02-05 15:38:31 +05:30
s-aga-r
61ded697a7 fix: update BO Ordered Quantity on PO Close/Open 2024-02-05 15:38:31 +05:30
s-aga-r
5ce5c352e4 fix: disable no-copy for blanket order in PO 2024-02-05 15:38:31 +05:30
Deepesh Garg
6e6c818084 feat: Period-wise closing entries for TB (#39712) 2024-02-05 14:10:42 +05:30
Deepesh Garg
b834ed10d6 perf: Move dimension validation out of GL Entry doctype (#39730) 2024-02-05 14:05:01 +05:30
Gursheen Anand
25c2b79864 fix: precision for tds amount 2024-02-05 13:03:21 +05:30
s-aga-r
7a04f0f7ba fix: update company in serial no doc 2024-02-05 12:35:26 +05:30
rohitwaghchaure
b70f3de16b perf: memory consumption for the stock balance report (#39626) 2024-02-05 11:46:39 +05:30
RitvikSardana
955098c4c0 Merge pull request #39651 from RitvikSardana/develop-ritvik-ignore-permission-flag
fix: add ignore_permissions flag while creating a payment entry.
2024-02-05 11:45:02 +05:30
rohitwaghchaure
675a0b810f Merge pull request #39659 from rohitwaghchaure/fixed-timeout-error-while-making-auto-mr
perf: timeout for auto material request through reorder level
2024-02-05 11:38:11 +05:30
rohitwaghchaure
d7e4a6be13 Merge pull request #39684 from rohitwaghchaure/fixed-landed-cost-voucher-issue-manually
fix: incorrect landed cost voucher amount
2024-02-05 11:37:41 +05:30
Raffael Meyer
617d923f0d Merge pull request #38647 from barredterra/copy-emails-to-customer 2024-02-04 22:13:48 +01:00
Gursheen Kaur Anand
407045a1de fix: production plan date filters for orders (#39702) 2024-02-04 23:01:51 +05:30
NIYAZ RAZAK
d73e42fc41 feat: project field 2024-02-04 17:23:08 +03:00
Rohit Waghchaure
9fafc83632 fix: use old serial / batch fields to make serial batch bundle 2024-02-04 18:32:19 +05:30
Vishnu VS
c81d597ca5 fix(work order): resolve type error during job card creation (#39713)
fix: type error
2024-02-04 06:47:18 +00:00
mergify[bot]
50cff656b4 Merge branch 'develop' into copy-emails-to-customer 2024-02-03 08:37:59 +00:00
Gursheen Kaur Anand
d9a72c1e61 feat: reference for POS SI payments (#39523)
* feat: reference field in SI payment

* fix: document link for pos si

* refactor: pos invoice queries
2024-02-03 13:05:41 +05:30
ruthra kumar
322cdbaccf refactor(test): make use of test fixtures in Payment Order 2024-02-03 12:09:50 +05:30
ruthra kumar
a9a2ec81de refactor(test): generate uniq GL acc and Bank acc for each test case 2024-02-03 12:07:43 +05:30
Raffael Meyer
93259cab1d fix(Bank Statement Import): scheduler not needed in dev mode (#39678) 2024-02-03 09:12:28 +05:30
Gursheen Anand
7efb5a8cb5 fix(portal): context pay_amount for button 2024-02-02 22:01:42 +05:30
Gursheen Anand
c18ff5bd25 fix(portal): payment amount for orders 2024-02-02 21:59:53 +05:30
Gursheen Anand
f7face43cd fix: check payments against orders for getting request amount 2024-02-02 21:57:45 +05:30
ruthra kumar
2caa2d677c refactor: ensure unique accounts for each Bank Account's 2024-02-02 21:03:41 +05:30
Deepesh Garg
6d87cfeb8d fix: Percentage handling in queries (#39692)
* fix: Percentage handling in queries

* test: Account with percent sign

* chore: add test records
2024-02-02 18:08:33 +05:30
s-aga-r
2693fcb446 Merge pull request #39687 from s-aga-r/FIX-9316
fix: out of range for valuation_rate column in SE
2024-02-02 13:35:00 +05:30
s-aga-r
7c6a5a0f23 fix: remove pricing rule 2024-02-02 13:18:52 +05:30
s-aga-r
1e15a3cc15 fix: out of range for valuation_rate column in SE 2024-02-02 13:07:26 +05:30
Rohit Waghchaure
d78a1e7814 fix: incorrect landed cost voucher amount 2024-02-01 19:29:06 +05:30
ruthra kumar
12affa70cf Merge pull request #39674 from ruthra-kumar/add_account_type_warning
refactor: use pop up to inform of possible data issue
2024-02-01 17:11:39 +05:30
ruthra kumar
78483e2ee6 refactor: use pop up to inform of possible data issue
and leave a comment in communcation trail as well
2024-02-01 16:24:47 +05:30
Divyam Mistry
e9fe10c6f1 fix: fetch/change tax template on basis of base_net_rate instead of net_rate (#39448)
fix: change tax template on basis of base_net_rate instead of net_rate

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2024-02-01 16:15:43 +05:30
ruthra kumar
518b06c8eb Merge pull request #39671 from ruthra-kumar/filter_to_ignore_err_journals_in_general_ledger
refactor: move ignore ERR filter from SOA to General Ledger
2024-02-01 16:09:53 +05:30
Gursheen Kaur Anand
27b557bef9 Merge branch 'develop' into editable-journal-entries 2024-02-01 16:08:14 +05:30
ruthra kumar
beff566c82 refactor(test): use party with USD billing currency 2024-02-01 15:46:57 +05:30
ruthra kumar
affca3a519 test: ignore_err filter out in General Ledger 2024-02-01 15:13:28 +05:30
ruthra kumar
c077eda64e refactor: move ignore ERR filters from SOA to General Ledger 2024-02-01 14:53:01 +05:30
Gursheen Kaur Anand
772f540bef fix: correctly calculate diff amount for included taxes (#39655) 2024-02-01 10:13:29 +05:30
Rohit Waghchaure
951023f434 perf: timeout for auto material request through reorder level 2024-01-31 17:27:32 +05:30
rohitwaghchaure
5e71d6ac4e Merge pull request #39643 from GursheenK/portal-po-pay-btn
fix(portal): show PO pay button if payments installed
2024-01-31 14:44:25 +05:30
Gursheen Kaur Anand
7475233fa6 Merge branch 'develop' into portal-po-pay-btn 2024-01-31 13:39:49 +05:30
Gursheen Anand
0c9572bb48 fix: conditionally display show btn setting 2024-01-31 13:37:01 +05:30
Rucha Mahabal
6b8f046fb4 chore: cleanup doctype descriptions (#39637)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-31 12:15:52 +05:30
RitvikSardana
1ff473b615 fix: add ignore_permissions flag while creating a payment entry 2024-01-31 11:34:20 +05:30
Deepesh Garg
cfd1666181 fix: Exchange rate on MR to PO creation for muticurrency POs (#39646) 2024-01-31 09:27:52 +05:30
Raffael Meyer
0c6c650c08 Merge pull request #39519 from barredterra/dont-override-tc 2024-01-31 01:12:27 +01:00
rohitwaghchaure
31f586f716 Merge pull request #38362 from rohitwaghchaure/feat-visual-plant-floor
feat: visual plant floor
2024-01-30 22:35:42 +05:30
Rohit Waghchaure
6fea9d6dfe feat: make material request for job card from workstation dashboard 2024-01-30 22:12:34 +05:30
Raffael Meyer
212d656d85 Merge pull request #39468 from blaggacao/feat/payment-request-failure-reason 2024-01-30 15:58:42 +01:00
David Arnold
9a705169fd fix: remove empty dn from bulk creation if date filter renders them empty 2024-01-30 13:51:48 +01:00
David Arnold
00a915b741 feat: hanled payment request failure reasons 2024-01-30 13:00:55 +01:00
Gursheen Anand
ae7be84d87 fix(portal): show PO pay button if payments installed 2024-01-30 17:24:59 +05:30
Raffael Meyer
f8a9554bbd Merge pull request #38157 from blaggacao/fix/notification-comply-with-upstream 2024-01-30 12:33:25 +01:00
David Arnold
d86186ec47 fix: correct receiver field 2024-01-30 12:12:15 +01:00
David Arnold
3fd43cd6bb chore: remove old md files 2024-01-30 12:11:08 +01:00
mergify[bot]
12a4f2761c Merge branch 'develop' into feat/add-delivery-cutoff-date-on-so 2024-01-30 09:56:24 +00:00
mergify[bot]
e9dfb45fca Merge branch 'develop' into fix/notification-comply-with-upstream 2024-01-30 09:49:57 +00:00
rohitwaghchaure
b14886b227 fix: perf issue while submitting stock entry (#39634) 2024-01-30 15:16:52 +05:30
Raffael Meyer
2e49423d3f Merge branch 'develop' into dont-override-tc 2024-01-30 10:44:16 +01:00
Gursheen Anand
ddecbeba75 fix: test JV totals using back calculation logic 2024-01-30 12:39:40 +05:30
ruthra kumar
2e5d716408 Merge pull request #39559 from ruthra-kumar/prevent_cr_note_with_different_account_to_sales_invoice
fix: prevent Return Invoices(Credit/Debit Note) from using a different account
2024-01-30 11:00:44 +05:30
ruthra kumar
bdca718103 test: debit note account mismatch 2024-01-30 10:38:44 +05:30
ruthra kumar
8bdc760733 test: account mismatch validation 2024-01-30 10:38:44 +05:30
ruthra kumar
6f2fae1b61 refactor: prevent '{debit/credit}_to' account mismatch 2024-01-30 10:38:44 +05:30
Raffael Meyer
91b913b5bb chore: regenerate pot file (#39627) 2024-01-30 08:32:55 +05:30
rohitwaghchaure
5cf47ae5f9 fix: not able to submit subcontracting pr (old flow) (#39622) 2024-01-29 20:41:26 +05:30
Deepesh Garg
a673220feb feat: Partly billed status in Purchase Receipt (#39543) 2024-01-29 19:56:46 +05:30
rohitwaghchaure
4e182b89ce fix: not able to save BOM (duplicate key error) (#39620) 2024-01-29 19:35:05 +05:30
Rohit Waghchaure
68c997aa06 feat: visual plant floor 2024-01-29 18:48:35 +05:30
Gursheen Kaur Anand
866df9f1c7 Merge pull request #39616 from GursheenK/item-delivery-date-from-qtn
fix(minor): do not auto-populate item delivery date from qtn
2024-01-29 15:50:23 +05:30
Gursheen Anand
079cd30b9c fix: qtn tests using delivery date 2024-01-29 14:19:25 +05:30
Gursheen Anand
49cb11c1f3 fix: do not auto-populate item delivery date 2024-01-29 13:15:00 +05:30
Jeffry Suryadharma
efade9b9ae fix amount not updated when change rate in material request (#39606)
* fix amount not updated when change rate in material request

* make code consistent
2024-01-29 12:57:49 +05:30
Gursheen Anand
2a46799188 fix: handle partial invoice against provisional entry 2024-01-29 11:34:06 +05:30
Dany Robert
50d56db0c2 fix: specify precision for net_amount (#39481)
* fix: specify precision for net_amount

* fix: correct existing test to account for precision

* fix: rounding issue in test cases

* fix: optional grand total manipulation

* fix: use `grand_total_diff` for manipulation

* fix: patch to set default for grand total manipulation

* fix: wrong rounding assertion for USD

* fix: undefined this.frm error

* chore: linters

* fix: `net_amount` percision and method rename

* fix: missing frm reference

* chore: minor cleanups and depr message

* refactor: remove optional adjusting of grand total
2024-01-29 09:32:44 +05:30
Deepesh Garg
16404110a8 Merge pull request #39588 from CitrusLeafSoft/New-Financial-report-views
feat: New financial views - Growth and margin views for P&L and balance sheet
2024-01-28 11:36:55 +05:30
mergify[bot]
6a63a8997d Merge branch 'develop' into fix/notification-comply-with-upstream 2024-01-28 05:42:37 +00:00
Deepesh Garg
88ff945e40 Merge pull request #39562 from GursheenK/JV-timeout-issue
fix: enqueue JV submission when > 100 accounts
2024-01-28 10:30:25 +05:30
Deepesh Garg
8f6c23cb53 Merge pull request #39598 from GursheenK/type-error-dashboard-report
fix(minor): type error in financial statements for dashboard
2024-01-28 09:55:49 +05:30
mergify[bot]
4c197c8dbd Merge branch 'develop' into copy-emails-to-customer 2024-01-28 04:23:49 +00:00
Deepesh Garg
f2891229ab Merge pull request #38643 from barredterra/quotation-to-customer
refactor: get/create customer for Sales Order
2024-01-28 09:53:15 +05:30
Gursheen Anand
2486b646a1 fix: check page obj before adding menu 2024-01-27 23:30:17 +05:30
rohitwaghchaure
8fdc244e16 fix: prevent extra transfer against inter transfer transaction (#39213)
* fix: prevent extra transfer against inter transfer transaction

* fix: internal transfer dashboard
2024-01-27 21:37:58 +05:30
ruthra kumar
5be868c7f6 Merge pull request #39591 from ruthra-kumar/conversion_on_future_payments
refactor: Do proper currency conversion on Future Payments column in AR/AP report
2024-01-27 12:52:18 +05:30
rohitwaghchaure
67d828dab3 fix: not able to save subcontracting purchase receipt (old flow) (#39590) 2024-01-27 12:00:06 +05:30
ruthra kumar
7b37389115 test: future payment with foreign currency 2024-01-27 11:48:22 +05:30
ruthra kumar
0de4197c88 refactor: do currency conversion on future amount columns 2024-01-27 11:48:19 +05:30
nitmit
92649de5c6 Adding growth and margin views for P&L and balance sheet financial reports in collaboration with Sapcon Instruments Pvt Ltd 2024-01-27 10:18:35 +05:30
Gursheen Anand
3e59c66806 fix: provisional reverse entry amount 2024-01-26 21:46:19 +05:30
Gursheen Anand
fc677811b7 fix: return doc obj after submit 2024-01-26 20:03:21 +05:30
mergify[bot]
19ff10dfeb Merge branch 'develop' into quotation-to-customer 2024-01-26 13:56:08 +00:00
Deepesh Garg
4173203382 Merge pull request #39578 from deepeshgarg007/fix_ci
fix: apply no copy on source docs
2024-01-26 19:25:22 +05:30
Deepesh Garg
dbd4dae3d9 test: Internal transfer using purchase receipt 2024-01-26 18:42:29 +05:30
Deepesh Garg
99b839d2b6 chore: failing ci tests 2024-01-26 10:46:44 +05:30
Deepesh Garg
30cc65d2b7 Merge pull request #39511 from barredterra/set-account-for-mode-of-payments
refactor(Sales Invoice): set account and sum for payments
2024-01-26 09:44:11 +05:30
Deepesh Garg
722ee53fb1 Merge branch 'develop' of https://github.com/frappe/erpnext into copy-emails-to-customer 2024-01-26 09:39:13 +05:30
Deepesh Garg
6173b34b10 Merge branch 'develop' of https://github.com/frappe/erpnext into quotation-to-customer 2024-01-26 09:35:38 +05:30
Deepesh Garg
f7a3af7473 Merge pull request #39532 from GursheenK/type-error-in-transaction-js
fix: type error in transaction.js
2024-01-26 09:30:53 +05:30
Deepesh Garg
d491036f2d Merge pull request #39108 from deepeshgarg007/in_words_pe
feat: In words in payment entry
2024-01-26 09:30:26 +05:30
Deepesh Garg
d2057588dd Merge branch 'develop' of https://github.com/frappe/erpnext into type-error-in-transaction-js 2024-01-26 09:29:05 +05:30
rohitwaghchaure
2bdfdeeb9a fix: incorrect amount in the material request item (#39567)
fix: incoorect amount in the material request
2024-01-25 16:49:12 +05:30
Nabin Hait
be074a2972 Merge pull request #39489 from nabinhait/grouped-asset-value
fix: fetch correct quantity and amount for grouped asset
2024-01-25 16:20:35 +05:30
Gursheen Kaur Anand
2b3cc5ba2d Merge pull request #39557 from GursheenK/validate-item-code-with-prevdoc
fix: make SO item code mandatory
2024-01-25 16:19:23 +05:30
Nabin Hait
06f48c678b fix: fetch correct quantity and amount for grouped asset 2024-01-25 16:18:54 +05:30
Gursheen Anand
53b44ccf29 fix: enqueue JV submission when more than 100 accounts 2024-01-25 16:13:24 +05:30
Deepesh Garg
69db569ca5 Merge pull request #39446 from GursheenK/payment-reco-company-field
fix: ignore user permissions for company in payment reco
2024-01-25 15:06:10 +05:30
Gursheen Anand
7f8303a493 fix: make SO item code reqd 2024-01-25 14:27:35 +05:30
Ankush Menat
dfda5ad673 ci: Add fake passing tests when CI is skipped (#39555) 2024-01-25 14:18:27 +05:30
ruthra kumar
1e89c1c875 Merge pull request #39535 from ruthra-kumar/rename_advance_doctype_variable_hook
refactor: use generic name for advance doctypes variable
2024-01-25 13:25:56 +05:30
rohitwaghchaure
d1fb90edff fix: default enable closing stock balance (#39551) 2024-01-25 12:42:16 +05:30
Gursheen Kaur Anand
3f383d81bd Merge branch 'develop' into payment-reco-company-field 2024-01-25 11:44:53 +05:30
ruthra kumar
9fcd89d456 refactor: use generic name for advance doctypes variable 2024-01-24 14:19:21 +05:30
Gursheen Anand
030d35628d fix: type error on company doc 2024-01-24 12:47:55 +05:30
barredterra
77b044f1a6 fix: don't overwrite existing terms in transaction 2024-01-24 01:48:10 +01:00
David Arnold
252fae68df feat: use new bulk creation arguments and contrue a cut-off date selector for dn-from-so 2024-01-23 17:46:12 +01:00
David Arnold
e5a5b6afc8 feat: add better preselection (cut-off: tomorrow) to dn-from-so creation dialogue 2024-01-23 17:45:40 +01:00
David Arnold
ffd38362d5 feat: add an argument pass mechanism to bulk transactions 2024-01-23 17:42:56 +01:00
barredterra
3815f07c33 refactor(Sales Invoice): set account for mode of payment 2024-01-23 13:11:06 +01:00
Deepesh Garg
13aae34e9c Merge branch 'develop' of https://github.com/frappe/erpnext into in_words_pe 2024-01-22 09:33:46 +05:30
Gursheen Anand
e9526b112d test: journals in withholding report 2024-01-21 18:04:47 +05:30
Gursheen Kaur Anand
a6afe50a92 Merge branch 'frappe:develop' into JVs-in-withholding-report 2024-01-21 17:55:56 +05:30
Gursheen Kaur Anand
d468accb02 Merge branch 'frappe:develop' into payment-reco-company-field 2024-01-19 11:52:34 +05:30
Gursheen Anand
527cfcd87f fix: ignore user permissions for company field 2024-01-18 11:58:06 +05:30
Gursheen Anand
c648090b5d fix: query for filter by party 2024-01-12 18:33:06 +05:30
barredterra
e67ed4fb2d Merge branch 'develop' into quotation-to-customer 2024-01-11 14:04:09 +01:00
barredterra
33bffe8201 Merge branch 'develop' into copy-emails-to-customer 2024-01-11 13:54:59 +01:00
barredterra
28626cd7c0 Merge branch 'develop' into copy-emails-to-customer 2024-01-09 17:50:42 +01:00
Deepesh Garg
b21da472f6 feat: In words in payment entry 2024-01-03 13:34:22 +05:30
Devin Slauenwhite
c86deceaba fix(ux): default parent delivery_date or schedule_date 2023-12-28 15:19:21 +00:00
David Arnold
c61925598a fix: translatable strings
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-12-15 18:24:34 +01:00
barredterra
906ac093e3 feat: copy emails from lead to customer 2023-12-08 14:56:10 +01:00
barredterra
8e0a7a8dbc refactor: get/create customer for Sales Order 2023-12-08 14:06:01 +01:00
David Arnold
083da7d8a4 Merge remote-tracking branch 'upstream/develop' into fix/notification-comply-with-upstream 2023-12-04 13:31:02 +01:00
David Arnold
1662a4c9c3 fix(notification): align with https://github.com/frappe/frappe/pull/22595 2023-11-17 15:02:30 +01:00
Gursheen Anand
fed8cf4196 fix: test for reposting pi 2023-10-12 17:40:57 +05:30
Gursheen Anand
528ed9c986 fix: check child rows before update 2023-10-12 16:54:41 +05:30
Gursheen Anand
e2cccc4005 chore: correct typo 2023-10-12 15:57:38 +05:30
Gursheen Anand
569d0961f2 test: reposting entries for JV 2023-10-12 15:06:04 +05:30
Gursheen Anand
de46fa8e66 refactor: use qb for JV tests 2023-10-12 15:04:56 +05:30
Gursheen Anand
bfa0c0981c feat: repost ledger button in JV 2023-10-12 13:31:15 +05:30
Gursheen Anand
c77c296b8b feat: validate before allowing repost 2023-10-12 13:10:59 +05:30
Gursheen Anand
9ab55a5bd8 refactor: better abstraction for controller code 2023-10-12 12:48:14 +05:30
Gursheen Anand
e4d657e6fd feat: update after submit in JV 2023-10-12 12:46:50 +05:30
Gursheen Anand
f4c8d63fe0 feat: allow on submit for selected fields 2023-10-12 12:20:01 +05:30
Gursheen Anand
d94f45531a refactor: remove controller logic for setting balances 2023-10-12 12:13:21 +05:30
Gursheen Anand
4d38bd8517 refactor: exclude balances while setting currency 2023-10-12 12:09:58 +05:30
Gursheen Anand
c99e7ca999 refactor: exclude balance while setting acc details 2023-10-12 12:07:36 +05:30
Gursheen Anand
aba3065573 refactor: remove balance formatter 2023-10-12 12:04:44 +05:30
Gursheen Anand
e95dce6d8d refactor: remove balance fields from jv account 2023-10-12 11:54:12 +05:30
820 changed files with 128593 additions and 39258 deletions

View File

@@ -9,6 +9,13 @@ trim_trailing_whitespace = true
charset = utf-8
# python, js indentation settings
[{*.py,*.js}]
[{*.py,*.js,*.vue,*.css,*.scss,*.html}]
indent_style = tab
indent_size = 4
max_line_length = 110
# JSON files - mostly doctype schema files
[{*.json}]
insert_final_newline = false
indent_style = space
indent_size = 2

View File

@@ -124,6 +124,7 @@
"beforeEach": true,
"onScan": true,
"extend_cscript": true,
"localforage": true
"localforage": true,
"Plaid": true
}
}

View File

@@ -32,3 +32,6 @@ baec607ff5905b1c67531096a9cf50ec7ff00a5d
# bulk refactor with sourcery
eb9ee3f79b94e594fc6dfa4f6514580e125eee8c
# js formatting
ec74a5e56617bbd76ac402451468fd4668af543d

40
.github/helper/update_pot_file.sh vendored Normal file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
set -e
cd ~ || exit
echo "Setting Up Bench..."
pip install frappe-bench
bench -v init frappe-bench --skip-assets --skip-redis-config-generation --python "$(which python)"
cd ./frappe-bench || exit
echo "Get ERPNext..."
bench get-app --skip-assets erpnext "${GITHUB_WORKSPACE}"
echo "Generating POT file..."
bench generate-pot-file --app erpnext
cd ./apps/erpnext || exit
echo "Configuring git user..."
git config user.email "developers@erpnext.com"
git config user.name "frappe-pr-bot"
echo "Setting the correct git remote..."
# Here, the git remote is a local file path by default. Let's change it to the upstream repo.
git remote set-url upstream https://github.com/frappe/erpnext.git
echo "Creating a new branch..."
isodate=$(date -u +"%Y-%m-%d")
branch_name="pot_${BASE_BRANCH}_${isodate}"
git checkout -b "${branch_name}"
echo "Commiting changes..."
git add .
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

38
.github/workflows/generate-pot-file.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
# This workflow is agnostic to branches. Only maintain on develop branch.
# To add/remove branches just modify the matrix.
name: Regenerate POT file (translatable strings)
on:
schedule:
# 9:30 UTC => 3 PM IST Sunday
- cron: "30 9 * * 0"
workflow_dispatch:
jobs:
regeneratee-pot-file:
name: Release
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
branch: ["develop"]
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ matrix.branch }}
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Run script to update POT file
run: |
bash ${GITHUB_WORKSPACE}/.github/helper/update_pot_file.sh
env:
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
BASE_BRANCH: ${{ matrix.branch }}

View File

@@ -31,6 +31,9 @@ jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 60
env:
NODE_ENV: "production"
WITH_COVERAGE: ${{ github.event_name != 'pull_request' }}
strategy:
fail-fast: false
@@ -117,11 +120,11 @@ jobs:
FRAPPE_BRANCH: ${{ github.event.inputs.branch }}
- name: Run Tests
run: 'cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --with-coverage --total-builds 4 --build-number ${{ matrix.container }}'
run: 'cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --total-builds 4 --build-number ${{ matrix.container }}'
env:
TYPE: server
CI_BUILD_ID: ${{ github.run_id }}
ORCHESTRATOR_URL: http://test-orchestrator.frappe.io
CAPTURE_COVERAGE: ${{ github.event_name != 'pull_request' }}
- name: Show bench output
if: ${{ always() }}
@@ -129,6 +132,7 @@ jobs:
- name: Upload coverage data
uses: actions/upload-artifact@v3
if: github.event_name != 'pull_request'
with:
name: coverage-${{ matrix.container }}
path: /home/runner/frappe-bench/sites/coverage.xml
@@ -137,6 +141,7 @@ jobs:
name: Coverage Wrap Up
needs: test
runs-on: ubuntu-latest
if: ${{ github.event_name != 'pull_request' }}
steps:
- name: Clone
uses: actions/checkout@v2
@@ -148,5 +153,6 @@ jobs:
uses: codecov/codecov-action@v2
with:
name: MariaDB
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
verbose: true

1
.gitignore vendored
View File

@@ -2,7 +2,6 @@
*.py~
.DS_Store
conf.py
locale
latest_updates.json
.wnf-lang-status
*.egg-info

View File

@@ -20,6 +20,23 @@ repos:
- id: check-yaml
- id: debug-statements
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
hooks:
- id: prettier
types_or: [javascript, vue, scss]
# Ignore any files that might contain jinja / bundles
exclude: |
(?x)^(
erpnext/public/dist/.*|
cypress/.*|
.*node_modules.*|
.*boilerplate.*|
erpnext/public/js/controllers/.*|
erpnext/templates/pages/order.js|
erpnext/templates/includes/.*
)$
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.44.0
hooks:

View File

@@ -7,8 +7,7 @@
<p>ERP made simple</p>
</p>
[![CI](https://github.com/frappe/erpnext/actions/workflows/server-tests.yml/badge.svg?branch=develop)](https://github.com/frappe/erpnext/actions/workflows/server-tests.yml)
[![UI](https://github.com/erpnext/erpnext_ui_tests/actions/workflows/ui-tests.yml/badge.svg?branch=develop&event=schedule)](https://github.com/erpnext/erpnext_ui_tests/actions/workflows/ui-tests.yml)
[![CI](https://github.com/frappe/erpnext/actions/workflows/server-tests-mariadb.yml/badge.svg?event=schedule)](https://github.com/frappe/erpnext/actions/workflows/server-tests-mariadb.yml)
[![Open Source Helpers](https://www.codetriage.com/frappe/erpnext/badges/users.svg)](https://www.codetriage.com/frappe/erpnext)
[![codecov](https://codecov.io/gh/frappe/erpnext/branch/develop/graph/badge.svg?token=0TwvyUg3I5)](https://codecov.io/gh/frappe/erpnext)
[![docker pulls](https://img.shields.io/docker/pulls/frappe/erpnext-worker.svg)](https://hub.docker.com/r/frappe/erpnext-worker)

View File

@@ -1,25 +1,13 @@
module.exports = {
parserPreset: 'conventional-changelog-conventionalcommits',
parserPreset: "conventional-changelog-conventionalcommits",
rules: {
'subject-empty': [2, 'never'],
'type-case': [2, 'always', 'lower-case'],
'type-empty': [2, 'never'],
'type-enum': [
"subject-empty": [2, "never"],
"type-case": [2, "always", "lower-case"],
"type-empty": [2, "never"],
"type-enum": [
2,
'always',
[
'build',
'chore',
'ci',
'docs',
'feat',
'fix',
'perf',
'refactor',
'revert',
'style',
'test',
],
"always",
["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test"],
],
},
};

View File

@@ -1,3 +1,4 @@
files:
- source: /erpnext/locale/main.pot
translation: /erpnext/locale/%two_letters_code%.po
pull_request_title: "chore: sync translations from crowdin"

View File

@@ -13,7 +13,7 @@ def get_default_company(user=None):
if not user:
user = frappe.session.user
companies = get_user_default_as_list(user, "company")
companies = get_user_default_as_list("company", user)
if companies:
default_company = companies[0]
else:

View File

@@ -1,4 +1,4 @@
frappe.provide('frappe.dashboards.chart_sources');
frappe.provide("frappe.dashboards.chart_sources");
frappe.dashboards.chart_sources["Account Balance Timeline"] = {
method: "erpnext.accounts.dashboard_chart_source.account_balance_timeline.account_balance_timeline.get",
@@ -9,14 +9,14 @@ frappe.dashboards.chart_sources["Account Balance Timeline"] = {
fieldtype: "Link",
options: "Company",
default: frappe.defaults.get_user_default("Company"),
reqd: 1
reqd: 1,
},
{
fieldname: "account",
label: __("Account"),
fieldtype: "Link",
options: "Account",
reqd: 1
reqd: 1,
},
]
],
};

View File

@@ -26,19 +26,14 @@ frappe.ui.form.on("Account", {
frm.toggle_enable(["is_group", "company"], false);
if (cint(frm.doc.is_group) == 0) {
frm.toggle_display(
"freeze_account",
frm.doc.__onload && frm.doc.__onload.can_freeze_account
);
frm.toggle_display("freeze_account", frm.doc.__onload && frm.doc.__onload.can_freeze_account);
}
// read-only for root accounts
if (!frm.is_new()) {
if (!frm.doc.parent_account) {
frm.set_read_only();
frm.set_intro(
__("This is a root account and cannot be edited.")
);
frm.set_intro(__("This is a root account and cannot be edited."));
} else {
// credit days and type if customer or supplier
frm.set_intro(null);
@@ -80,27 +75,33 @@ frappe.ui.form.on("Account", {
);
if (frm.doc.is_group == 1) {
frm.add_custom_button(__('Convert to Non-Group'), function () {
return frappe.call({
doc: frm.doc,
method: 'convert_group_to_ledger',
callback: function() {
frm.refresh();
}
});
}, __('Actions'));
} else if (cint(frm.doc.is_group) == 0
&& frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
frm.add_custom_button(__('General Ledger'), function () {
frappe.route_options = {
"account": frm.doc.name,
"from_date": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
"to_date": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
"company": frm.doc.company
};
frappe.set_route("query-report", "General Ledger");
}, __('View'));
frm.add_custom_button(
__("Convert to Non-Group"),
function () {
return frappe.call({
doc: frm.doc,
method: "convert_group_to_ledger",
callback: function () {
frm.refresh();
},
});
},
__("Actions")
);
} else if (cint(frm.doc.is_group) == 0 && frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
frm.add_custom_button(
__("General Ledger"),
function () {
frappe.route_options = {
account: frm.doc.name,
from_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
to_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
company: frm.doc.company,
};
frappe.set_route("query-report", "General Ledger");
},
__("View")
);
frm.add_custom_button(
__("Convert to Group"),
@@ -193,14 +194,8 @@ frappe.ui.form.on("Account", {
if (r.message) {
frappe.set_route("Form", "Account", r.message);
} else {
frm.set_value(
"account_number",
data.account_number
);
frm.set_value(
"account_name",
data.account_name
);
frm.set_value("account_number", data.account_number);
frm.set_value("account_name", data.account_name);
}
d.hide();
}

View File

@@ -118,6 +118,7 @@ class Account(NestedSet):
self.validate_balance_must_be_debit_or_credit()
self.validate_account_currency()
self.validate_root_company_and_sync_account_to_children()
self.validate_receivable_payable_account_type()
def validate_parent_child_account_type(self):
if self.parent_account:
@@ -188,6 +189,24 @@ class Account(NestedSet):
"Balance Sheet" if self.root_type in ("Asset", "Liability", "Equity") else "Profit and Loss"
)
def validate_receivable_payable_account_type(self):
doc_before_save = self.get_doc_before_save()
receivable_payable_types = ["Receivable", "Payable"]
if (
doc_before_save
and doc_before_save.account_type in receivable_payable_types
and doc_before_save.account_type != self.account_type
):
# check for ledger entries
if frappe.db.get_all("GL Entry", filters={"account": self.name, "is_cancelled": 0}, limit=1):
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.msgprint(msg)
self.add_comment("Comment", msg)
def validate_root_details(self):
doc_before_save = self.get_doc_before_save()

View File

@@ -1,4 +1,4 @@
frappe.provide("frappe.treeview_settings")
frappe.provide("frappe.treeview_settings");
frappe.treeview_settings["Account"] = {
breadcrumb: "Accounts",
@@ -7,12 +7,12 @@ frappe.treeview_settings["Account"] = {
filters: [
{
fieldname: "company",
fieldtype:"Select",
fieldtype: "Select",
options: erpnext.utils.get_tree_options("company"),
label: __("Company"),
default: erpnext.utils.get_tree_default("company"),
on_change: function() {
var me = frappe.treeview_settings['Account'].treeview;
on_change: function () {
var me = frappe.treeview_settings["Account"].treeview;
var company = me.page.fields_dict.company.get_value();
if (!company) {
frappe.throw(__("Please set a Company"));
@@ -22,30 +22,36 @@ frappe.treeview_settings["Account"] = {
args: {
company: company,
},
callback: function(r) {
if(r.message) {
callback: function (r) {
if (r.message) {
let root_company = r.message.length ? r.message[0] : "";
me.page.fields_dict.root_company.set_value(root_company);
frappe.db.get_value("Company", {"name": company}, "allow_account_creation_against_child_company", (r) => {
frappe.flags.ignore_root_company_validation = r.allow_account_creation_against_child_company;
});
frappe.db.get_value(
"Company",
{ name: company },
"allow_account_creation_against_child_company",
(r) => {
frappe.flags.ignore_root_company_validation =
r.allow_account_creation_against_child_company;
}
);
}
}
},
});
}
},
},
{
fieldname: "root_company",
fieldtype:"Data",
fieldtype: "Data",
label: __("Root Company"),
hidden: true,
disable_onchange: true
}
disable_onchange: true,
},
],
root_label: "Accounts",
get_tree_nodes: 'erpnext.accounts.utils.get_children',
on_get_node: function(nodes, deep=false) {
get_tree_nodes: "erpnext.accounts.utils.get_children",
on_get_node: function (nodes, deep = false) {
if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return;
let accounts = [];
@@ -57,151 +63,231 @@ frappe.treeview_settings["Account"] = {
}
frappe.db.get_single_value("Accounts Settings", "show_balance_in_coa").then((value) => {
if(value) {
if (value) {
const get_balances = frappe.call({
method: 'erpnext.accounts.utils.get_account_balances',
method: "erpnext.accounts.utils.get_account_balances",
args: {
accounts: accounts,
company: cur_tree.args.company
company: cur_tree.args.company,
},
});
get_balances.then(r => {
get_balances.then((r) => {
if (!r.message || r.message.length == 0) return;
for (let account of r.message) {
const node = cur_tree.nodes && cur_tree.nodes[account.value];
if (!node || node.is_root) continue;
// show Dr if positive since balance is calculated as debit - credit else show Cr
const balance = account.balance_in_account_currency || account.balance;
const dr_or_cr = balance > 0 ? __("Dr"): __("Cr");
const dr_or_cr = balance > 0 ? __("Dr") : __("Cr");
const format = (value, currency) => format_currency(Math.abs(value), currency);
if (account.balance!==undefined) {
node.parent && node.parent.find('.balance-area').remove();
$('<span class="balance-area pull-right">'
+ (account.balance_in_account_currency ?
(format(account.balance_in_account_currency, account.account_currency) + " / ") : "")
+ format(account.balance, account.company_currency)
+ " " + dr_or_cr
+ '</span>').insertBefore(node.$ul);
if (account.balance !== undefined) {
node.parent && node.parent.find(".balance-area").remove();
$(
'<span class="balance-area pull-right">' +
(account.balance_in_account_currency
? format(
account.balance_in_account_currency,
account.account_currency
) + " / "
: "") +
format(account.balance, account.company_currency) +
" " +
dr_or_cr +
"</span>"
).insertBefore(node.$ul);
}
}
});
}
});
},
add_tree_node: 'erpnext.accounts.utils.add_ac',
menu_items:[
add_tree_node: "erpnext.accounts.utils.add_ac",
menu_items: [
{
label: __('New Company'),
action: function() { frappe.new_doc("Company", true) },
condition: 'frappe.boot.user.can_create.indexOf("Company") !== -1'
}
label: __("New Company"),
action: function () {
frappe.new_doc("Company", true);
},
condition: 'frappe.boot.user.can_create.indexOf("Company") !== -1',
},
],
fields: [
{fieldtype:'Data', fieldname:'account_name', label:__('New Account Name'), reqd:true,
description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers")},
{fieldtype:'Data', fieldname:'account_number', label:__('Account Number'),
description: __("Number of new Account, it will be included in the account name as a prefix")},
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
{fieldtype:'Select', fieldname:'root_type', label:__('Root Type'),
options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n'),
depends_on: 'eval:doc.is_group && !doc.parent_account'},
{fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
options: frappe.get_meta("Account").fields.filter(d => d.fieldname=='account_type')[0].options,
description: __("Optional. This setting will be used to filter in various transactions.")
{
fieldtype: "Data",
fieldname: "account_name",
label: __("New Account Name"),
reqd: true,
description: __(
"Name of new Account. Note: Please don't create accounts for Customers and Suppliers"
),
},
{
fieldtype: "Data",
fieldname: "account_number",
label: __("Account Number"),
description: __("Number of new Account, it will be included in the account name as a prefix"),
},
{
fieldtype: "Check",
fieldname: "is_group",
label: __("Is Group"),
description: __(
"Further accounts can be made under Groups, but entries can be made against non-Groups"
),
},
{
fieldtype: "Select",
fieldname: "root_type",
label: __("Root Type"),
options: ["Asset", "Liability", "Equity", "Income", "Expense"].join("\n"),
depends_on: "eval:doc.is_group && !doc.parent_account",
},
{
fieldtype: "Select",
fieldname: "account_type",
label: __("Account Type"),
options: frappe.get_meta("Account").fields.filter((d) => d.fieldname == "account_type")[0]
.options,
description: __("Optional. This setting will be used to filter in various transactions."),
},
{
fieldtype: "Float",
fieldname: "tax_rate",
label: __("Tax Rate"),
depends_on: 'eval:doc.is_group==0&&doc.account_type=="Tax"',
},
{
fieldtype: "Link",
fieldname: "account_currency",
label: __("Currency"),
options: "Currency",
description: __("Optional. Sets company's default currency, if not specified."),
},
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate'),
depends_on: 'eval:doc.is_group==0&&doc.account_type=="Tax"'},
{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency",
description: __("Optional. Sets company's default currency, if not specified.")}
],
ignore_fields:["parent_account"],
onload: function(treeview) {
frappe.treeview_settings['Account'].treeview = {};
$.extend(frappe.treeview_settings['Account'].treeview, treeview);
ignore_fields: ["parent_account"],
onload: function (treeview) {
frappe.treeview_settings["Account"].treeview = {};
$.extend(frappe.treeview_settings["Account"].treeview, treeview);
function get_company() {
return treeview.page.fields_dict.company.get_value();
}
// tools
treeview.page.add_inner_button(__("Chart of Cost Centers"), function() {
frappe.set_route('Tree', 'Cost Center', {company: get_company()});
}, __('View'));
treeview.page.add_inner_button(
__("Chart of Cost Centers"),
function () {
frappe.set_route("Tree", "Cost Center", { company: get_company() });
},
__("View")
);
treeview.page.add_inner_button(__("Opening Invoice Creation Tool"), function() {
frappe.set_route('Form', 'Opening Invoice Creation Tool', {company: get_company()});
}, __('View'));
treeview.page.add_inner_button(
__("Opening Invoice Creation Tool"),
function () {
frappe.set_route("Form", "Opening Invoice Creation Tool", { company: get_company() });
},
__("View")
);
treeview.page.add_inner_button(__("Period Closing Voucher"), function() {
frappe.set_route('List', 'Period Closing Voucher', {company: get_company()});
}, __('View'));
treeview.page.add_inner_button(
__("Period Closing Voucher"),
function () {
frappe.set_route("List", "Period Closing Voucher", { company: get_company() });
},
__("View")
);
treeview.page.add_inner_button(__("Journal Entry"), function() {
frappe.new_doc('Journal Entry', {company: get_company()});
}, __('Create'));
treeview.page.add_inner_button(__("Company"), function() {
frappe.new_doc('Company');
}, __('Create'));
treeview.page.add_inner_button(
__("Journal Entry"),
function () {
frappe.new_doc("Journal Entry", { company: get_company() });
},
__("Create")
);
treeview.page.add_inner_button(
__("Company"),
function () {
frappe.new_doc("Company");
},
__("Create")
);
// financial statements
for (let report of ['Trial Balance', 'General Ledger', 'Balance Sheet',
'Profit and Loss Statement', 'Cash Flow Statement', 'Accounts Payable', 'Accounts Receivable']) {
treeview.page.add_inner_button(__(report), function() {
frappe.set_route('query-report', report, {company: get_company()});
}, __('Financial Statements'));
for (let report of [
"Trial Balance",
"General Ledger",
"Balance Sheet",
"Profit and Loss Statement",
"Cash Flow Statement",
"Accounts Payable",
"Accounts Receivable",
]) {
treeview.page.add_inner_button(
__(report),
function () {
frappe.set_route("query-report", report, { company: get_company() });
},
__("Financial Statements")
);
}
},
post_render: function(treeview) {
frappe.treeview_settings['Account'].treeview["tree"] = treeview.tree;
treeview.page.set_primary_action(__("New"), function() {
let root_company = treeview.page.fields_dict.root_company.get_value();
post_render: function (treeview) {
frappe.treeview_settings["Account"].treeview["tree"] = treeview.tree;
treeview.page.set_primary_action(
__("New"),
function () {
let root_company = treeview.page.fields_dict.root_company.get_value();
if(root_company) {
frappe.throw(__("Please add the account to root level Company - {0}"), [root_company]);
} else {
treeview.new_node();
}
}, "add");
if (root_company) {
frappe.throw(__("Please add the account to root level Company - {0}"), [root_company]);
} else {
treeview.new_node();
}
},
"add"
);
},
toolbar: [
{
label:__("Add Child"),
condition: function(node) {
return frappe.boot.user.can_create.indexOf("Account") !== -1
&& (!frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value()
|| frappe.flags.ignore_root_company_validation)
&& node.expandable && !node.hide_add;
label: __("Add Child"),
condition: function (node) {
return (
frappe.boot.user.can_create.indexOf("Account") !== -1 &&
(!frappe.treeview_settings[
"Account"
].treeview.page.fields_dict.root_company.get_value() ||
frappe.flags.ignore_root_company_validation) &&
node.expandable &&
!node.hide_add
);
},
click: function() {
var me = frappe.views.trees['Account'];
click: function () {
var me = frappe.views.trees["Account"];
me.new_node();
},
btnClass: "hidden-xs"
btnClass: "hidden-xs",
},
{
condition: function(node) {
return !node.root && frappe.boot.user.can_read.indexOf("GL Entry") !== -1
condition: function (node) {
return !node.root && frappe.boot.user.can_read.indexOf("GL Entry") !== -1;
},
label: __("View Ledger"),
click: function(node, btn) {
click: function (node, btn) {
frappe.route_options = {
"account": node.label,
"from_date": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
"to_date": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
"company": frappe.treeview_settings['Account'].treeview.page.fields_dict.company.get_value()
account: node.label,
from_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
to_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
company:
frappe.treeview_settings["Account"].treeview.page.fields_dict.company.get_value(),
};
frappe.set_route("query-report", "General Ledger");
},
btnClass: "hidden-xs"
}
btnClass: "hidden-xs",
},
],
extend_toolbar: true
}
extend_toolbar: true,
};

View File

@@ -56,7 +56,9 @@
"Constru\u00e7\u00f5es em Andamento de Im\u00f3veis Destinados \u00e0 Venda": {},
"Estoques Destinados \u00e0 Doa\u00e7\u00e3o": {},
"Im\u00f3veis Destinados \u00e0 Venda": {},
"Insumos (materiais diretos)": {},
"Insumos (materiais diretos)": {
"account_type": "Stock"
},
"Insumos Agropecu\u00e1rios": {},
"Mercadorias para Revenda": {},
"Outras 11": {},
@@ -146,6 +148,65 @@
"root_type": "Asset"
},
"CUSTOS DE PRODU\u00c7\u00c3O": {
"CUSTO DOS PRODUTOS E SERVI\u00c7OS VENDIDOS": {
"CUSTO DOS PRODUTOS VENDIDOS": {
"CUSTO DOS PRODUTOS VENDIDOS PARA AS DEMAIS ATIVIDADES": {
"Custos dos Produtos Vendidos em Geral": {
"account_type": "Cost of Goods Sold"
},
"Outros Custos 4": {},
"account_type": "Cost of Goods Sold"
},
"CUSTO DOS PRODUTOS VENDIDOS PARA ASSIST\u00caNCIA SOCIAL": {
"Custos dos Produtos para Assist\u00eancia Social - Gratuidades": {},
"Custos dos Produtos para Assist\u00eancia Social - Vendidos": {},
"Outras": {}
},
"CUSTO DOS PRODUTOS VENDIDOS PARA EDUCA\u00c7\u00c3O": {
"Custos dos Produtos para Educa\u00e7\u00e3o - Gratuidades": {},
"Custos dos Produtos para Educa\u00e7\u00e3o - Vendidos": {},
"Outros Custos 6": {}
},
"CUSTO DOS PRODUTOS VENDIDOS PARA SA\u00daDE": {
"Custos dos Produtos para Sa\u00fade - Gratuidades": {},
"Custos dos Produtos para Sa\u00fade \u2013 Vendidos": {},
"Outros Custos 5": {}
},
"account_type": "Cost of Goods Sold"
},
"CUSTO DOS SERVI\u00c7OS PRESTADOS": {
"CUSTO DOS SERVI\u00c7OS PRESTADOS PARA AS DEMAIS ATIVIDADES": {
"Custo dos Servi\u00e7os Prestados em Geral": {},
"Outros Custos": {}
},
"CUSTO DOS SERVI\u00c7OS PRESTADOS PARA ASSIST\u00caNCIA SOCIAL": {
"Custo dos Servi\u00e7os Prestados a Conv\u00eanios/Contratos/Parcerias": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es 1": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es/Subven\u00e7\u00f5es Vinculadas 1": {},
"Custo dos Servi\u00e7os Prestados a Gratuidade 1": {},
"Custo dos Servi\u00e7os Prestados a Pacientes Particulares": {},
"Outros Custos 2": {}
},
"CUSTO DOS SERVI\u00c7OS PRESTADOS PARA EDUCA\u00c7\u00c3O": {
"Custo dos Servi\u00e7os Prestados a Alunos N\u00e3o Bolsistas": {},
"Custo dos Servi\u00e7os Prestados a Conv\u00eanios/Contratos/Parcerias (Exceto PROUNI)": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es/Subven\u00e7\u00f5es Vinculadas": {},
"Custo dos Servi\u00e7os Prestados a Gratuidade": {},
"Custo dos Servi\u00e7os Prestados ao PROUNI": {},
"Outros Custos 1": {}
},
"CUSTO DOS SERVI\u00c7OS PRESTADOS PARA SA\u00daDE": {
"Custo dos Servi\u00e7os Prestados a Conv\u00eanios SUS": {},
"Custo dos Servi\u00e7os Prestados a Conv\u00eanios/Contratos/Parcerias 1": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es 2": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es/Subven\u00e7\u00f5es Vinculadas 2": {},
"Custo dos Servi\u00e7os Prestados a Gratuidade 2": {},
"Custo dos Servi\u00e7os Prestados a Pacientes Particulares 1": {},
"Outros Custos 3": {}
}
}
},
"CUSTO DOS BENS E SERVI\u00c7OS PRODUZIDOS": {
"CUSTO DOS PRODUTOS DE FABRICA\u00c7\u00c3O PR\u00d3PRIA PRODUZIDOS": {
"Alimenta\u00e7\u00e3o do Trabalhador": {},
@@ -621,7 +682,9 @@
"Receita das Unidades Imobili\u00e1rias Vendidas": {},
"Receita de Exporta\u00e7\u00e3o Direta de Mercadorias e Produtos": {},
"Receita de Exporta\u00e7\u00e3o de Servi\u00e7os": {},
"Receita de Loca\u00e7\u00e3o de Bens M\u00f3veis e Im\u00f3veis": {},
"Receita de Loca\u00e7\u00e3o de Bens M\u00f3veis e Im\u00f3veis": {
"account_type": "Income Account"
},
"Receita de Vendas de Mercadorias e Produtos a Comercial Exportadora com Fim Espec\u00edfico de Exporta\u00e7\u00e3o": {}
}
}
@@ -645,65 +708,6 @@
}
},
"RESULTADO OPERACIONAL": {
"CUSTO DOS PRODUTOS E SERVI\u00c7OS VENDIDOS": {
"CUSTO DOS PRODUTOS VENDIDOS": {
"CUSTO DOS PRODUTOS VENDIDOS PARA AS DEMAIS ATIVIDADES": {
"Custos dos Produtos Vendidos em Geral": {
"account_type": "Cost of Goods Sold"
},
"Outros Custos 4": {},
"account_type": "Cost of Goods Sold"
},
"CUSTO DOS PRODUTOS VENDIDOS PARA ASSIST\u00caNCIA SOCIAL": {
"Custos dos Produtos para Assist\u00eancia Social - Gratuidades": {},
"Custos dos Produtos para Assist\u00eancia Social - Vendidos": {},
"Outras": {}
},
"CUSTO DOS PRODUTOS VENDIDOS PARA EDUCA\u00c7\u00c3O": {
"Custos dos Produtos para Educa\u00e7\u00e3o - Gratuidades": {},
"Custos dos Produtos para Educa\u00e7\u00e3o - Vendidos": {},
"Outros Custos 6": {}
},
"CUSTO DOS PRODUTOS VENDIDOS PARA SA\u00daDE": {
"Custos dos Produtos para Sa\u00fade - Gratuidades": {},
"Custos dos Produtos para Sa\u00fade \u2013 Vendidos": {},
"Outros Custos 5": {}
},
"account_type": "Cost of Goods Sold"
},
"CUSTO DOS SERVI\u00c7OS PRESTADOS": {
"CUSTO DOS SERVI\u00c7OS PRESTADOS PARA AS DEMAIS ATIVIDADES": {
"Custo dos Servi\u00e7os Prestados em Geral": {},
"Outros Custos": {}
},
"CUSTO DOS SERVI\u00c7OS PRESTADOS PARA ASSIST\u00caNCIA SOCIAL": {
"Custo dos Servi\u00e7os Prestados a Conv\u00eanios/Contratos/Parcerias": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es 1": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es/Subven\u00e7\u00f5es Vinculadas 1": {},
"Custo dos Servi\u00e7os Prestados a Gratuidade 1": {},
"Custo dos Servi\u00e7os Prestados a Pacientes Particulares": {},
"Outros Custos 2": {}
},
"CUSTO DOS SERVI\u00c7OS PRESTADOS PARA EDUCA\u00c7\u00c3O": {
"Custo dos Servi\u00e7os Prestados a Alunos N\u00e3o Bolsistas": {},
"Custo dos Servi\u00e7os Prestados a Conv\u00eanios/Contratos/Parcerias (Exceto PROUNI)": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es/Subven\u00e7\u00f5es Vinculadas": {},
"Custo dos Servi\u00e7os Prestados a Gratuidade": {},
"Custo dos Servi\u00e7os Prestados ao PROUNI": {},
"Outros Custos 1": {}
},
"CUSTO DOS SERVI\u00c7OS PRESTADOS PARA SA\u00daDE": {
"Custo dos Servi\u00e7os Prestados a Conv\u00eanios SUS": {},
"Custo dos Servi\u00e7os Prestados a Conv\u00eanios/Contratos/Parcerias 1": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es 2": {},
"Custo dos Servi\u00e7os Prestados a Doa\u00e7\u00f5es/Subven\u00e7\u00f5es Vinculadas 2": {},
"Custo dos Servi\u00e7os Prestados a Gratuidade 2": {},
"Custo dos Servi\u00e7os Prestados a Pacientes Particulares 1": {},
"Outros Custos 3": {}
}
}
},
"DESPESAS OPERACIONAIS": {
"DESPESAS OPERACIONAIS 1": {
"DESPESAS OPERACIONAIS 2": {

View File

@@ -6,6 +6,7 @@ import unittest
import frappe
from frappe.test_runner import make_test_records
from frappe.utils import nowdate
from erpnext.accounts.doctype.account.account import (
InvalidAccountMergeError,
@@ -324,6 +325,19 @@ class TestAccount(unittest.TestCase):
acc.account_currency = "USD"
self.assertRaises(frappe.ValidationError, acc.save)
def test_account_balance(self):
from erpnext.accounts.utils import get_balance_on
if not frappe.db.exists("Account", "Test Percent Account %5 - _TC"):
acc = frappe.new_doc("Account")
acc.account_name = "Test Percent Account %5"
acc.parent_account = "Tax Assets - _TC"
acc.company = "_Test Company"
acc.insert()
balance = get_balance_on(account="Test Percent Account %5 - _TC", date=nowdate())
self.assertEqual(balance, 0)
def _make_test_records(verbose=None):
from frappe.test_runner import make_test_objects

View File

@@ -1,74 +1,86 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Accounting Dimension', {
refresh: function(frm) {
frm.set_query('document_type', () => {
frappe.ui.form.on("Accounting Dimension", {
refresh: function (frm) {
frm.set_query("document_type", () => {
let invalid_doctypes = frappe.model.core_doctypes_list;
invalid_doctypes.push('Accounting Dimension', 'Project',
'Cost Center', 'Accounting Dimension Detail', 'Company');
invalid_doctypes.push(
"Accounting Dimension",
"Project",
"Cost Center",
"Accounting Dimension Detail",
"Company"
);
return {
filters: {
name: ['not in', invalid_doctypes]
}
name: ["not in", invalid_doctypes],
},
};
});
frm.set_query("offsetting_account", "dimension_defaults", function(doc, cdt, cdn) {
frm.set_query("offsetting_account", "dimension_defaults", function (doc, cdt, cdn) {
let d = locals[cdt][cdn];
return {
filters: {
company: d.company,
root_type: ["in", ["Asset", "Liability"]],
is_group: 0
}
}
is_group: 0,
},
};
});
if (!frm.is_new()) {
frm.add_custom_button(__('Show {0}', [frm.doc.document_type]), function () {
frm.add_custom_button(__("Show {0}", [frm.doc.document_type]), function () {
frappe.set_route("List", frm.doc.document_type);
});
let button = frm.doc.disabled ? "Enable" : "Disable";
frm.add_custom_button(__(button), function() {
frm.set_value('disabled', 1 - frm.doc.disabled);
frm.add_custom_button(__(button), function () {
frm.set_value("disabled", 1 - frm.doc.disabled);
frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
args: {
doc: frm.doc
doc: frm.doc,
},
freeze: true,
callback: function(r) {
callback: function (r) {
let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled";
frm.save();
frappe.show_alert({message:__(message), indicator:'green'});
}
frappe.show_alert({ message: __(message), indicator: "green" });
},
});
});
}
},
document_type: function(frm) {
document_type: function (frm) {
frm.set_value("label", frm.doc.document_type);
frm.set_value("fieldname", frappe.model.scrub(frm.doc.document_type));
frm.set_value('label', frm.doc.document_type);
frm.set_value('fieldname', frappe.model.scrub(frm.doc.document_type));
frappe.db.get_value('Accounting Dimension', {'document_type': frm.doc.document_type}, 'document_type', (r) => {
if (r && r.document_type) {
frm.set_df_property('document_type', 'description', "Document type is already set as dimension");
frappe.db.get_value(
"Accounting Dimension",
{ document_type: frm.doc.document_type },
"document_type",
(r) => {
if (r && r.document_type) {
frm.set_df_property(
"document_type",
"description",
"Document type is already set as dimension"
);
}
}
});
);
},
});
frappe.ui.form.on('Accounting Dimension Detail', {
dimension_defaults_add: function(frm, cdt, cdn) {
frappe.ui.form.on("Accounting Dimension Detail", {
dimension_defaults_add: function (frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.reference_document = frm.doc.document_type;
}
},
});

View File

@@ -11,6 +11,10 @@ from frappe.model import core_doctypes_list
from frappe.model.document import Document
from frappe.utils import cstr
from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import (
get_allowed_types_from_settings,
)
class AccountingDimension(Document):
# begin: auto-generated types
@@ -106,6 +110,7 @@ def make_dimension_in_accounting_doctypes(doc, doclist=None):
doc_count = len(get_accounting_dimensions())
count = 0
repostable_doctypes = get_allowed_types_from_settings()
for doctype in doclist:
@@ -121,6 +126,7 @@ def make_dimension_in_accounting_doctypes(doc, doclist=None):
"options": doc.document_type,
"insert_after": insert_after_field,
"owner": "Administrator",
"allow_on_submit": 1 if doctype in repostable_doctypes else 0,
}
meta = frappe.get_meta(doctype, cached=False)

View File

@@ -1,10 +1,9 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Accounting Dimension Filter', {
refresh: function(frm, cdt, cdn) {
let help_content =
`<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);">
frappe.ui.form.on("Accounting Dimension Filter", {
refresh: function (frm, cdt, cdn) {
let help_content = `<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);">
<tr><td>
<p>
<i class="fa fa-hand-right"></i>
@@ -13,77 +12,80 @@ frappe.ui.form.on('Accounting Dimension Filter', {
</td></tr>
</table>`;
frm.set_df_property('dimension_filter_help', 'options', help_content);
frm.set_df_property("dimension_filter_help", "options", help_content);
},
onload: function(frm) {
frm.set_query('applicable_on_account', 'accounts', function() {
onload: function (frm) {
frm.set_query("applicable_on_account", "accounts", function () {
return {
filters: {
'company': frm.doc.company
}
company: frm.doc.company,
},
};
});
frappe.db.get_list('Accounting Dimension',
{fields: ['document_type']}).then((res) => {
let options = ['Cost Center', 'Project'];
frappe.db.get_list("Accounting Dimension", { fields: ["document_type"] }).then((res) => {
let options = ["Cost Center", "Project"];
res.forEach((dimension) => {
options.push(dimension.document_type);
});
frm.set_df_property('accounting_dimension', 'options', options);
frm.set_df_property("accounting_dimension", "options", options);
});
frm.trigger('setup_filters');
frm.trigger("setup_filters");
},
setup_filters: function(frm) {
setup_filters: function (frm) {
let filters = {};
if (frm.doc.accounting_dimension) {
frappe.model.with_doctype(frm.doc.accounting_dimension, function() {
frappe.model.with_doctype(frm.doc.accounting_dimension, function () {
if (frappe.model.is_tree(frm.doc.accounting_dimension)) {
filters['is_group'] = 0;
filters["is_group"] = 0;
}
if (frappe.meta.has_field(frm.doc.accounting_dimension, 'company')) {
filters['company'] = frm.doc.company;
if (frappe.meta.has_field(frm.doc.accounting_dimension, "company")) {
filters["company"] = frm.doc.company;
}
frm.set_query('dimension_value', 'dimensions', function() {
frm.set_query("dimension_value", "dimensions", function () {
return {
filters: filters
filters: filters,
};
});
});
}
},
accounting_dimension: function(frm) {
accounting_dimension: function (frm) {
frm.clear_table("dimensions");
let row = frm.add_child("dimensions");
row.accounting_dimension = frm.doc.accounting_dimension;
frm.fields_dict["dimensions"].grid.update_docfield_property("dimension_value", "label", frm.doc.accounting_dimension);
frm.fields_dict["dimensions"].grid.update_docfield_property(
"dimension_value",
"label",
frm.doc.accounting_dimension
);
frm.refresh_field("dimensions");
frm.trigger('setup_filters');
frm.trigger("setup_filters");
},
apply_restriction_on_values: function(frm) {
apply_restriction_on_values: function (frm) {
/** If restriction on values is not applied, we should set "allow_or_restrict" to "Restrict" with an empty allowed dimension table.
* Hence it's not "restricted" on any value.
*/
*/
if (!frm.doc.apply_restriction_on_values) {
frm.set_value("allow_or_restrict", "Restrict");
frm.clear_table("dimensions");
frm.refresh_field("dimensions");
}
}
},
});
frappe.ui.form.on('Allowed Dimension', {
dimensions_add: function(frm, cdt, cdn) {
frappe.ui.form.on("Allowed Dimension", {
dimensions_add: function (frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.accounting_dimension = frm.doc.accounting_dimension;
frm.refresh_field("dimensions");
}
},
});

View File

@@ -1,30 +1,33 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Accounting Period', {
onload: function(frm) {
if(frm.doc.closed_documents.length === 0 || (frm.doc.closed_documents.length === 1 && frm.doc.closed_documents[0].document_type == undefined)) {
frappe.ui.form.on("Accounting Period", {
onload: function (frm) {
if (
frm.doc.closed_documents.length === 0 ||
(frm.doc.closed_documents.length === 1 && frm.doc.closed_documents[0].document_type == undefined)
) {
frappe.call({
method: "get_doctypes_for_closing",
doc:frm.doc,
callback: function(r) {
if(r.message) {
doc: frm.doc,
callback: function (r) {
if (r.message) {
cur_frm.clear_table("closed_documents");
r.message.forEach(function(element) {
r.message.forEach(function (element) {
var c = frm.add_child("closed_documents");
c.document_type = element.document_type;
c.closed = element.closed;
});
refresh_field("closed_documents");
}
}
},
});
}
frm.set_query("document_type", "closed_documents", () => {
return {
query: "erpnext.controllers.queries.get_doctypes_for_closing",
}
};
});
}
},
});

View File

@@ -1,8 +1,6 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Accounts Settings', {
refresh: function(frm) {
}
frappe.ui.form.on("Accounts Settings", {
refresh: function (frm) {},
});

View File

@@ -1,7 +1,6 @@
{
"actions": [],
"creation": "2013-06-24 15:49:57",
"description": "Settings for Accounts",
"doctype": "DocType",
"document_type": "Other",
"editable_grid": 1,
@@ -462,7 +461,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-11-20 09:37:47.650347",
"modified": "2024-01-30 14:04:26.553554",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -1,8 +1,11 @@
frappe.ui.form.on('Accounts Settings', {
refresh: function(frm) {
frappe.ui.form.on("Accounts Settings", {
refresh: function (frm) {
frm.set_df_property("acc_frozen_upto", "label", "Books Closed Through");
frm.set_df_property("frozen_accounts_modifier", "label", "Role Allowed to Close Books & Make Changes to Closed Periods");
frm.set_df_property(
"frozen_accounts_modifier",
"label",
"Role Allowed to Close Books & Make Changes to Closed Periods"
);
frm.set_df_property("credit_controller", "label", "Credit Manager");
}
},
});

View File

@@ -1,38 +1,36 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.provide('erpnext.integrations');
frappe.provide("erpnext.integrations");
frappe.ui.form.on('Bank', {
onload: function(frm) {
frappe.ui.form.on("Bank", {
onload: function (frm) {
add_fields_to_mapping_table(frm);
},
refresh: function(frm) {
refresh: function (frm) {
add_fields_to_mapping_table(frm);
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
frm.toggle_display(["address_html", "contact_html"], !frm.doc.__islocal);
if (frm.doc.__islocal) {
frm.set_df_property('address_and_contact', 'hidden', 1);
frm.set_df_property("address_and_contact", "hidden", 1);
frappe.contacts.clear_address_and_contact(frm);
}
else {
frm.set_df_property('address_and_contact', 'hidden', 0);
} else {
frm.set_df_property("address_and_contact", "hidden", 0);
frappe.contacts.render_address_and_contact(frm);
}
if (frm.doc.plaid_access_token) {
frm.add_custom_button(__('Refresh Plaid Link'), () => {
frm.add_custom_button(__("Refresh Plaid Link"), () => {
new erpnext.integrations.refreshPlaidLink(frm.doc.plaid_access_token);
});
}
}
},
});
let add_fields_to_mapping_table = function (frm) {
let options = [];
frappe.model.with_doctype("Bank Transaction", function() {
frappe.model.with_doctype("Bank Transaction", function () {
let meta = frappe.get_meta("Bank Transaction");
meta.fields.forEach(value => {
meta.fields.forEach((value) => {
if (!["Section Break", "Column Break"].includes(value.fieldtype)) {
options.push(value.fieldname);
}
@@ -40,30 +38,32 @@ let add_fields_to_mapping_table = function (frm) {
});
frm.fields_dict.bank_transaction_mapping.grid.update_docfield_property(
'bank_transaction_field', 'options', options
"bank_transaction_field",
"options",
options
);
};
erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
constructor(access_token) {
this.access_token = access_token;
this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js';
this.plaidUrl = "https://cdn.plaid.com/link/v2/stable/link-initialize.js";
this.init_config();
}
async init_config() {
this.plaid_env = await frappe.db.get_single_value('Plaid Settings', 'plaid_env');
this.plaid_env = await frappe.db.get_single_value("Plaid Settings", "plaid_env");
this.token = await this.get_link_token_for_update();
this.init_plaid();
}
async get_link_token_for_update() {
const token = frappe.xcall(
'erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.get_link_token_for_update',
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.get_link_token_for_update",
{ access_token: this.access_token }
)
);
if (!token) {
frappe.throw(__('Cannot retrieve link token for update. Check Error Log for more information'));
frappe.throw(__("Cannot retrieve link token for update. Check Error Log for more information"));
}
return token;
}
@@ -90,35 +90,45 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
resolve();
return;
}
const el = document.createElement('script');
el.type = 'text/javascript';
const el = document.createElement("script");
el.type = "text/javascript";
el.async = true;
el.src = src;
el.addEventListener('load', resolve);
el.addEventListener('error', reject);
el.addEventListener('abort', reject);
el.addEventListener("load", resolve);
el.addEventListener("error", reject);
el.addEventListener("abort", reject);
document.head.appendChild(el);
});
}
onScriptLoaded(me) {
me.linkHandler = Plaid.create({ // eslint-disable-line no-undef
me.linkHandler = Plaid.create({
// eslint-disable-line no-undef
env: me.plaid_env,
token: me.token,
onSuccess: me.plaid_success
onSuccess: me.plaid_success,
});
}
onScriptError(error) {
frappe.msgprint(__("There was an issue connecting to Plaid's authentication server. Check browser console for more information"));
frappe.msgprint(
__(
"There was an issue connecting to Plaid's authentication server. Check browser console for more information"
)
);
console.log(error);
}
plaid_success(token, response) {
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.update_bank_account_ids', {
response: response,
}).then(() => {
frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
});
frappe
.xcall(
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.update_bank_account_ids",
{
response: response,
}
)
.then(() => {
frappe.show_alert({ message: __("Plaid Link Updated"), indicator: "green" });
});
}
};

View File

@@ -1,45 +1,49 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Bank Account', {
setup: function(frm) {
frm.set_query("account", function() {
frappe.ui.form.on("Bank Account", {
setup: function (frm) {
frm.set_query("account", function () {
return {
filters: {
'account_type': 'Bank',
'company': frm.doc.company,
'is_group': 0
}
account_type: "Bank",
company: frm.doc.company,
is_group: 0,
},
};
});
frm.set_query("party_type", function() {
frm.set_query("party_type", function () {
return {
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
};
});
},
refresh: function(frm) {
frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Bank Account' }
refresh: function (frm) {
frappe.dynamic_link = { doc: frm.doc, fieldname: "name", doctype: "Bank Account" };
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
frm.toggle_display(["address_html", "contact_html"], !frm.doc.__islocal);
if (frm.doc.__islocal) {
frappe.contacts.clear_address_and_contact(frm);
}
else {
} else {
frappe.contacts.render_address_and_contact(frm);
}
if (frm.doc.integration_id) {
frm.add_custom_button(__("Unlink external integrations"), function() {
frappe.confirm(__("This action will unlink this account from any external service integrating ERPNext with your bank accounts. It cannot be undone. Are you certain ?"), function() {
frm.set_value("integration_id", "");
});
frm.add_custom_button(__("Unlink external integrations"), function () {
frappe.confirm(
__(
"This action will unlink this account from any external service integrating ERPNext with your bank accounts. It cannot be undone. Are you certain ?"
),
function () {
frm.set_value("integration_id", "");
}
);
});
}
},
is_company_account: function(frm) {
frm.set_df_property('account', 'reqd', frm.doc.is_company_account);
}
is_company_account: function (frm) {
frm.set_df_property("account", "reqd", frm.doc.is_company_account);
},
});

View File

@@ -9,6 +9,7 @@ from frappe.contacts.address_and_contact import (
load_address_and_contact,
)
from frappe.model.document import Document
from frappe.utils import comma_and, get_link_to_form
class BankAccount(Document):
@@ -52,6 +53,19 @@ class BankAccount(Document):
def validate(self):
self.validate_company()
self.validate_iban()
self.validate_account()
def validate_account(self):
if self.account:
if accounts := frappe.db.get_all(
"Bank Account", filters={"account": self.account, "name": ["!=", self.name]}, as_list=1
):
frappe.throw(
_("'{0}' account is already used by {1}. Use another account.").format(
frappe.bold(self.account),
frappe.bold(comma_and([get_link_to_form(self.doctype, x[0]) for x in accounts])),
)
)
def validate_company(self):
if self.is_company_account and not self.company:

View File

@@ -1,8 +1,6 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Bank Account Subtype', {
refresh: function() {
}
frappe.ui.form.on("Bank Account Subtype", {
refresh: function () {},
});

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Bank Account Type', {
frappe.ui.form.on("Bank Account Type", {
// refresh: function(frm) {
// }
});

View File

@@ -2,80 +2,76 @@
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Bank Clearance", {
setup: function(frm) {
setup: function (frm) {
frm.add_fetch("account", "account_currency", "account_currency");
frm.set_query("account", function() {
frm.set_query("account", function () {
return {
"filters": {
"account_type": ["in",["Bank","Cash"]],
"is_group": 0,
}
filters: {
account_type: ["in", ["Bank", "Cash"]],
is_group: 0,
},
};
});
frm.set_query("bank_account", function () {
return {
filters: {
'is_company_account': 1
is_company_account: 1,
},
};
});
},
onload: function(frm) {
let default_bank_account = frappe.defaults.get_user_default("Company")?
locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "";
onload: function (frm) {
let default_bank_account = frappe.defaults.get_user_default("Company")
? locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]
: "";
frm.set_value("account", default_bank_account);
frm.set_value("from_date", frappe.datetime.month_start());
frm.set_value("to_date", frappe.datetime.month_end());
},
refresh: function(frm) {
refresh: function (frm) {
frm.disable_save();
frm.add_custom_button(__('Get Payment Entries'), () =>
frm.trigger("get_payment_entries")
);
frm.add_custom_button(__("Get Payment Entries"), () => frm.trigger("get_payment_entries"));
frm.change_custom_button_type(__('Get Payment Entries'), null, 'primary');
frm.change_custom_button_type(__("Get Payment Entries"), null, "primary");
},
update_clearance_date: function(frm) {
update_clearance_date: function (frm) {
return frappe.call({
method: "update_clearance_date",
doc: frm.doc,
callback: function(r, rt) {
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.change_custom_button_type(__("Get Payment Entries"), null, "primary");
frm.change_custom_button_type(__("Update Clearance Date"), null, "default");
}
}
},
});
},
get_payment_entries: function(frm) {
get_payment_entries: function (frm) {
return frappe.call({
method: "get_payment_entries",
doc: frm.doc,
callback: function(r, rt) {
callback: function (r, rt) {
frm.refresh_field("payment_entries");
if (frm.doc.payment_entries.length) {
frm.add_custom_button(__('Update Clearance Date'), () =>
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');
frm.change_custom_button_type(__("Get Payment Entries"), null, "default");
frm.change_custom_button_type(__("Update Clearance Date"), null, "primary");
}
}
},
});
}
},
});

View File

@@ -5,7 +5,9 @@
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 pypika import Order
import erpnext
@@ -179,39 +181,62 @@ def get_payment_entries_for_bank_clearance(
pos_sales_invoices, pos_purchase_invoices = [], []
if include_pos_transactions:
pos_sales_invoices = frappe.db.sql(
"""
select
"Sales Invoice Payment" as payment_document, sip.name as payment_entry, sip.amount as debit,
si.posting_date, si.customer as against_account, sip.clearance_date,
account.account_currency, 0 as credit
from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account
where
sip.account=%(account)s and si.docstatus=1 and sip.parent = si.name
and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s
order by
si.posting_date ASC, si.name DESC
""",
{"account": account, "from": from_date, "to": to_date},
as_dict=1,
)
si_payment = frappe.qb.DocType("Sales Invoice Payment")
si = frappe.qb.DocType("Sales Invoice")
acc = frappe.qb.DocType("Account")
pos_purchase_invoices = frappe.db.sql(
"""
select
"Purchase Invoice" as payment_document, pi.name as payment_entry, pi.paid_amount as credit,
pi.posting_date, pi.supplier as against_account, pi.clearance_date,
account.account_currency, 0 as debit
from `tabPurchase Invoice` pi, `tabAccount` account
where
pi.cash_bank_account=%(account)s and pi.docstatus=1 and account.name = pi.cash_bank_account
and pi.posting_date >= %(from)s and pi.posting_date <= %(to)s
order by
pi.posting_date ASC, pi.name DESC
""",
{"account": account, "from": from_date, "to": to_date},
as_dict=1,
)
pos_sales_invoices = (
frappe.qb.from_(si_payment)
.inner_join(si)
.on(si_payment.parent == si.name)
.inner_join(acc)
.on(si_payment.account == acc.name)
.select(
ConstantColumn("Sales Invoice").as_("payment_document"),
si.name.as_("payment_entry"),
si_payment.reference_no.as_("cheque_number"),
si_payment.amount.as_("debit"),
si.posting_date,
si.customer.as_("against_account"),
si_payment.clearance_date,
acc.account_currency,
ConstantColumn(0).as_("credit"),
)
.where(
(si.docstatus == 1)
& (si_payment.account == account)
& (si.posting_date >= from_date)
& (si.posting_date <= to_date)
)
.orderby(si.posting_date)
.orderby(si.name, order=Order.desc)
).run(as_dict=True)
pi = frappe.qb.DocType("Purchase Invoice")
pos_purchase_invoices = (
frappe.qb.from_(pi)
.inner_join(acc)
.on(pi.cash_bank_account == acc.name)
.select(
ConstantColumn("Purchase Invoice").as_("payment_document"),
pi.name.as_("payment_entry"),
pi.paid_amount.as_("credit"),
pi.posting_date,
pi.supplier.as_("against_account"),
pi.clearance_date,
acc.account_currency,
ConstantColumn(0).as_("debit"),
)
.where(
(pi.docstatus == 1)
& (pi.cash_bank_account == account)
& (pi.posting_date >= from_date)
& (pi.posting_date <= to_date)
)
.orderby(pi.posting_date)
.orderby(pi.name, order=Order.desc)
).run(as_dict=True)
entries = (
list(payment_entries)

View File

@@ -1,39 +1,39 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
cur_frm.add_fetch('bank_account','account','account');
cur_frm.add_fetch('bank_account','bank_account_no','bank_account_no');
cur_frm.add_fetch('bank_account','iban','iban');
cur_frm.add_fetch('bank_account','branch_code','branch_code');
cur_frm.add_fetch('bank','swift_number','swift_number');
cur_frm.add_fetch("bank_account", "account", "account");
cur_frm.add_fetch("bank_account", "bank_account_no", "bank_account_no");
cur_frm.add_fetch("bank_account", "iban", "iban");
cur_frm.add_fetch("bank_account", "branch_code", "branch_code");
cur_frm.add_fetch("bank", "swift_number", "swift_number");
frappe.ui.form.on('Bank Guarantee', {
setup: function(frm) {
frm.set_query("bank", function() {
return {
filters: {
company: frm.doc.company
}
};
});
frm.set_query("bank_account", function() {
frappe.ui.form.on("Bank Guarantee", {
setup: function (frm) {
frm.set_query("bank", function () {
return {
filters: {
company: frm.doc.company,
bank: frm.doc.bank
}
}
},
};
});
frm.set_query("project", function() {
frm.set_query("bank_account", function () {
return {
filters: {
customer: frm.doc.customer
}
company: frm.doc.company,
bank: frm.doc.bank,
},
};
});
frm.set_query("project", function () {
return {
filters: {
customer: frm.doc.customer,
},
};
});
},
bg_type: function(frm) {
bg_type: function (frm) {
if (frm.doc.bg_type == "Receiving") {
frm.set_value("reference_doctype", "Sales Order");
} else if (frm.doc.bg_type == "Providing") {
@@ -41,34 +41,33 @@ frappe.ui.form.on('Bank Guarantee', {
}
},
reference_docname: function(frm) {
reference_docname: function (frm) {
if (frm.doc.reference_docname && frm.doc.reference_doctype) {
let party_field = frm.doc.reference_doctype == "Sales Order" ? "customer" : "supplier";
frappe.call({
method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_voucher_details",
args: {
"bank_guarantee_type": frm.doc.bg_type,
"reference_name": frm.doc.reference_docname
bank_guarantee_type: frm.doc.bg_type,
reference_name: frm.doc.reference_docname,
},
callback: function(r) {
callback: function (r) {
if (r.message) {
if (r.message[party_field]) frm.set_value(party_field, r.message[party_field]);
if (r.message.project) frm.set_value("project", r.message.project);
if (r.message.grand_total) frm.set_value("amount", r.message.grand_total);
}
}
},
});
}
},
start_date: function(frm) {
start_date: function (frm) {
var end_date = frappe.datetime.add_days(cur_frm.doc.start_date, cur_frm.doc.validity - 1);
cur_frm.set_value("end_date", end_date);
},
validity: function(frm) {
validity: function (frm) {
var end_date = frappe.datetime.add_days(cur_frm.doc.start_date, cur_frm.doc.validity - 1);
cur_frm.set_value("end_date", end_date);
}
},
});

View File

@@ -8,21 +8,22 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
return {
filters: {
company: frm.doc.company,
'is_company_account': 1
is_company_account: 1,
},
};
});
let no_bank_transactions_text =
`<div class="text-muted text-center">${__("No Matching Bank Transactions Found")}</div>`
let no_bank_transactions_text = `<div class="text-muted text-center">${__(
"No Matching Bank Transactions Found"
)}</div>`;
set_field_options("no_bank_transactions", no_bank_transactions_text);
},
onload: function (frm) {
// Set default filter dates
let today = frappe.datetime.get_today()
let today = frappe.datetime.get_today();
frm.doc.bank_statement_from_date = frappe.datetime.add_months(today, -1);
frm.doc.bank_statement_to_date = today;
frm.trigger('bank_account');
frm.trigger("bank_account");
},
filter_by_reference_date: function (frm) {
@@ -37,34 +38,27 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
refresh: function (frm) {
frm.disable_save();
frappe.require("bank-reconciliation-tool.bundle.js", () =>
frm.trigger("make_reconciliation_tool")
);
frappe.require("bank-reconciliation-tool.bundle.js", () => frm.trigger("make_reconciliation_tool"));
frm.add_custom_button(__("Upload Bank Statement"), () =>
frappe.call({
method:
"erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement",
args: {
dt: frm.doc.doctype,
dn: frm.doc.name,
company: frm.doc.company,
bank_account: frm.doc.bank_account,
},
callback: function (r) {
if (!r.exc) {
var doc = frappe.model.sync(r.message);
frappe.set_route(
"Form",
doc[0].doctype,
doc[0].name
);
}
},
})
frappe.call({
method: "erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement",
args: {
dt: frm.doc.doctype,
dn: frm.doc.name,
company: frm.doc.company,
bank_account: frm.doc.bank_account,
},
callback: function (r) {
if (!r.exc) {
var doc = frappe.model.sync(r.message);
frappe.set_route("Form", doc[0].doctype, doc[0].name);
}
},
})
);
frm.add_custom_button(__('Auto Reconcile'), function() {
frm.add_custom_button(__("Auto Reconcile"), function () {
frappe.call({
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers",
args: {
@@ -75,33 +69,22 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
from_reference_date: frm.doc.from_reference_date,
to_reference_date: frm.doc.to_reference_date,
},
})
});
});
frm.add_custom_button(__('Get Unreconciled Entries'), function() {
frm.add_custom_button(__("Get Unreconciled Entries"), function () {
frm.trigger("make_reconciliation_tool");
});
frm.change_custom_button_type(__('Get Unreconciled Entries'), null, 'primary');
frm.change_custom_button_type(__("Get Unreconciled Entries"), null, "primary");
},
bank_account: function (frm) {
frappe.db.get_value(
"Bank Account",
frm.doc.bank_account,
"account",
(r) => {
frappe.db.get_value(
"Account",
r.account,
"account_currency",
(r) => {
frm.doc.account_currency = r.account_currency;
frm.trigger("render_chart");
}
);
}
);
frappe.db.get_value("Bank Account", frm.doc.bank_account, "account", (r) => {
frappe.db.get_value("Account", r.account, "account_currency", (r) => {
frm.doc.account_currency = r.account_currency;
frm.trigger("render_chart");
});
});
frm.trigger("get_account_opening_balance");
},
@@ -120,11 +103,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
) {
frm.trigger("render_chart");
frm.trigger("render");
frappe.utils.scroll_to(
frm.get_field("reconciliation_tool_cards").$wrapper,
true,
30
);
frappe.utils.scroll_to(frm.get_field("reconciliation_tool_cards").$wrapper, true, 30);
}
});
}
@@ -133,11 +112,10 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
get_account_opening_balance(frm) {
if (frm.doc.bank_account && frm.doc.bank_statement_from_date) {
frappe.call({
method:
"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
args: {
bank_account: frm.doc.bank_account,
till_date: frappe.datetime.add_days(frm.doc.bank_statement_from_date, -1)
till_date: frappe.datetime.add_days(frm.doc.bank_statement_from_date, -1),
},
callback: (response) => {
frm.set_value("account_opening_balance", response.message);
@@ -149,8 +127,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
get_cleared_balance(frm) {
if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
return frappe.call({
method:
"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
args: {
bank_account: frm.doc.bank_account,
till_date: frm.doc.bank_statement_to_date,
@@ -163,41 +140,30 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
},
render_chart(frm) {
frm.cards_manager = new erpnext.accounts.bank_reconciliation.NumberCardManager(
{
$reconciliation_tool_cards: frm.get_field(
"reconciliation_tool_cards"
).$wrapper,
bank_statement_closing_balance:
frm.doc.bank_statement_closing_balance,
cleared_balance: frm.cleared_balance,
currency: frm.doc.account_currency,
}
);
frm.cards_manager = new erpnext.accounts.bank_reconciliation.NumberCardManager({
$reconciliation_tool_cards: frm.get_field("reconciliation_tool_cards").$wrapper,
bank_statement_closing_balance: frm.doc.bank_statement_closing_balance,
cleared_balance: frm.cleared_balance,
currency: frm.doc.account_currency,
});
},
render(frm) {
if (frm.doc.bank_account) {
frm.bank_reconciliation_data_table_manager = new erpnext.accounts.bank_reconciliation.DataTableManager(
{
frm.bank_reconciliation_data_table_manager =
new erpnext.accounts.bank_reconciliation.DataTableManager({
company: frm.doc.company,
bank_account: frm.doc.bank_account,
$reconciliation_tool_dt: frm.get_field(
"reconciliation_tool_dt"
).$wrapper,
$no_bank_transactions: frm.get_field(
"no_bank_transactions"
).$wrapper,
$reconciliation_tool_dt: frm.get_field("reconciliation_tool_dt").$wrapper,
$no_bank_transactions: frm.get_field("no_bank_transactions").$wrapper,
bank_statement_from_date: frm.doc.bank_statement_from_date,
bank_statement_to_date: frm.doc.bank_statement_to_date,
filter_by_reference_date: frm.doc.filter_by_reference_date,
from_reference_date: frm.doc.from_reference_date,
to_reference_date: frm.doc.to_reference_date,
bank_statement_closing_balance:
frm.doc.bank_statement_closing_balance,
bank_statement_closing_balance: frm.doc.bank_statement_closing_balance,
cards_manager: frm.cards_manager,
}
);
});
}
},
});

View File

@@ -17,11 +17,9 @@ frappe.ui.form.on("Bank Statement Import", {
frm.import_in_progress = false;
if (data_import !== frm.doc.name) return;
frappe.model.clear_doc("Bank Statement Import", frm.doc.name);
frappe.model
.with_doc("Bank Statement Import", frm.doc.name)
.then(() => {
frm.refresh();
});
frappe.model.with_doc("Bank Statement Import", frm.doc.name).then(() => {
frm.refresh();
});
});
frappe.realtime.on("data_import_progress", (data) => {
frm.import_in_progress = true;
@@ -48,20 +46,9 @@ frappe.ui.form.on("Bank Statement Import", {
: __("Updating {0} of {1}, {2}", message_args);
}
if (data.skipping) {
message = __(
"Skipping {0} of {1}, {2}",
[
data.current,
data.total,
eta_message,
]
);
message = __("Skipping {0} of {1}, {2}", [data.current, data.total, eta_message]);
}
frm.dashboard.show_progress(
__("Import Progress"),
percent,
message
);
frm.dashboard.show_progress(__("Import Progress"), percent, message);
frm.page.set_indicator(__("In Progress"), "orange");
// hide progress when complete
@@ -103,15 +90,12 @@ frappe.ui.form.on("Bank Statement Import", {
frm.trigger("show_report_error_button");
if (frm.doc.status === "Partial Success") {
frm.add_custom_button(__("Export Errored Rows"), () =>
frm.trigger("export_errored_rows")
);
frm.add_custom_button(__("Export Errored Rows"), () => frm.trigger("export_errored_rows"));
}
if (frm.doc.status.includes("Success")) {
frm.add_custom_button(
__("Go to {0} List", [__(frm.doc.reference_doctype)]),
() => frappe.set_route("List", frm.doc.reference_doctype)
frm.add_custom_button(__("Go to {0} List", [__(frm.doc.reference_doctype)]), () =>
frappe.set_route("List", frm.doc.reference_doctype)
);
}
},
@@ -128,13 +112,8 @@ frappe.ui.form.on("Bank Statement Import", {
frm.disable_save();
if (frm.doc.status !== "Success") {
if (!frm.is_new() && frm.has_import_file()) {
let label =
frm.doc.status === "Pending"
? __("Start Import")
: __("Retry");
frm.page.set_primary_action(label, () =>
frm.events.start_import(frm)
);
let label = frm.doc.status === "Pending" ? __("Start Import") : __("Retry");
frm.page.set_primary_action(label, () => frm.events.start_import(frm));
} else {
frm.page.set_primary_action(__("Save"), () => frm.save());
}
@@ -176,24 +155,24 @@ frappe.ui.form.on("Bank Statement Import", {
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} 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
);
"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} 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
);
"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);
@@ -236,8 +215,7 @@ frappe.ui.form.on("Bank Statement Import", {
},
download_template() {
let method =
"/api/method/frappe.core.doctype.data_import.data_import.download_template";
let method = "/api/method/frappe.core.doctype.data_import.data_import.download_template";
open_url_post(method, {
doctype: "Bank Transaction",
@@ -250,7 +228,7 @@ frappe.ui.form.on("Bank Statement Import", {
"description",
"reference_number",
"bank_account",
"currency"
"currency",
],
},
});
@@ -321,10 +299,7 @@ frappe.ui.form.on("Bank Statement Import", {
show_import_preview(frm, preview_data) {
let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
if (
frm.import_preview &&
frm.import_preview.doctype === frm.doc.reference_doctype
) {
if (frm.import_preview && frm.import_preview.doctype === frm.doc.reference_doctype) {
frm.import_preview.preview_data = preview_data;
frm.import_preview.import_log = import_log;
frm.import_preview.refresh();
@@ -340,19 +315,10 @@ frappe.ui.form.on("Bank Statement Import", {
frm,
events: {
remap_column(changed_map) {
let template_options = JSON.parse(
frm.doc.template_options || "{}"
);
template_options.column_to_field_map =
template_options.column_to_field_map || {};
Object.assign(
template_options.column_to_field_map,
changed_map
);
frm.set_value(
"template_options",
JSON.stringify(template_options)
);
let template_options = JSON.parse(frm.doc.template_options || "{}");
template_options.column_to_field_map = template_options.column_to_field_map || {};
Object.assign(template_options.column_to_field_map, changed_map);
frm.set_value("template_options", JSON.stringify(template_options));
frm.save().then(() => frm.trigger("import_file"));
},
},
@@ -386,8 +352,7 @@ frappe.ui.form.on("Bank Statement Import", {
let other_warnings = [];
for (let warning of warnings) {
if (warning.row) {
warnings_by_row[warning.row] =
warnings_by_row[warning.row] || [];
warnings_by_row[warning.row] = warnings_by_row[warning.row] || [];
warnings_by_row[warning.row].push(warning);
} else {
other_warnings.push(warning);
@@ -402,9 +367,7 @@ frappe.ui.form.on("Bank Statement Import", {
if (w.field) {
let label =
w.field.label +
(w.field.parent !== frm.doc.reference_doctype
? ` (${w.field.parent})`
: "");
(w.field.parent !== frm.doc.reference_doctype ? ` (${w.field.parent})` : "");
return `<li>${label}: ${w.message}</li>`;
}
return `<li>${w.message}</li>`;
@@ -423,10 +386,9 @@ frappe.ui.form.on("Bank Statement Import", {
.map((warning) => {
let header = "";
if (warning.col) {
let column_number = `<span class="text-uppercase">${__(
"Column {0}",
[warning.col]
)}</span>`;
let column_number = `<span class="text-uppercase">${__("Column {0}", [
warning.col,
])}</span>`;
let column_header = columns[warning.col].header_title;
header = `${column_number} (${column_header})`;
}
@@ -465,36 +427,28 @@ frappe.ui.form.on("Bank Statement Import", {
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>`,
]
);
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>`,
]
);
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>`
: "";
let title = m.title ? `<strong>${m.title}</strong>` : "";
let message = m.message ? `<div>${m.message}</div>` : "";
return title + message;
})
.join("");

View File

@@ -80,7 +80,8 @@ class BankStatementImport(DataImport):
from frappe.utils.background_jobs import is_job_enqueued
from frappe.utils.scheduler import is_scheduler_inactive
if is_scheduler_inactive() and not frappe.flags.in_test:
run_now = frappe.flags.in_test or frappe.conf.developer_mode
if is_scheduler_inactive() and not run_now:
frappe.throw(_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive"))
job_id = f"bank_statement_import::{self.name}"
@@ -97,7 +98,7 @@ class BankStatementImport(DataImport):
google_sheets_url=self.google_sheets_url,
bank=self.bank,
template_options=self.template_options,
now=frappe.conf.developer_mode or frappe.flags.in_test,
now=run_now,
)
return True

View File

@@ -1,36 +1,34 @@
let imports_in_progress = [];
frappe.listview_settings['Bank Statement Import'] = {
frappe.listview_settings["Bank Statement Import"] = {
onload(listview) {
frappe.realtime.on('data_import_progress', data => {
frappe.realtime.on("data_import_progress", (data) => {
if (!imports_in_progress.includes(data.data_import)) {
imports_in_progress.push(data.data_import);
}
});
frappe.realtime.on('data_import_refresh', data => {
imports_in_progress = imports_in_progress.filter(
d => d !== data.data_import
);
frappe.realtime.on("data_import_refresh", (data) => {
imports_in_progress = imports_in_progress.filter((d) => d !== data.data_import);
listview.refresh();
});
},
get_indicator: function(doc) {
get_indicator: function (doc) {
var colors = {
'Pending': 'orange',
'Not Started': 'orange',
'Partial Success': 'orange',
'Success': 'green',
'In Progress': 'orange',
'Error': 'red'
Pending: "orange",
"Not Started": "orange",
"Partial Success": "orange",
Success: "green",
"In Progress": "orange",
Error: "red",
};
let status = doc.status;
if (imports_in_progress.includes(doc.name)) {
status = 'In Progress';
status = "In Progress";
}
if (status == 'Pending') {
status = 'Not Started';
if (status == "Pending") {
status = "Not Started";
}
return [__(status), colors[status], 'status,=,' + doc.status];
return [__(status), colors[status], "status,=," + doc.status];
},
hide_name_column: true
hide_name_column: true,
};

View File

@@ -3,7 +3,7 @@
frappe.ui.form.on("Bank Transaction", {
onload(frm) {
frm.set_query("payment_document", "payment_entries", function() {
frm.set_query("payment_document", "payment_entries", function () {
const payment_doctypes = frm.events.get_payment_doctypes(frm);
return {
filters: {
@@ -23,7 +23,7 @@ frappe.ui.form.on("Bank Transaction", {
set_bank_statement_filter(frm);
},
setup: function(frm) {
setup: function (frm) {
frm.set_query("party_type", function () {
return {
filters: {
@@ -33,16 +33,10 @@ frappe.ui.form.on("Bank Transaction", {
});
},
get_payment_doctypes: function() {
get_payment_doctypes: function () {
// get payment doctypes from all the apps
return [
"Payment Entry",
"Journal Entry",
"Sales Invoice",
"Purchase Invoice",
"Bank Transaction",
];
}
return ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Bank Transaction"];
},
});
frappe.ui.form.on("Bank Transaction Payments", {
@@ -54,10 +48,11 @@ frappe.ui.form.on("Bank Transaction Payments", {
const update_clearance_date = (frm, cdt, cdn) => {
if (frm.doc.docstatus === 1) {
frappe
.xcall(
"erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment",
{ doctype: cdt, docname: cdn, bt_name: frm.doc.name }
)
.xcall("erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment", {
doctype: cdt,
docname: cdn,
bt_name: frm.doc.name,
})
.then((e) => {
if (e == "success") {
frappe.show_alert({

View File

@@ -94,10 +94,13 @@ class BankTransaction(Document):
pe.append(reference)
def update_allocated_amount(self):
self.allocated_amount = (
allocated_amount = (
sum(p.allocated_amount for p in self.payment_entries) if self.payment_entries else 0.0
)
self.unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit)) - self.allocated_amount
unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit)) - allocated_amount
self.allocated_amount = flt(allocated_amount, self.precision("allocated_amount"))
self.unallocated_amount = flt(unallocated_amount, self.precision("unallocated_amount"))
def before_submit(self):
self.allocate_payment_entries()

View File

@@ -1,15 +1,15 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.listview_settings['Bank Transaction'] = {
frappe.listview_settings["Bank Transaction"] = {
add_fields: ["unallocated_amount"],
get_indicator: function(doc) {
if(doc.docstatus == 2) {
get_indicator: function (doc) {
if (doc.docstatus == 2) {
return [__("Cancelled"), "red", "docstatus,=,2"];
} else if(flt(doc.unallocated_amount)<=0) {
} else if (flt(doc.unallocated_amount) <= 0) {
return [__("Reconciled"), "green", "unallocated_amount,=,0"];
} else if(flt(doc.unallocated_amount)>0) {
} else if (flt(doc.unallocated_amount) > 0) {
return [__("Unreconciled"), "orange", "unallocated_amount,>,0"];
}
}
},
};

View File

@@ -32,8 +32,16 @@ class TestBankTransaction(FrappeTestCase):
frappe.db.delete(dt)
clear_loan_transactions()
make_pos_profile()
add_transactions()
add_vouchers()
# generate and use a uniq hash identifier for 'Bank Account' and it's linked GL 'Account' to avoid validation error
uniq_identifier = frappe.generate_hash(length=10)
gl_account = create_gl_account("_Test Bank " + uniq_identifier)
bank_account = create_bank_account(
gl_account=gl_account, bank_account_name="Checking Account " + uniq_identifier
)
add_transactions(bank_account=bank_account)
add_vouchers(gl_account=gl_account)
# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction.
def test_linked_payments(self):
@@ -219,7 +227,9 @@ def clear_loan_transactions():
frappe.db.delete("Loan Repayment")
def create_bank_account(bank_name="Citi Bank", account_name="_Test Bank - _TC"):
def create_bank_account(
bank_name="Citi Bank", gl_account="_Test Bank - _TC", bank_account_name="Checking Account"
):
try:
frappe.get_doc(
{
@@ -231,21 +241,35 @@ def create_bank_account(bank_name="Citi Bank", account_name="_Test Bank - _TC"):
pass
try:
frappe.get_doc(
bank_account = frappe.get_doc(
{
"doctype": "Bank Account",
"account_name": "Checking Account",
"account_name": bank_account_name,
"bank": bank_name,
"account": account_name,
"account": gl_account,
}
).insert(ignore_if_duplicate=True)
except frappe.DuplicateEntryError:
pass
return bank_account.name
def add_transactions():
create_bank_account()
def create_gl_account(gl_account_name="_Test Bank - _TC"):
gl_account = frappe.get_doc(
{
"doctype": "Account",
"company": "_Test Company",
"parent_account": "Current Assets - _TC",
"account_type": "Bank",
"is_group": 0,
"account_name": gl_account_name,
}
).insert()
return gl_account.name
def add_transactions(bank_account="_Test Bank - _TC"):
doc = frappe.get_doc(
{
"doctype": "Bank Transaction",
@@ -253,7 +277,7 @@ def add_transactions():
"date": "2018-10-23",
"deposit": 1200,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank",
"bank_account": bank_account,
}
).insert()
doc.submit()
@@ -265,7 +289,7 @@ def add_transactions():
"date": "2018-10-23",
"deposit": 1700,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank",
"bank_account": bank_account,
}
).insert()
doc.submit()
@@ -277,7 +301,7 @@ def add_transactions():
"date": "2018-10-26",
"withdrawal": 690,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank",
"bank_account": bank_account,
}
).insert()
doc.submit()
@@ -289,7 +313,7 @@ def add_transactions():
"date": "2018-10-27",
"deposit": 3900,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank",
"bank_account": bank_account,
}
).insert()
doc.submit()
@@ -301,13 +325,13 @@ def add_transactions():
"date": "2018-10-27",
"withdrawal": 109080,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank",
"bank_account": bank_account,
}
).insert()
doc.submit()
def add_vouchers():
def add_vouchers(gl_account="_Test Bank - _TC"):
try:
frappe.get_doc(
{
@@ -323,7 +347,7 @@ def add_vouchers():
pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account)
pe.reference_no = "Conrad Oct 18"
pe.reference_date = "2018-10-24"
pe.insert()
@@ -342,14 +366,14 @@ def add_vouchers():
pass
pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1200)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account)
pe.reference_no = "Herr G Oct 18"
pe.reference_date = "2018-10-24"
pe.insert()
pe.submit()
pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1700)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account)
pe.reference_no = "Herr G Nov 18"
pe.reference_date = "2018-11-01"
pe.insert()
@@ -380,10 +404,10 @@ def add_vouchers():
pass
pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900, is_paid=1, do_not_save=1)
pi.cash_bank_account = "_Test Bank - _TC"
pi.cash_bank_account = gl_account
pi.insert()
pi.submit()
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account)
pe.reference_no = "Poore Simon's Oct 18"
pe.reference_date = "2018-10-28"
pe.paid_amount = 690
@@ -392,7 +416,7 @@ def add_vouchers():
pe.submit()
si = create_sales_invoice(customer="Poore Simon's", qty=1, rate=3900)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
pe = get_payment_entry("Sales Invoice", si.name, bank_account=gl_account)
pe.reference_no = "Poore Simon's Oct 18"
pe.reference_date = "2018-10-28"
pe.insert()
@@ -415,16 +439,12 @@ def add_vouchers():
if not frappe.db.get_value(
"Mode of Payment Account", {"company": "_Test Company", "parent": "Cash"}
):
mode_of_payment.append(
"accounts", {"company": "_Test Company", "default_account": "_Test Bank - _TC"}
)
mode_of_payment.append("accounts", {"company": "_Test Company", "default_account": gl_account})
mode_of_payment.save()
si = create_sales_invoice(customer="Fayva", qty=1, rate=109080, do_not_save=1)
si.is_pos = 1
si.append(
"payments", {"mode_of_payment": "Cash", "account": "_Test Bank - _TC", "amount": 109080}
)
si.append("payments", {"mode_of_payment": "Cash", "account": gl_account, "amount": 109080})
si.insert()
si.submit()

View File

@@ -6,18 +6,18 @@ frappe.ui.form.on("Bisect Accounting Statements", {
frm.trigger("render_heatmap");
},
refresh(frm) {
frm.add_custom_button(__('Bisect Left'), () => {
frm.add_custom_button(__("Bisect Left"), () => {
frm.trigger("bisect_left");
});
frm.add_custom_button(__('Bisect Right'), () => {
frm.add_custom_button(__("Bisect Right"), () => {
frm.trigger("bisect_right");
});
frm.add_custom_button(__('Up'), () => {
frm.add_custom_button(__("Up"), () => {
frm.trigger("move_up");
});
frm.add_custom_button(__('Build Tree'), () => {
frm.add_custom_button(__("Build Tree"), () => {
frm.trigger("build_tree");
});
},
@@ -26,16 +26,16 @@ frappe.ui.form.on("Bisect Accounting Statements", {
bisect_heatmap.addClass("bisect_heatmap_location");
// milliseconds in a day
let msiad=24*60*60*1000;
let msiad = 24 * 60 * 60 * 1000;
let datapoints = {};
let fr_dt = new Date(frm.doc.from_date).getTime();
let to_dt = new Date(frm.doc.to_date).getTime();
let bisect_start = new Date(frm.doc.current_from_date).getTime();
let bisect_end = new Date(frm.doc.current_to_date).getTime();
for(let x=fr_dt; x <= to_dt; x+=msiad){
let epoch_in_seconds = x/1000;
if ((bisect_start <= x) && (x <= bisect_end )) {
for (let x = fr_dt; x <= to_dt; x += msiad) {
let epoch_in_seconds = x / 1000;
if (bisect_start <= x && x <= bisect_end) {
datapoints[epoch_in_seconds] = 1.0;
} else {
datapoints[epoch_in_seconds] = 0.0;
@@ -49,19 +49,19 @@ frappe.ui.form.on("Bisect Accounting Statements", {
start: new Date(frm.doc.from_date),
end: new Date(frm.doc.to_date),
},
countLabel: 'Bisecting',
countLabel: "Bisecting",
discreteDomains: 1,
});
},
bisect_left(frm) {
frm.call({
doc: frm.doc,
method: 'bisect_left',
method: "bisect_left",
freeze: true,
freeze_message: __("Bisecting Left ..."),
callback: (r) => {
frm.trigger("render_heatmap");
}
},
});
},
bisect_right(frm) {
@@ -69,10 +69,10 @@ frappe.ui.form.on("Bisect Accounting Statements", {
doc: frm.doc,
freeze: true,
freeze_message: __("Bisecting Right ..."),
method: 'bisect_right',
method: "bisect_right",
callback: (r) => {
frm.trigger("render_heatmap");
}
},
});
},
move_up(frm) {
@@ -80,10 +80,10 @@ frappe.ui.form.on("Bisect Accounting Statements", {
doc: frm.doc,
freeze: true,
freeze_message: __("Moving up in tree ..."),
method: 'move_up',
method: "move_up",
callback: (r) => {
frm.trigger("render_heatmap");
}
},
});
},
build_tree(frm) {
@@ -91,10 +91,10 @@ frappe.ui.form.on("Bisect Accounting Statements", {
doc: frm.doc,
freeze: true,
freeze_message: __("Rebuilding BTree for period ..."),
method: 'build_tree',
method: "build_tree",
callback: (r) => {
frm.trigger("render_heatmap");
}
},
});
},
});

View File

@@ -138,10 +138,11 @@ class BisectAccountingStatements(Document):
# set root as current node
root = frappe.db.get_all("Bisect Nodes", filters={"root": ["is", "not set"]})[0]
self.get_report_summary()
self.current_node = root.name
self.current_from_date = self.from_date
self.current_to_date = self.to_date
self.get_report_summary()
self.save()
def get_report_summary(self):

View File

@@ -2,48 +2,48 @@
// For license information, please see license.txt
frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Budget', {
onload: function(frm) {
frm.set_query("account", "accounts", function() {
frappe.ui.form.on("Budget", {
onload: function (frm) {
frm.set_query("account", "accounts", function () {
return {
filters: {
company: frm.doc.company,
report_type: "Profit and Loss",
is_group: 0
}
is_group: 0,
},
};
});
frm.set_query("monthly_distribution", function() {
frm.set_query("monthly_distribution", function () {
return {
filters: {
fiscal_year: frm.doc.fiscal_year
}
fiscal_year: frm.doc.fiscal_year,
},
};
});
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
frm.trigger("toggle_reqd_fields")
refresh: function (frm) {
frm.trigger("toggle_reqd_fields");
},
budget_against: function(frm) {
frm.trigger("set_null_value")
frm.trigger("toggle_reqd_fields")
budget_against: function (frm) {
frm.trigger("set_null_value");
frm.trigger("toggle_reqd_fields");
},
set_null_value: function(frm) {
if(frm.doc.budget_against == 'Cost Center') {
frm.set_value('project', null)
set_null_value: function (frm) {
if (frm.doc.budget_against == "Cost Center") {
frm.set_value("project", null);
} else {
frm.set_value('cost_center', null)
frm.set_value("cost_center", null);
}
},
toggle_reqd_fields: function(frm) {
frm.toggle_reqd("cost_center", frm.doc.budget_against=="Cost Center");
frm.toggle_reqd("project", frm.doc.budget_against=="Project");
}
toggle_reqd_fields: function (frm) {
frm.toggle_reqd("cost_center", frm.doc.budget_against == "Cost Center");
frm.toggle_reqd("project", frm.doc.budget_against == "Project");
},
});

View File

@@ -1,11 +1,10 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on('Cashier Closing', {
setup: function(frm){
frappe.ui.form.on("Cashier Closing", {
setup: function (frm) {
if (frm.doc.user == "" || frm.doc.user == null) {
frm.doc.user = frappe.session.user;
}
}
},
});

View File

@@ -1,4 +1,4 @@
frappe.ui.form.on('Chart of Accounts Importer', {
frappe.ui.form.on("Chart of Accounts Importer", {
onload: function (frm) {
frm.set_value("company", "");
frm.set_value("import_file", "");
@@ -8,31 +8,34 @@ frappe.ui.form.on('Chart of Accounts Importer', {
frm.disable_save();
// make company mandatory
frm.set_df_property('company', 'reqd', frm.doc.company ? 0 : 1);
frm.set_df_property('import_file_section', 'hidden', frm.doc.company ? 0 : 1);
frm.set_df_property("company", "reqd", frm.doc.company ? 0 : 1);
frm.set_df_property("import_file_section", "hidden", frm.doc.company ? 0 : 1);
if (frm.doc.import_file) {
frappe.run_serially([
() => generate_tree_preview(frm),
() => create_import_button(frm),
() => frm.set_df_property('chart_preview', 'hidden', 0)
() => frm.set_df_property("chart_preview", "hidden", 0),
]);
}
frm.set_df_property('chart_preview', 'hidden',
$(frm.fields_dict['chart_tree'].wrapper).html()!="" ? 0 : 1);
frm.set_df_property(
"chart_preview",
"hidden",
$(frm.fields_dict["chart_tree"].wrapper).html() != "" ? 0 : 1
);
},
download_template: function(frm) {
download_template: function (frm) {
var d = new frappe.ui.Dialog({
title: __("Download Template"),
fields: [
{
label : "File Type",
label: "File Type",
fieldname: "file_type",
fieldtype: "Select",
reqd: 1,
options: ["Excel", "CSV"]
options: ["Excel", "CSV"],
},
{
label: "Template Type",
@@ -41,21 +44,27 @@ frappe.ui.form.on('Chart of Accounts Importer', {
reqd: 1,
options: ["Sample Template", "Blank Template"],
change: () => {
let template_type = d.get_value('template_type');
let template_type = d.get_value("template_type");
if (template_type === "Sample Template") {
d.set_df_property('template_type', 'description',
d.set_df_property(
"template_type",
"description",
`The Sample Template contains all the required accounts pre filled in the template.
You can add more accounts or change existing accounts in the template as per your choice.`);
You can add more accounts or change existing accounts in the template as per your choice.`
);
} else {
d.set_df_property('template_type', 'description',
d.set_df_property(
"template_type",
"description",
`The Blank Template contains just the account type and root type required to build the Chart
of Accounts. Please enter the account names and add more rows as per your requirement.`);
of Accounts. Please enter the account names and add more rows as per your requirement.`
);
}
}
},
},
{
label : "Company",
label: "Company",
fieldname: "company",
fieldtype: "Link",
reqd: 1,
@@ -63,25 +72,25 @@ frappe.ui.form.on('Chart of Accounts Importer', {
default: frm.doc.company,
},
],
primary_action: function() {
primary_action: function () {
let data = d.get_values();
if (!data.template_type) {
frappe.throw(__('Please select <b>Template Type</b> to download template'));
frappe.throw(__("Please select <b>Template Type</b> to download template"));
}
open_url_post(
'/api/method/erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.download_template',
"/api/method/erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.download_template",
{
file_type: data.file_type,
template_type: data.template_type,
company: data.company
company: data.company,
}
);
d.hide();
},
primary_action_label: __('Download')
primary_action_label: __("Download"),
});
d.show();
},
@@ -89,7 +98,7 @@ frappe.ui.form.on('Chart of Accounts Importer', {
import_file: function (frm) {
if (!frm.doc.import_file) {
frm.page.set_indicator("");
$(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper on removing file
$(frm.fields_dict["chart_tree"].wrapper).empty(); // empty wrapper on removing file
}
},
@@ -99,89 +108,97 @@ frappe.ui.form.on('Chart of Accounts Importer', {
frappe.call({
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.validate_company",
args: {
company: frm.doc.company
company: frm.doc.company,
},
callback: function(r) {
if(r.message===false) {
callback: function (r) {
if (r.message === false) {
frm.set_value("company", "");
frappe.throw(__("Transactions against the Company already exist! Chart of Accounts can only be imported for a Company with no transactions."));
frappe.throw(
__(
"Transactions against the Company already exist! Chart of Accounts can only be imported for a Company with no transactions."
)
);
} else {
frm.trigger("refresh");
}
}
},
});
}
}
},
});
var create_import_button = function(frm) {
frm.page.set_primary_action(__("Import"), function () {
var create_import_button = function (frm) {
frm.page
.set_primary_action(__("Import"), function () {
return frappe.call({
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.import_coa",
args: {
file_name: frm.doc.import_file,
company: frm.doc.company,
},
freeze: true,
freeze_message: __("Creating Accounts..."),
callback: function (r) {
if (!r.exc) {
clearInterval(frm.page["interval"]);
frm.page.set_indicator(__("Import Successful"), "blue");
create_reset_button(frm);
}
},
});
})
.addClass("btn btn-primary");
};
var create_reset_button = function (frm) {
frm.page
.set_primary_action(__("Reset"), function () {
frm.page.clear_primary_action();
delete frm.page["show_import_button"];
frm.reload_doc();
})
.addClass("btn btn-primary");
};
var validate_coa = function (frm) {
if (frm.doc.import_file) {
let parent = __("All Accounts");
return frappe.call({
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.import_coa",
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa",
args: {
file_name: frm.doc.import_file,
company: frm.doc.company
},
freeze: true,
freeze_message: __("Creating Accounts..."),
callback: function(r) {
if (!r.exc) {
clearInterval(frm.page["interval"]);
frm.page.set_indicator(__('Import Successful'), 'blue');
create_reset_button(frm);
}
}
});
}).addClass('btn btn-primary');
};
var create_reset_button = function(frm) {
frm.page.set_primary_action(__("Reset"), function () {
frm.page.clear_primary_action();
delete frm.page["show_import_button"];
frm.reload_doc();
}).addClass('btn btn-primary');
};
var validate_coa = function(frm) {
if (frm.doc.import_file) {
let parent = __('All Accounts');
return frappe.call({
'method': 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa',
'args': {
file_name: frm.doc.import_file,
parent: parent,
doctype: 'Chart of Accounts Importer',
doctype: "Chart of Accounts Importer",
file_type: frm.doc.file_type,
for_validate: 1
for_validate: 1,
},
callback: function(r) {
if (r.message['show_import_button']) {
frm.page['show_import_button'] = Boolean(r.message['show_import_button']);
callback: function (r) {
if (r.message["show_import_button"]) {
frm.page["show_import_button"] = Boolean(r.message["show_import_button"]);
}
}
},
});
}
};
var generate_tree_preview = function(frm) {
let parent = __('All Accounts');
$(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper to load new data
var generate_tree_preview = function (frm) {
let parent = __("All Accounts");
$(frm.fields_dict["chart_tree"].wrapper).empty(); // empty wrapper to load new data
// generate tree structure based on the csv data
return new frappe.ui.Tree({
parent: $(frm.fields_dict['chart_tree'].wrapper),
parent: $(frm.fields_dict["chart_tree"].wrapper),
label: parent,
expandable: true,
method: 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa',
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa",
args: {
file_name: frm.doc.import_file,
parent: parent,
doctype: 'Chart of Accounts Importer',
file_type: frm.doc.file_type
doctype: "Chart of Accounts Importer",
file_type: frm.doc.file_type,
},
onclick: function(node) {
onclick: function (node) {
parent = node.value;
}
},
});
};

View File

@@ -3,18 +3,20 @@
frappe.provide("erpnext.cheque_print");
frappe.ui.form.on('Cheque Print Template', {
refresh: function(frm) {
if(!frm.doc.__islocal) {
frm.add_custom_button(frm.doc.has_print_format?__("Update Print Format"):__("Create Print Format"),
function() {
frappe.ui.form.on("Cheque Print Template", {
refresh: function (frm) {
if (!frm.doc.__islocal) {
frm.add_custom_button(
frm.doc.has_print_format ? __("Update Print Format") : __("Create Print Format"),
function () {
erpnext.cheque_print.view_cheque_print(frm);
}).addClass("btn-primary");
}
).addClass("btn-primary");
$(frm.fields_dict.cheque_print_preview.wrapper).empty()
$(frm.fields_dict.cheque_print_preview.wrapper).empty();
var template = '<div style="position: relative; overflow-x: scroll;">\
var template =
'<div style="position: relative; overflow-x: scroll;">\
<div id="cheque_preview" style="width: {{ cheque_width }}cm; \
height: {{ cheque_height }}cm;\
background-repeat: no-repeat;\
@@ -48,30 +50,30 @@ frappe.ui.form.on('Cheque Print Template', {
</div>\
</div>';
$(frappe.render(template, frm.doc)).appendTo(frm.fields_dict.cheque_print_preview.wrapper)
$(frappe.render(template, frm.doc)).appendTo(frm.fields_dict.cheque_print_preview.wrapper);
if (frm.doc.scanned_cheque) {
$(frm.fields_dict.cheque_print_preview.wrapper).find("#cheque_preview").css('background-image', 'url(' + frm.doc.scanned_cheque + ')');
$(frm.fields_dict.cheque_print_preview.wrapper)
.find("#cheque_preview")
.css("background-image", "url(" + frm.doc.scanned_cheque + ")");
}
}
}
},
});
erpnext.cheque_print.view_cheque_print = function(frm) {
erpnext.cheque_print.view_cheque_print = function (frm) {
frappe.call({
method: "erpnext.accounts.doctype.cheque_print_template.cheque_print_template.create_or_update_cheque_print_format",
args:{
"template_name": frm.doc.name
args: {
template_name: frm.doc.name,
},
callback: function(r) {
callback: function (r) {
if (!r.exe && !frm.doc.has_print_format) {
var doc = frappe.model.sync(r.message);
frappe.set_route("Form", r.message.doctype, r.message.name);
} else {
frappe.msgprint(__("Print settings updated in respective print format"));
}
else {
frappe.msgprint(__("Print settings updated in respective print format"))
}
}
})
}
},
});
};

View File

@@ -3,75 +3,80 @@
frappe.provide("erpnext.accounts");
frappe.ui.form.on('Cost Center', {
onload: function(frm) {
frm.set_query("parent_cost_center", function() {
frappe.ui.form.on("Cost Center", {
onload: function (frm) {
frm.set_query("parent_cost_center", function () {
return {
filters: {
company: frm.doc.company,
is_group: 1
}
}
is_group: 1,
},
};
});
},
refresh: function(frm) {
refresh: function (frm) {
if (!frm.is_new()) {
frm.add_custom_button(__('Update Cost Center Name / Number'), function () {
frm.add_custom_button(__("Update Cost Center Name / Number"), function () {
frm.trigger("update_cost_center_number");
});
}
let intro_txt = '';
let intro_txt = "";
let doc = frm.doc;
frm.toggle_display('cost_center_name', doc.__islocal);
frm.toggle_enable(['is_group', 'company'], doc.__islocal);
frm.toggle_display("cost_center_name", doc.__islocal);
frm.toggle_enable(["is_group", "company"], doc.__islocal);
if(!doc.__islocal && doc.is_group==1) {
intro_txt += __('Note: This Cost Center is a Group. Cannot make accounting entries against groups.');
if (!doc.__islocal && doc.is_group == 1) {
intro_txt += __(
"Note: This Cost Center is a Group. Cannot make accounting entries against groups."
);
}
frm.events.hide_unhide_group_ledger(frm);
frm.toggle_display('sb1', doc.is_group==0);
frm.toggle_display("sb1", doc.is_group == 0);
frm.set_intro(intro_txt);
if(!frm.doc.__islocal) {
frm.add_custom_button(__('Chart of Cost Centers'),
function() { frappe.set_route("Tree", "Cost Center"); });
if (!frm.doc.__islocal) {
frm.add_custom_button(__("Chart of Cost Centers"), function () {
frappe.set_route("Tree", "Cost Center");
});
frm.add_custom_button(__('Budget'),
function() { frappe.set_route("List", "Budget", {'cost_center': frm.doc.name}); });
frm.add_custom_button(__("Budget"), function () {
frappe.set_route("List", "Budget", { cost_center: frm.doc.name });
});
}
},
update_cost_center_number: function(frm) {
update_cost_center_number: function (frm) {
var d = new frappe.ui.Dialog({
title: __('Update Cost Center Name / Number'),
title: __("Update Cost Center Name / Number"),
fields: [
{
"label": "Cost Center Name",
"fieldname": "cost_center_name",
"fieldtype": "Data",
"reqd": 1,
"default": frm.doc.cost_center_name
label: "Cost Center Name",
fieldname: "cost_center_name",
fieldtype: "Data",
reqd: 1,
default: frm.doc.cost_center_name,
},
{
"label": "Cost Center Number",
"fieldname": "cost_center_number",
"fieldtype": "Data",
"default": frm.doc.cost_center_number
label: "Cost Center Number",
fieldname: "cost_center_number",
fieldtype: "Data",
default: frm.doc.cost_center_number,
},
{
"label": __("Merge with existing"),
"fieldname": "merge",
"fieldtype": "Check",
"default": 0
}
label: __("Merge with existing"),
fieldname: "merge",
fieldtype: "Check",
default: 0,
},
],
primary_action: function() {
primary_action: function () {
let data = d.get_values();
if(data.cost_center_name === frm.doc.cost_center_name && data.cost_center_number === frm.doc.cost_center_number) {
if (
data.cost_center_name === frm.doc.cost_center_name &&
data.cost_center_number === frm.doc.cost_center_number
) {
d.hide();
return;
}
@@ -83,12 +88,12 @@ frappe.ui.form.on('Cost Center', {
cost_center_name: data.cost_center_name,
cost_center_number: cstr(data.cost_center_number),
company: frm.doc.company,
merge: data.merge
merge: data.merge,
},
callback: function(r) {
callback: function (r) {
frappe.dom.unfreeze();
if(!r.exc) {
if(r.message) {
if (!r.exc) {
if (r.message) {
frappe.set_route("Form", "Cost Center", r.message);
} else {
frm.set_value("cost_center_name", data.cost_center_name);
@@ -96,44 +101,42 @@ frappe.ui.form.on('Cost Center', {
}
d.hide();
}
}
},
});
},
primary_action_label: __('Update')
primary_action_label: __("Update"),
});
d.show();
},
parent_cost_center(frm) {
if(!frm.doc.company) {
frappe.msgprint(__('Please enter company name first'));
if (!frm.doc.company) {
frappe.msgprint(__("Please enter company name first"));
}
},
hide_unhide_group_ledger(frm) {
let doc = frm.doc;
if (doc.is_group == 1) {
frm.add_custom_button(__('Convert to Non-Group'),
() => frm.events.convert_to_ledger(frm));
frm.add_custom_button(__("Convert to Non-Group"), () => frm.events.convert_to_ledger(frm));
} else if (doc.is_group == 0) {
frm.add_custom_button(__('Convert to Group'),
() => frm.events.convert_to_group(frm));
frm.add_custom_button(__("Convert to Group"), () => frm.events.convert_to_group(frm));
}
},
convert_to_group(frm) {
frm.call('convert_ledger_to_group').then(r => {
if(r.message === 1) {
frm.call("convert_ledger_to_group").then((r) => {
if (r.message === 1) {
frm.refresh();
}
});
},
convert_to_ledger(frm) {
frm.call('convert_group_to_ledger').then(r => {
if(r.message === 1) {
frm.call("convert_group_to_ledger").then((r) => {
if (r.message === 1) {
frm.refresh();
}
});
}
},
});

View File

@@ -41,7 +41,7 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Cost Center Number",
"read_only": 1
"read_only_depends_on": "eval:!doc.__islocal"
},
{
"fieldname": "parent_cost_center",
@@ -170,4 +170,4 @@
"sort_field": "modified",
"sort_order": "ASC",
"states": []
}
}

View File

@@ -1,54 +1,84 @@
frappe.treeview_settings["Cost Center"] = {
breadcrumb: "Accounts",
get_tree_root: false,
filters: [{
fieldname: "company",
fieldtype:"Select",
options: erpnext.utils.get_tree_options("company"),
label: __("Company"),
default: erpnext.utils.get_tree_default("company")
}],
root_label: "Cost Centers",
get_tree_nodes: 'erpnext.accounts.utils.get_children',
add_tree_node: 'erpnext.accounts.utils.add_cc',
menu_items:[
filters: [
{
label: __('New Company'),
action: function() { frappe.new_doc("Company", true) },
condition: 'frappe.boot.user.can_create.indexOf("Company") !== -1'
}
fieldname: "company",
fieldtype: "Select",
options: erpnext.utils.get_tree_options("company"),
label: __("Company"),
default: erpnext.utils.get_tree_default("company"),
},
],
fields:[
{fieldtype:'Data', fieldname:'cost_center_name', label:__('New Cost Center Name'), reqd:true},
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
description:__('Further cost centers can be made under Groups but entries can be made against non-Groups')},
{fieldtype:'Data', fieldname:'cost_center_number', label:__('Cost Center Number'),
description: __("Number of new Cost Center, it will be included in the cost center name as a prefix")}
root_label: "Cost Centers",
get_tree_nodes: "erpnext.accounts.utils.get_children",
add_tree_node: "erpnext.accounts.utils.add_cc",
menu_items: [
{
label: __("New Company"),
action: function () {
frappe.new_doc("Company", true);
},
condition: 'frappe.boot.user.can_create.indexOf("Company") !== -1',
},
],
ignore_fields:["parent_cost_center"],
onload: function(treeview) {
fields: [
{ fieldtype: "Data", fieldname: "cost_center_name", label: __("New Cost Center Name"), reqd: true },
{
fieldtype: "Check",
fieldname: "is_group",
label: __("Is Group"),
description: __(
"Further cost centers can be made under Groups but entries can be made against non-Groups"
),
},
{
fieldtype: "Data",
fieldname: "cost_center_number",
label: __("Cost Center Number"),
description: __(
"Number of new Cost Center, it will be included in the cost center name as a prefix"
),
},
],
ignore_fields: ["parent_cost_center"],
onload: function (treeview) {
function get_company() {
return treeview.page.fields_dict.company.get_value();
}
// tools
treeview.page.add_inner_button(__("Chart of Accounts"), function() {
frappe.set_route('Tree', 'Account', {company: get_company()});
}, __('View'));
treeview.page.add_inner_button(
__("Chart of Accounts"),
function () {
frappe.set_route("Tree", "Account", { company: get_company() });
},
__("View")
);
// make
treeview.page.add_inner_button(__("Budget List"), function() {
frappe.set_route('List', 'Budget', {company: get_company()});
}, __('Budget'));
treeview.page.add_inner_button(
__("Budget List"),
function () {
frappe.set_route("List", "Budget", { company: get_company() });
},
__("Budget")
);
treeview.page.add_inner_button(__("Monthly Distribution"), function() {
frappe.set_route('List', 'Monthly Distribution', {company: get_company()});
}, __('Budget'));
treeview.page.add_inner_button(
__("Monthly Distribution"),
function () {
frappe.set_route("List", "Monthly Distribution", { company: get_company() });
},
__("Budget")
);
treeview.page.add_inner_button(__("Budget Variance Report"), function() {
frappe.set_route('query-report', 'Budget Variance Report', {company: get_company()});
}, __('Budget'));
}
}
treeview.page.add_inner_button(
__("Budget Variance Report"),
function () {
frappe.set_route("query-report", "Budget Variance Report", { company: get_company() });
},
__("Budget")
);
},
};

View File

@@ -1,19 +1,24 @@
// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Cost Center Allocation', {
setup: function(frm) {
let filters = {"is_group": 0};
if (frm.doc.company) {
$.extend(filters, {
"company": frm.doc.company
});
}
frm.set_query('main_cost_center', function() {
frappe.ui.form.on("Cost Center Allocation", {
setup: function (frm) {
frm.set_query("main_cost_center", function () {
return {
filters: filters
filters: {
company: frm.doc.company,
is_group: 0,
},
};
});
}
frm.set_query("cost_center", "allocation_percentages", function () {
return {
filters: {
company: frm.doc.company,
is_group: 0,
},
};
});
},
});

View File

@@ -1,44 +1,41 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Coupon Code', {
setup: function(frm) {
frm.set_query("pricing_rule", function() {
frappe.ui.form.on("Coupon Code", {
setup: function (frm) {
frm.set_query("pricing_rule", function () {
return {
filters: [
["Pricing Rule","coupon_code_based", "=", "1"]
]
filters: [["Pricing Rule", "coupon_code_based", "=", "1"]],
};
});
},
coupon_name:function(frm){
if (frm.doc.__islocal===1) {
coupon_name: function (frm) {
if (frm.doc.__islocal === 1) {
frm.trigger("make_coupon_code");
}
},
coupon_type:function(frm){
if (frm.doc.__islocal===1) {
coupon_type: function (frm) {
if (frm.doc.__islocal === 1) {
frm.trigger("make_coupon_code");
}
},
make_coupon_code: function(frm) {
var coupon_name=frm.doc.coupon_name;
make_coupon_code: function (frm) {
var coupon_name = frm.doc.coupon_name;
var coupon_code;
if (frm.doc.coupon_type=='Gift Card') {
coupon_code=Math.random().toString(12).substring(2, 12).toUpperCase();
if (frm.doc.coupon_type == "Gift Card") {
coupon_code = Math.random().toString(12).substring(2, 12).toUpperCase();
} else if (frm.doc.coupon_type == "Promotional") {
coupon_name = coupon_name.replace(/\s/g, "");
coupon_code = coupon_name.toUpperCase().slice(0, 8);
}
else if(frm.doc.coupon_type=='Promotional'){
coupon_name=coupon_name.replace(/\s/g,'');
coupon_code=coupon_name.toUpperCase().slice(0,8);
}
frm.doc.coupon_code=coupon_code;
frm.refresh_field('coupon_code');
frm.doc.coupon_code = coupon_code;
frm.refresh_field("coupon_code");
},
refresh: function(frm) {
refresh: function (frm) {
if (frm.doc.pricing_rule) {
frm.add_custom_button(__("Add/Edit Coupon Conditions"), function(){
frm.add_custom_button(__("Add/Edit Coupon Conditions"), function () {
frappe.set_route("Form", "Pricing Rule", frm.doc.pricing_rule);
});
}
}
},
});

View File

@@ -1,28 +1,27 @@
// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Currency Exchange Settings', {
service_provider: function(frm) {
frappe.ui.form.on("Currency Exchange Settings", {
service_provider: function (frm) {
if (frm.doc.service_provider == "exchangerate.host") {
let result = ['result'];
let result = ["result"];
let params = {
date: '{transaction_date}',
from: '{from_currency}',
to: '{to_currency}'
date: "{transaction_date}",
from: "{from_currency}",
to: "{to_currency}",
};
add_param(frm, "https://api.exchangerate.host/convert", params, result);
} else if (frm.doc.service_provider == "frankfurter.app") {
let result = ['rates', '{to_currency}'];
let result = ["rates", "{to_currency}"];
let params = {
base: '{from_currency}',
symbols: '{to_currency}'
base: "{from_currency}",
symbols: "{to_currency}",
};
add_param(frm, "https://frankfurter.app/{transaction_date}", params, result);
}
}
},
});
function add_param(frm, api, params, result) {
var row;
frm.clear_table("req_params");
@@ -30,13 +29,13 @@ function add_param(frm, api, params, result) {
frm.doc.api_endpoint = api;
$.each(params, function(key, value) {
$.each(params, function (key, value) {
row = frm.add_child("req_params");
row.key = key;
row.value = value;
});
$.each(result, function(key, value) {
$.each(result, function (key, value) {
row = frm.add_child("result_key");
row.key = value;
});

View File

@@ -10,7 +10,7 @@ frappe.ui.form.on("Dunning", {
company: frm.doc.company,
customer: frm.doc.customer,
outstanding_amount: [">", 0],
status: "Overdue"
status: "Overdue",
},
};
});
@@ -19,16 +19,16 @@ frappe.ui.form.on("Dunning", {
filters: {
company: frm.doc.company,
root_type: "Income",
is_group: 0
}
is_group: 0,
},
};
});
frm.set_query("cost_center", () => {
return {
filters: {
company: frm.doc.company,
is_group: 0
}
is_group: 0,
},
};
});
@@ -51,7 +51,8 @@ frappe.ui.form.on("Dunning", {
__("Payment"),
function () {
frm.events.make_payment_entry(frm);
}, __("Create")
},
__("Create")
);
frm.page.set_inner_btn_group_as_primary(__("Create"));
}
@@ -69,7 +70,7 @@ frappe.ui.form.on("Dunning", {
get_query_filters: {
docstatus: 1,
status: "Overdue",
company: frm.doc.company
company: frm.doc.company,
},
allow_child_item_selection: true,
child_fieldname: "payment_schedule",
@@ -78,9 +79,12 @@ frappe.ui.form.on("Dunning", {
});
}
frappe.dynamic_link = { doc: frm.doc, fieldname: 'customer', doctype: 'Customer' };
frappe.dynamic_link = { doc: frm.doc, fieldname: "customer", doctype: "Customer" };
frm.toggle_display("customer_name", (frm.doc.customer_name && frm.doc.customer_name !== frm.doc.customer));
frm.toggle_display(
"customer_name",
frm.doc.customer_name && frm.doc.customer_name !== frm.doc.customer
);
},
// When multiple companies are set up. in case company name is changed set default company address
company: function (frm) {
@@ -90,8 +94,8 @@ frappe.ui.form.on("Dunning", {
args: { name: frm.doc.company, existing_address: frm.doc.company_address || "" },
debounce: 2000,
callback: function (r) {
frm.set_value("company_address", r && r.message || "");
}
frm.set_value("company_address", (r && r.message) || "");
},
});
if (frm.fields_dict.currency) {
@@ -125,16 +129,16 @@ frappe.ui.form.on("Dunning", {
transaction_date: frm.doc.posting_date,
from_currency: frm.doc.currency,
to_currency: company_currency,
args: "for_selling"
args: "for_selling",
},
freeze: true,
freeze_message: __("Fetching exchange rates ..."),
callback: function(r) {
callback: function (r) {
const exchange_rate = flt(r.message);
if (exchange_rate != frm.doc.conversion_rate) {
frm.set_value("conversion_rate", exchange_rate);
}
}
},
});
} else {
frm.trigger("conversion_rate");
@@ -166,8 +170,7 @@ frappe.ui.form.on("Dunning", {
get_dunning_letter_text: function (frm) {
if (frm.doc.dunning_type) {
frappe.call({
method:
"erpnext.accounts.doctype.dunning.dunning.get_dunning_letter_text",
method: "erpnext.accounts.doctype.dunning.dunning.get_dunning_letter_text",
args: {
dunning_type: frm.doc.dunning_type,
language: frm.doc.language,
@@ -204,10 +207,7 @@ frappe.ui.form.on("Dunning", {
calculate_overdue_days: function (frm) {
frm.doc.overdue_payments.forEach((row) => {
if (frm.doc.posting_date && row.due_date) {
const overdue_days = moment(frm.doc.posting_date).diff(
row.due_date,
"days"
);
const overdue_days = moment(frm.doc.posting_date).diff(row.due_date, "days");
frappe.model.set_value(row.doctype, row.name, "overdue_days", overdue_days);
}
});
@@ -215,15 +215,16 @@ frappe.ui.form.on("Dunning", {
calculate_interest: function (frm) {
frm.doc.overdue_payments.forEach((row) => {
const interest_per_day = frm.doc.rate_of_interest / 100 / 365;
const interest = flt((interest_per_day * row.overdue_days * row.outstanding), precision("interest", row));
const interest = flt(
interest_per_day * row.overdue_days * row.outstanding,
precision("interest", row)
);
frappe.model.set_value(row.doctype, row.name, "interest", interest);
});
},
calculate_totals: function (frm) {
const total_interest = frm.doc.overdue_payments
.reduce((prev, cur) => prev + cur.interest, 0);
const total_outstanding = frm.doc.overdue_payments
.reduce((prev, cur) => prev + cur.outstanding, 0);
const total_interest = frm.doc.overdue_payments.reduce((prev, cur) => prev + cur.interest, 0);
const total_outstanding = frm.doc.overdue_payments.reduce((prev, cur) => prev + cur.outstanding, 0);
const dunning_amount = total_interest + frm.doc.dunning_fee;
const base_dunning_amount = dunning_amount * frm.doc.conversion_rate;
const grand_total = total_outstanding + dunning_amount;
@@ -240,8 +241,7 @@ frappe.ui.form.on("Dunning", {
},
make_payment_entry: function (frm) {
return frappe.call({
method:
"erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry",
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry",
args: {
dt: frm.doc.doctype,
dn: frm.doc.name,
@@ -257,5 +257,5 @@ frappe.ui.form.on("Dunning", {
frappe.ui.form.on("Overdue Payment", {
interest: function (frm) {
frm.trigger("calculate_totals");
}
});
},
});

View File

@@ -85,7 +85,14 @@ class Dunning(AccountsController):
frappe.throw(
_(
"The currency of invoice {} ({}) is different from the currency of this dunning ({})."
).format(row.sales_invoice, invoice_currency, self.currency)
).format(
frappe.get_desk_link(
"Sales Invoice",
row.sales_invoice,
),
invoice_currency,
self.currency,
)
)
def validate_overdue_payments(self):

View File

@@ -1,75 +1,79 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Exchange Rate Revaluation', {
setup: function(frm) {
frm.set_query("party_type", "accounts", function() {
frappe.ui.form.on("Exchange Rate Revaluation", {
setup: function (frm) {
frm.set_query("party_type", "accounts", function () {
return {
"filters": {
"name": ["in", Object.keys(frappe.boot.party_account_types)],
}
filters: {
name: ["in", Object.keys(frappe.boot.party_account_types)],
},
};
});
frm.set_query("account", "accounts", function(doc) {
frm.set_query("account", "accounts", function (doc) {
return {
"filters": {
"company": doc.company
}
filters: {
company: doc.company,
},
};
});
},
refresh: function(frm) {
if(frm.doc.docstatus==1) {
refresh: function (frm) {
if (frm.doc.docstatus == 1) {
frappe.call({
method: 'check_journal_entry_condition',
method: "check_journal_entry_condition",
doc: frm.doc,
callback: function(r) {
callback: function (r) {
if (r.message) {
frm.add_custom_button(__('Journal Entries'), function() {
return frm.events.make_jv(frm);
}, __('Create'));
frm.add_custom_button(
__("Journal Entries"),
function () {
return frm.events.make_jv(frm);
},
__("Create")
);
}
}
},
});
}
},
validate_rounding_loss: function(frm) {
validate_rounding_loss: function (frm) {
let allowance = frm.doc.rounding_loss_allowance;
if (!(allowance >= 0 && allowance < 1)) {
frappe.throw(__("Rounding Loss Allowance should be between 0 and 1"));
}
},
rounding_loss_allowance: function(frm) {
rounding_loss_allowance: function (frm) {
frm.events.validate_rounding_loss(frm);
},
validate: function(frm) {
validate: function (frm) {
frm.events.validate_rounding_loss(frm);
},
get_entries: function(frm, account) {
get_entries: function (frm, account) {
frappe.call({
method: "get_accounts_data",
doc: cur_frm.doc,
account: account,
callback: function(r){
callback: function (r) {
frappe.model.clear_table(frm.doc, "accounts");
if(r.message) {
if (r.message) {
r.message.forEach((d) => {
cur_frm.add_child("accounts",d);
cur_frm.add_child("accounts", d);
});
frm.events.get_total_gain_loss(frm);
refresh_field("accounts");
}
}
},
});
},
get_total_gain_loss: function(frm) {
if(!(frm.doc.accounts && frm.doc.accounts.length)) return;
get_total_gain_loss: function (frm) {
if (!(frm.doc.accounts && frm.doc.accounts.length)) return;
let total_gain_loss = 0;
frm.doc.accounts.forEach((d) => {
@@ -80,7 +84,7 @@ frappe.ui.form.on('Exchange Rate Revaluation', {
frm.refresh_fields();
},
make_jv : function(frm) {
make_jv: function (frm) {
let revaluation_journal = null;
let zero_balance_journal = null;
frappe.call({
@@ -88,66 +92,68 @@ frappe.ui.form.on('Exchange Rate Revaluation', {
doc: frm.doc,
freeze: true,
freeze_message: "Making Journal Entries...",
callback: function(r){
callback: function (r) {
if (r.message) {
let response = r.message;
if(response['revaluation_jv'] || response['zero_balance_jv']) {
if (response["revaluation_jv"] || response["zero_balance_jv"]) {
frappe.msgprint(__("Journals have been created"));
}
}
}
},
});
}
},
});
frappe.ui.form.on("Exchange Rate Revaluation Account", {
new_exchange_rate: function(frm, cdt, cdn) {
new_exchange_rate: function (frm, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
row.new_balance_in_base_currency = flt(row.new_exchange_rate * flt(row.balance_in_account_currency),
precision("new_balance_in_base_currency", row));
row.new_balance_in_base_currency = flt(
row.new_exchange_rate * flt(row.balance_in_account_currency),
precision("new_balance_in_base_currency", row)
);
row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency);
refresh_field("accounts");
frm.events.get_total_gain_loss(frm);
},
account: function(frm, cdt, cdn) {
account: function (frm, cdt, cdn) {
var row = locals[cdt][cdn];
if (row.account) {
get_account_details(frm, cdt, cdn);
}
},
party: function(frm, cdt, cdn) {
party: function (frm, cdt, cdn) {
var row = locals[cdt][cdn];
if (row.party && row.account) {
get_account_details(frm, cdt, cdn);
}
},
accounts_remove: function(frm) {
accounts_remove: function (frm) {
frm.events.get_total_gain_loss(frm);
}
},
});
var get_account_details = function(frm, cdt, cdn) {
var get_account_details = function (frm, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
if(!frm.doc.company || !frm.doc.posting_date) {
if (!frm.doc.company || !frm.doc.posting_date) {
frappe.throw(__("Please select Company and Posting Date to getting entries"));
}
frappe.call({
method: "erpnext.accounts.doctype.exchange_rate_revaluation.exchange_rate_revaluation.get_account_details",
args:{
args: {
account: row.account,
company: frm.doc.company,
posting_date: frm.doc.posting_date,
party_type: row.party_type,
party: row.party,
rounding_loss_allowance: frm.doc.rounding_loss_allowance
rounding_loss_allowance: frm.doc.rounding_loss_allowance,
},
callback: function(r){
callback: function (r) {
$.extend(row, r.message);
refresh_field("accounts");
frm.events.get_total_gain_loss(frm);
}
},
});
};

View File

@@ -1,8 +1,6 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Finance Book', {
refresh: function(frm) {
}
frappe.ui.form.on("Finance Book", {
refresh: function (frm) {},
});

View File

@@ -1,17 +1,21 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on('Fiscal Year', {
onload: function(frm) {
if(frm.doc.__islocal) {
frm.set_value("year_start_date",
frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1));
frappe.ui.form.on("Fiscal Year", {
onload: function (frm) {
if (frm.doc.__islocal) {
frm.set_value(
"year_start_date",
frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1)
);
}
},
year_start_date: function(frm) {
year_start_date: function (frm) {
if (!frm.doc.is_short_year) {
let year_end_date =
frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1);
let year_end_date = frappe.datetime.add_days(
frappe.datetime.add_months(frm.doc.year_start_date, 12),
-1
);
frm.set_value("year_end_date", year_end_date);
}
},

View File

@@ -3,7 +3,7 @@
"allow_import": 1,
"autoname": "field:year",
"creation": "2013-01-22 16:50:25",
"description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
"description": "Represents a Financial Year. All accounting entries and other major transactions are tracked against the Fiscal Year.",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
@@ -82,11 +82,12 @@
"icon": "fa fa-calendar",
"idx": 1,
"links": [],
"modified": "2024-01-17 13:06:01.608953",
"modified": "2024-01-30 12:35:38.645968",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Fiscal Year",
"owner": "Administrator",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
@@ -130,5 +131,6 @@
],
"show_name_in_global_search": 1,
"sort_field": "name",
"sort_order": "DESC"
"sort_order": "DESC",
"states": []
}

View File

@@ -1,8 +1,8 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('GL Entry', {
refresh: function(frm) {
frm.page.btn_secondary.hide()
}
frappe.ui.form.on("GL Entry", {
refresh: function (frm) {
frm.page.btn_secondary.hide();
},
});

View File

@@ -13,16 +13,9 @@ import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_checks_for_pl_and_bs_accounts,
)
from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import (
get_dimension_filter_map,
)
from erpnext.accounts.party import validate_party_frozen_disabled, validate_party_gle_currency
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
from erpnext.exceptions import (
InvalidAccountCurrency,
InvalidAccountDimensionError,
MandatoryAccountDimensionError,
)
from erpnext.exceptions import InvalidAccountCurrency
exclude_from_linked_with = True
@@ -98,7 +91,6 @@ class GLEntry(Document):
if not self.flags.from_repost and self.voucher_type != "Period Closing Voucher":
self.validate_account_details(adv_adj)
self.validate_dimensions_for_pl_and_bs()
self.validate_allowed_dimensions()
validate_balance_type(self.account, adv_adj)
validate_frozen_account(self.account, adv_adj)
@@ -208,42 +200,6 @@ class GLEntry(Document):
)
)
def validate_allowed_dimensions(self):
dimension_filter_map = get_dimension_filter_map()
for key, value in dimension_filter_map.items():
dimension = key[0]
account = key[1]
if self.account == account:
if value["is_mandatory"] and not self.get(dimension):
frappe.throw(
_("{0} is mandatory for account {1}").format(
frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)
),
MandatoryAccountDimensionError,
)
if value["allow_or_restrict"] == "Allow":
if self.get(dimension) and self.get(dimension) not in value["allowed_dimensions"]:
frappe.throw(
_("Invalid value {0} for {1} against account {2}").format(
frappe.bold(self.get(dimension)),
frappe.bold(frappe.unscrub(dimension)),
frappe.bold(self.account),
),
InvalidAccountDimensionError,
)
else:
if self.get(dimension) and self.get(dimension) in value["allowed_dimensions"]:
frappe.throw(
_("Invalid value {0} for {1} against account {2}").format(
frappe.bold(self.get(dimension)),
frappe.bold(frappe.unscrub(dimension)),
frappe.bold(self.account),
),
InvalidAccountDimensionError,
)
def check_pl_account(self):
if (
self.is_opening == "Yes"

View File

@@ -1,47 +1,49 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Invoice Discounting', {
frappe.ui.form.on("Invoice Discounting", {
setup: (frm) => {
frm.set_query("sales_invoice", "invoices", (doc) => {
return {
"filters": {
"docstatus": 1,
"company": doc.company,
"outstanding_amount": [">", 0]
filters: {
docstatus: 1,
company: doc.company,
outstanding_amount: [">", 0],
},
};
});
frm.events.filter_accounts("bank_account", frm, [["account_type", "=", "Bank"]]);
frm.events.filter_accounts("bank_charges_account", frm, [["root_type", "=", "Expense"]]);
frm.events.filter_accounts("short_term_loan", frm, [["root_type", "=", "Liability"]]);
frm.events.filter_accounts("accounts_receivable_discounted", frm, [["account_type", "=", "Receivable"]]);
frm.events.filter_accounts("accounts_receivable_discounted", frm, [
["account_type", "=", "Receivable"],
]);
frm.events.filter_accounts("accounts_receivable_credit", frm, [["account_type", "=", "Receivable"]]);
frm.events.filter_accounts("accounts_receivable_unpaid", frm, [["account_type", "=", "Receivable"]]);
},
filter_accounts: (fieldname, frm, addl_filters) => {
let filters = [
["company", "=", frm.doc.company],
["is_group", "=", 0]
["is_group", "=", 0],
];
if(addl_filters){
filters = $.merge(filters , addl_filters);
if (addl_filters) {
filters = $.merge(filters, addl_filters);
}
frm.set_query(fieldname, () => { return { "filters": filters }; });
frm.set_query(fieldname, () => {
return { filters: filters };
});
},
refresh_filters: (frm) =>{
let invoice_accounts = Object.keys(frm.doc.invoices).map(function(key) {
refresh_filters: (frm) => {
let invoice_accounts = Object.keys(frm.doc.invoices).map(function (key) {
return frm.doc.invoices[key].debit_to;
});
let filters = [
["account_type", "=", "Receivable"],
["name", "not in", invoice_accounts]
["name", "not in", invoice_accounts],
];
frm.events.filter_accounts("accounts_receivable_credit", frm, filters);
frm.events.filter_accounts("accounts_receivable_discounted", frm, filters);
@@ -52,19 +54,19 @@ frappe.ui.form.on('Invoice Discounting', {
frm.events.show_general_ledger(frm);
if (frm.doc.docstatus === 0) {
frm.add_custom_button(__('Get Invoices'), function() {
frm.add_custom_button(__("Get Invoices"), function () {
frm.events.get_invoices(frm);
});
}
if (frm.doc.docstatus === 1 && frm.doc.status !== "Settled") {
if (frm.doc.status == "Sanctioned") {
frm.add_custom_button(__('Disburse Loan'), function() {
frm.add_custom_button(__("Disburse Loan"), function () {
frm.events.create_disbursement_entry(frm);
}).addClass("btn-primary");
}
if (frm.doc.status == "Disbursed") {
frm.add_custom_button(__('Close Loan'), function() {
frm.add_custom_button(__("Close Loan"), function () {
frm.events.close_loan(frm);
}).addClass("btn-primary");
}
@@ -92,119 +94,121 @@ frappe.ui.form.on('Invoice Discounting', {
calculate_total_amount: (frm) => {
let total_amount = 0.0;
for (let row of (frm.doc.invoices || [])) {
for (let row of frm.doc.invoices || []) {
total_amount += flt(row.outstanding_amount);
}
frm.set_value("total_amount", total_amount);
},
get_invoices: (frm) => {
var d = new frappe.ui.Dialog({
title: __('Get Invoices based on Filters'),
title: __("Get Invoices based on Filters"),
fields: [
{
"label": "Customer",
"fieldname": "customer",
"fieldtype": "Link",
"options": "Customer"
label: "Customer",
fieldname: "customer",
fieldtype: "Link",
options: "Customer",
},
{
"label": "From Date",
"fieldname": "from_date",
"fieldtype": "Date"
label: "From Date",
fieldname: "from_date",
fieldtype: "Date",
},
{
"label": "To Date",
"fieldname": "to_date",
"fieldtype": "Date"
label: "To Date",
fieldname: "to_date",
fieldtype: "Date",
},
{
"fieldname": "col_break",
"fieldtype": "Column Break",
fieldname: "col_break",
fieldtype: "Column Break",
},
{
"label": "Min Amount",
"fieldname": "min_amount",
"fieldtype": "Currency"
label: "Min Amount",
fieldname: "min_amount",
fieldtype: "Currency",
},
{
"label": "Max Amount",
"fieldname": "max_amount",
"fieldtype": "Currency"
}
label: "Max Amount",
fieldname: "max_amount",
fieldtype: "Currency",
},
],
primary_action: function() {
primary_action: function () {
var data = d.get_values();
frappe.call({
method: "erpnext.accounts.doctype.invoice_discounting.invoice_discounting.get_invoices",
args: {
filters: data
filters: data,
},
callback: function(r) {
if(!r.exc) {
callback: function (r) {
if (!r.exc) {
d.hide();
$.each(r.message, function(i, v) {
frm.doc.invoices = frm.doc.invoices.filter(row => row.sales_invoice);
$.each(r.message, function (i, v) {
frm.doc.invoices = frm.doc.invoices.filter((row) => row.sales_invoice);
let row = frm.add_child("invoices");
$.extend(row, v);
frm.events.refresh_filters(frm);
});
refresh_field("invoices");
}
}
},
});
},
primary_action_label: __('Get Invoices')
primary_action_label: __("Get Invoices"),
});
d.show();
},
create_disbursement_entry: (frm) => {
frappe.call({
method:"create_disbursement_entry",
method: "create_disbursement_entry",
doc: frm.doc,
callback: function(r) {
if(!r.exc){
callback: function (r) {
if (!r.exc) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
}
},
});
},
close_loan: (frm) => {
frappe.call({
method:"close_loan",
method: "close_loan",
doc: frm.doc,
callback: function(r) {
if(!r.exc){
callback: function (r) {
if (!r.exc) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
}
},
});
},
show_general_ledger: (frm) => {
if(frm.doc.docstatus > 0) {
cur_frm.add_custom_button(__('Accounting Ledger'), function() {
frappe.route_options = {
voucher_no: frm.doc.name,
from_date: frm.doc.posting_date,
to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
company: frm.doc.company,
group_by: "Group by Voucher (Consolidated)",
show_cancelled_entries: frm.doc.docstatus === 2
};
frappe.set_route("query-report", "General Ledger");
}, __("View"));
if (frm.doc.docstatus > 0) {
cur_frm.add_custom_button(
__("Accounting Ledger"),
function () {
frappe.route_options = {
voucher_no: frm.doc.name,
from_date: frm.doc.posting_date,
to_date: moment(frm.doc.modified).format("YYYY-MM-DD"),
company: frm.doc.company,
group_by: "Group by Voucher (Consolidated)",
show_cancelled_entries: frm.doc.docstatus === 2,
};
frappe.set_route("query-report", "General Ledger");
},
__("View")
);
}
}
},
});
frappe.ui.form.on('Discounted Invoice', {
frappe.ui.form.on("Discounted Invoice", {
sales_invoice: (frm) => {
frm.events.calculate_total_amount(frm);
frm.events.refresh_filters(frm);
@@ -212,5 +216,5 @@ frappe.ui.form.on('Discounted Invoice', {
invoices_remove: (frm) => {
frm.events.calculate_total_amount(frm);
frm.events.refresh_filters(frm);
}
},
});

View File

@@ -1,21 +1,16 @@
frappe.listview_settings['Invoice Discounting'] = {
frappe.listview_settings["Invoice Discounting"] = {
add_fields: ["status"],
get_indicator: function(doc)
{
if(doc.status == "Draft") {
get_indicator: function (doc) {
if (doc.status == "Draft") {
return [__("Draft"), "red", "status,=,Draft"];
}
else if(doc.status == "Sanctioned") {
} else if (doc.status == "Sanctioned") {
return [__("Sanctioned"), "green", "status,=,Sanctioned"];
}
else if(doc.status == "Disbursed") {
} else if (doc.status == "Disbursed") {
return [__("Disbursed"), "blue", "status,=,Disbursed"];
}
else if(doc.status == "Settled") {
} else if (doc.status == "Settled") {
return [__("Settled"), "orange", "status,=,Settled"];
}
else if(doc.status == "Canceled") {
} else if (doc.status == "Canceled") {
return [__("Canceled"), "red", "status,=,Canceled"];
}
}
},
};

View File

@@ -1,27 +1,49 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Item Tax Template', {
setup: function(frm) {
frm.set_query("tax_type", "taxes", function(doc) {
frappe.ui.form.on("Item Tax Template", {
setup: function (frm) {
frm.set_query("tax_type", "taxes", function (doc) {
return {
filters: [
['Account', 'company', '=', frm.doc.company],
['Account', 'is_group', '=', 0],
['Account', 'account_type', 'in', ['Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation']]
]
}
["Account", "company", "=", frm.doc.company],
["Account", "is_group", "=", 0],
[
"Account",
"account_type",
"in",
[
"Tax",
"Chargeable",
"Income Account",
"Expense Account",
"Expenses Included In Valuation",
],
],
],
};
});
},
company: function (frm) {
frm.set_query("tax_type", "taxes", function(doc) {
frm.set_query("tax_type", "taxes", function (doc) {
return {
filters: [
['Account', 'company', '=', frm.doc.company],
['Account', 'is_group', '=', 0],
['Account', 'account_type', 'in', ['Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation']]
]
}
["Account", "company", "=", frm.doc.company],
["Account", "is_group", "=", 0],
[
"Account",
"account_type",
"in",
[
"Tax",
"Chargeable",
"Income Account",
"Expense Account",
"Expenses Included In Valuation",
],
],
],
};
});
}
},
});

View File

@@ -4,39 +4,82 @@
frappe.provide("erpnext.accounts");
frappe.provide("erpnext.journal_entry");
frappe.ui.form.on("Journal Entry", {
setup: function(frm) {
setup: function (frm) {
frm.add_fetch("bank_account", "account", "account");
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset', 'Asset Movement', 'Asset Depreciation Schedule', "Repost Accounting Ledger", "Unreconcile Payment", "Unreconcile Payment Entries", "Bank Transaction"];
frm.ignore_doctypes_on_cancel_all = [
"Sales Invoice",
"Purchase Invoice",
"Journal Entry",
"Repost Payment Ledger",
"Asset",
"Asset Movement",
"Asset Depreciation Schedule",
"Repost Accounting Ledger",
"Unreconcile Payment",
"Unreconcile Payment Entries",
"Bank Transaction",
];
},
refresh: function(frm) {
refresh: function (frm) {
erpnext.toggle_naming_series();
if(frm.doc.docstatus > 0) {
frm.add_custom_button(__('Ledger'), function() {
frappe.route_options = {
"voucher_no": frm.doc.name,
"from_date": frm.doc.posting_date,
"to_date": moment(frm.doc.modified).format('YYYY-MM-DD'),
"company": frm.doc.company,
"finance_book": frm.doc.finance_book,
"group_by": '',
"show_cancelled_entries": frm.doc.docstatus === 2
};
frappe.set_route("query-report", "General Ledger");
}, __('View'));
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==1) {
frm.add_custom_button(__('Reverse Journal Entry'), function() {
return erpnext.journal_entry.reverse_journal_entry(frm);
}, __('Actions'));
if (frm.doc.docstatus > 0) {
frm.add_custom_button(
__("Ledger"),
function () {
frappe.route_options = {
voucher_no: frm.doc.name,
from_date: frm.doc.posting_date,
to_date: moment(frm.doc.modified).format("YYYY-MM-DD"),
company: frm.doc.company,
finance_book: frm.doc.finance_book,
group_by: "",
show_cancelled_entries: frm.doc.docstatus === 2,
};
frappe.set_route("query-report", "General Ledger");
},
__("View")
);
}
if (frm.doc.docstatus == 1) {
frm.add_custom_button(
__("Reverse Journal Entry"),
function () {
return erpnext.journal_entry.reverse_journal_entry(frm);
},
__("Actions")
);
}
if (frm.doc.__islocal) {
frm.add_custom_button(__('Quick Entry'), function() {
frm.add_custom_button(__("Quick Entry"), function () {
return erpnext.journal_entry.quick_entry(frm);
});
}
@@ -44,52 +87,63 @@ frappe.ui.form.on("Journal Entry", {
// hide /unhide fields based on currency
erpnext.journal_entry.toggle_fields_based_on_currency(frm);
if ((frm.doc.voucher_type == "Inter Company Journal Entry") && (frm.doc.docstatus == 1) && (!frm.doc.inter_company_journal_entry_reference)) {
frm.add_custom_button(__("Create Inter Company Journal Entry"),
function() {
if (
frm.doc.voucher_type == "Inter Company Journal Entry" &&
frm.doc.docstatus == 1 &&
!frm.doc.inter_company_journal_entry_reference
) {
frm.add_custom_button(
__("Create Inter Company Journal Entry"),
function () {
frm.trigger("make_inter_company_journal_entry");
}, __('Make'));
},
__("Make")
);
}
erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm);
},
before_save: function(frm) {
if ((frm.doc.docstatus == 0) && (!frm.doc.is_system_generated)) {
let payment_entry_references = frm.doc.accounts.filter(elem => (elem.reference_type == "Payment Entry"));
before_save: function (frm) {
if (frm.doc.docstatus == 0 && !frm.doc.is_system_generated) {
let payment_entry_references = frm.doc.accounts.filter(
(elem) => elem.reference_type == "Payment Entry"
);
if (payment_entry_references.length > 0) {
let rows = payment_entry_references.map(x => "#"+x.idx);
frappe.throw(__("Rows: {0} have 'Payment Entry' as reference_type. This should not be set manually.", [frappe.utils.comma_and(rows)]));
let rows = payment_entry_references.map((x) => "#" + x.idx);
frappe.throw(
__("Rows: {0} have 'Payment Entry' as reference_type. This should not be set manually.", [
frappe.utils.comma_and(rows),
])
);
}
}
},
make_inter_company_journal_entry: function(frm) {
make_inter_company_journal_entry: function (frm) {
var d = new frappe.ui.Dialog({
title: __("Select Company"),
fields: [
{
'fieldname': 'company',
'fieldtype': 'Link',
'label': __('Company'),
'options': 'Company',
"get_query": function () {
fieldname: "company",
fieldtype: "Link",
label: __("Company"),
options: "Company",
get_query: function () {
return {
filters: [
["Company", "name", "!=", frm.doc.company]
]
filters: [["Company", "name", "!=", frm.doc.company]],
};
},
'reqd': 1
}
reqd: 1,
},
],
});
d.set_primary_action(__('Create'), function() {
d.set_primary_action(__("Create"), function () {
d.hide();
var args = d.get_values();
frappe.call({
args: {
"name": frm.doc.name,
"voucher_type": frm.doc.voucher_type,
"company": args.company
name: frm.doc.name,
voucher_type: frm.doc.voucher_type,
company: args.company,
},
method: "erpnext.accounts.doctype.journal_entry.journal_entry.make_inter_company_journal_entry",
callback: function (r) {
@@ -97,103 +151,106 @@ frappe.ui.form.on("Journal Entry", {
var doc = frappe.model.sync(r.message)[0];
frappe.set_route("Form", doc.doctype, doc.name);
}
}
},
});
});
d.show();
},
multi_currency: function(frm) {
multi_currency: function (frm) {
erpnext.journal_entry.toggle_fields_based_on_currency(frm);
},
posting_date: function(frm) {
if(!frm.doc.multi_currency || !frm.doc.posting_date) return;
posting_date: function (frm) {
if (!frm.doc.multi_currency || !frm.doc.posting_date) return;
$.each(frm.doc.accounts || [], function(i, row) {
$.each(frm.doc.accounts || [], function (i, row) {
erpnext.journal_entry.set_exchange_rate(frm, row.doctype, row.name);
})
});
},
company: function(frm) {
company: function (frm) {
frappe.call({
method: "frappe.client.get_value",
args: {
doctype: "Company",
filters: {"name": frm.doc.company},
fieldname: "cost_center"
filters: { name: frm.doc.company },
fieldname: "cost_center",
},
callback: function(r){
if(r.message){
$.each(frm.doc.accounts || [], function(i, jvd) {
callback: function (r) {
if (r.message) {
$.each(frm.doc.accounts || [], function (i, jvd) {
frappe.model.set_value(jvd.doctype, jvd.name, "cost_center", r.message.cost_center);
});
}
}
},
});
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
voucher_type: function(frm){
voucher_type: function (frm) {
if (!frm.doc.company) return null;
if(!frm.doc.company) return null;
if((!(frm.doc.accounts || []).length) || ((frm.doc.accounts || []).length === 1 && !frm.doc.accounts[0].account)) {
if(in_list(["Bank Entry", "Cash Entry"], frm.doc.voucher_type)) {
if (
!(frm.doc.accounts || []).length ||
((frm.doc.accounts || []).length === 1 && !frm.doc.accounts[0].account)
) {
if (in_list(["Bank Entry", "Cash Entry"], frm.doc.voucher_type)) {
return frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
args: {
"account_type": (frm.doc.voucher_type=="Bank Entry" ?
"Bank" : (frm.doc.voucher_type=="Cash Entry" ? "Cash" : null)),
"company": frm.doc.company
account_type:
frm.doc.voucher_type == "Bank Entry"
? "Bank"
: frm.doc.voucher_type == "Cash Entry"
? "Cash"
: null,
company: frm.doc.company,
},
callback: function(r) {
if(r.message) {
callback: function (r) {
if (r.message) {
// If default company bank account not set
if(!$.isEmptyObject(r.message)){
if (!$.isEmptyObject(r.message)) {
update_jv_details(frm.doc, [r.message]);
}
}
}
},
});
}
}
},
from_template: function(frm){
if (frm.doc.from_template){
frappe.db.get_doc("Journal Entry Template", frm.doc.from_template)
.then((doc) => {
frappe.model.clear_table(frm.doc, "accounts");
frm.set_value({
"company": doc.company,
"voucher_type": doc.voucher_type,
"naming_series": doc.naming_series,
"is_opening": doc.is_opening,
"multi_currency": doc.multi_currency
})
update_jv_details(frm.doc, doc.accounts);
from_template: function (frm) {
if (frm.doc.from_template) {
frappe.db.get_doc("Journal Entry Template", frm.doc.from_template).then((doc) => {
frappe.model.clear_table(frm.doc, "accounts");
frm.set_value({
company: doc.company,
voucher_type: doc.voucher_type,
naming_series: doc.naming_series,
is_opening: doc.is_opening,
multi_currency: doc.multi_currency,
});
update_jv_details(frm.doc, doc.accounts);
});
}
}
},
});
var update_jv_details = function(doc, r) {
$.each(r, function(i, d) {
var update_jv_details = function (doc, r) {
$.each(r, function (i, d) {
var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
frappe.model.set_value(row.doctype, row.name, "account", d.account)
frappe.model.set_value(row.doctype, row.name, "balance", d.balance)
frappe.model.set_value(row.doctype, row.name, "account", d.account);
});
refresh_field("accounts");
}
};
erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Controller {
onload() {
this.load_defaults();
this.setup_queries();
this.setup_balance_formatter();
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
}
@@ -203,69 +260,67 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
load_defaults() {
//this.frm.show_print_first = true;
if(this.frm.doc.__islocal && this.frm.doc.company) {
if (this.frm.doc.__islocal && this.frm.doc.company) {
frappe.model.set_default_values(this.frm.doc);
$.each(this.frm.doc.accounts || [], function(i, jvd) {
$.each(this.frm.doc.accounts || [], function (i, jvd) {
frappe.model.set_default_values(jvd);
});
var posting_date = this.frm.doc.posting_date;
if(!this.frm.doc.amended_from) this.frm.set_value('posting_date', posting_date || frappe.datetime.get_today());
if (!this.frm.doc.amended_from)
this.frm.set_value("posting_date", posting_date || frappe.datetime.get_today());
}
}
setup_queries() {
var me = this;
me.frm.set_query("account", "accounts", function(doc, cdt, cdn) {
me.frm.set_query("account", "accounts", function (doc, cdt, cdn) {
return erpnext.journal_entry.account_query(me.frm);
});
me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
me.frm.set_query("party_type", "accounts", function (doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
filters: {
'account': row.account
}
}
account: row.account,
},
};
});
me.frm.set_query("reference_name", "accounts", function(doc, cdt, cdn) {
me.frm.set_query("reference_name", "accounts", function (doc, cdt, cdn) {
var jvd = frappe.get_doc(cdt, cdn);
// journal entry
if(jvd.reference_type==="Journal Entry") {
if (jvd.reference_type === "Journal Entry") {
frappe.model.validate_missing(jvd, "account");
return {
query: "erpnext.accounts.doctype.journal_entry.journal_entry.get_against_jv",
filters: {
account: jvd.account,
party: jvd.party
}
party: jvd.party,
},
};
}
var out = {
filters: [
[jvd.reference_type, "docstatus", "=", 1]
]
filters: [[jvd.reference_type, "docstatus", "=", 1]],
};
if(in_list(["Sales Invoice", "Purchase Invoice"], jvd.reference_type)) {
if (in_list(["Sales Invoice", "Purchase Invoice"], jvd.reference_type)) {
out.filters.push([jvd.reference_type, "outstanding_amount", "!=", 0]);
// Filter by cost center
if(jvd.cost_center) {
if (jvd.cost_center) {
out.filters.push([jvd.reference_type, "cost_center", "in", ["", jvd.cost_center]]);
}
// account filter
frappe.model.validate_missing(jvd, "account");
var party_account_field = jvd.reference_type==="Sales Invoice" ? "debit_to": "credit_to";
var party_account_field = jvd.reference_type === "Sales Invoice" ? "debit_to" : "credit_to";
out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]);
}
if(in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) {
if (in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) {
// party_type and party mandatory
frappe.model.validate_missing(jvd, "party_type");
frappe.model.validate_missing(jvd, "party");
@@ -273,11 +328,11 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
out.filters.push([jvd.reference_type, "per_billed", "<", 100]);
}
if(jvd.party_type && jvd.party) {
if (jvd.party_type && jvd.party) {
let party_field = "";
if(jvd.reference_type.indexOf("Sales")===0) {
if (jvd.reference_type.indexOf("Sales") === 0) {
party_field = "customer";
} else if (jvd.reference_type.indexOf("Purchase")===0) {
} else if (jvd.reference_type.indexOf("Purchase") === 0) {
party_field = "supplier";
}
@@ -288,64 +343,49 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
return out;
});
}
setup_balance_formatter() {
const formatter = function(value, df, options, doc) {
var currency = frappe.meta.get_field_currency(df, doc);
var dr_or_cr = value ? ('<label>' + (value > 0.0 ? __("Dr") : __("Cr")) + '</label>') : "";
return "<div style='text-align: right'>"
+ ((value==null || value==="") ? "" : format_currency(Math.abs(value), currency))
+ " " + dr_or_cr
+ "</div>";
};
this.frm.fields_dict.accounts.grid.update_docfield_property('balance', 'formatter', formatter);
this.frm.fields_dict.accounts.grid.update_docfield_property('party_balance', 'formatter', formatter);
}
reference_name(doc, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn);
if(d.reference_name) {
if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) {
this.get_outstanding('Purchase Invoice', d.reference_name, doc.company, d);
} else if (d.reference_type==="Sales Invoice" && !flt(d.credit)) {
this.get_outstanding('Sales Invoice', d.reference_name, doc.company, d);
} else if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
this.get_outstanding('Journal Entry', d.reference_name, doc.company, d);
if (d.reference_name) {
if (d.reference_type === "Purchase Invoice" && !flt(d.debit)) {
this.get_outstanding("Purchase Invoice", d.reference_name, doc.company, d);
} else if (d.reference_type === "Sales Invoice" && !flt(d.credit)) {
this.get_outstanding("Sales Invoice", d.reference_name, doc.company, d);
} else if (d.reference_type === "Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
this.get_outstanding("Journal Entry", d.reference_name, doc.company, d);
}
}
}
get_outstanding(doctype, docname, company, child) {
var args = {
"doctype": doctype,
"docname": docname,
"party": child.party,
"account": child.account,
"account_currency": child.account_currency,
"company": company
}
doctype: doctype,
docname: docname,
party: child.party,
account: child.account,
account_currency: child.account_currency,
company: company,
};
return frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_outstanding",
args: { args: args},
callback: function(r) {
if(r.message) {
$.each(r.message, function(field, value) {
args: { args: args },
callback: function (r) {
if (r.message) {
$.each(r.message, function (field, value) {
frappe.model.set_value(child.doctype, child.name, field, value);
})
});
}
}
},
});
}
accounts_add(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
$.each(doc.accounts, function(i, d) {
if(d.account && d.party && d.party_type) {
$.each(doc.accounts, function (i, d) {
if (d.account && d.party && d.party_type) {
row.account = d.account;
row.party = d.party;
row.party_type = d.party_type;
@@ -353,8 +393,8 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
});
// set difference
if(doc.difference) {
if(doc.difference > 0) {
if (doc.difference) {
if (doc.difference > 0) {
row.credit_in_account_currency = doc.difference;
row.credit = doc.difference;
} else {
@@ -364,132 +404,141 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
}
cur_frm.cscript.update_totals(doc);
erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'accounts');
erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, "accounts");
}
};
cur_frm.script_manager.make(erpnext.accounts.JournalEntry);
cur_frm.cscript.update_totals = function(doc) {
var td=0.0; var tc =0.0;
cur_frm.cscript.update_totals = function (doc) {
var td = 0.0;
var tc = 0.0;
var accounts = doc.accounts || [];
for(var i in accounts) {
for (var i in accounts) {
td += flt(accounts[i].debit, precision("debit", accounts[i]));
tc += flt(accounts[i].credit, precision("credit", accounts[i]));
}
doc = locals[doc.doctype][doc.name];
doc.total_debit = td;
doc.total_credit = tc;
doc.difference = flt((td - tc), precision("difference"));
refresh_many(['total_debit','total_credit','difference']);
}
doc.difference = flt(td - tc, precision("difference"));
refresh_many(["total_debit", "total_credit", "difference"]);
};
cur_frm.cscript.get_balance = function(doc,dt,dn) {
cur_frm.cscript.get_balance = function (doc, dt, dn) {
cur_frm.cscript.update_totals(doc);
cur_frm.call('get_balance', null, () => { cur_frm.refresh(); });
}
cur_frm.call("get_balance", null, () => {
cur_frm.refresh();
});
};
cur_frm.cscript.validate = function(doc,cdt,cdn) {
cur_frm.cscript.validate = function (doc, cdt, cdn) {
cur_frm.cscript.update_totals(doc);
}
};
frappe.ui.form.on("Journal Entry Account", {
party: function(frm, cdt, cdn) {
party: function (frm, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn);
if(!d.account && d.party_type && d.party) {
if(!frm.doc.company) frappe.throw(__("Please select Company"));
if (!d.account && d.party_type && d.party) {
if (!frm.doc.company) frappe.throw(__("Please select Company"));
return frm.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_balance",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_currency",
child: d,
args: {
company: frm.doc.company,
party_type: d.party_type,
party: d.party,
cost_center: d.cost_center
}
},
});
}
},
cost_center: function(frm, dt, dn) {
erpnext.journal_entry.set_account_balance(frm, dt, dn);
cost_center: function (frm, dt, dn) {
erpnext.journal_entry.set_account_details(frm, dt, dn);
},
account: function(frm, dt, dn) {
erpnext.journal_entry.set_account_balance(frm, dt, dn);
account: function (frm, dt, dn) {
erpnext.journal_entry.set_account_details(frm, dt, dn);
},
debit_in_account_currency: function(frm, cdt, cdn) {
debit_in_account_currency: function (frm, cdt, cdn) {
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
},
credit_in_account_currency: function(frm, cdt, cdn) {
credit_in_account_currency: function (frm, cdt, cdn) {
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
},
debit: function(frm, dt, dn) {
debit: function (frm, dt, dn) {
cur_frm.cscript.update_totals(frm.doc);
},
credit: function(frm, dt, dn) {
credit: function (frm, dt, dn) {
cur_frm.cscript.update_totals(frm.doc);
},
exchange_rate: function(frm, cdt, cdn) {
exchange_rate: function (frm, cdt, cdn) {
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
var row = locals[cdt][cdn];
if(row.account_currency == company_currency || !frm.doc.multi_currency) {
if (row.account_currency == company_currency || !frm.doc.multi_currency) {
frappe.model.set_value(cdt, cdn, "exchange_rate", 1);
}
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
}
})
},
});
frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) {
frappe.ui.form.on("Journal Entry Account", "accounts_remove", function (frm) {
cur_frm.cscript.update_totals(frm.doc);
});
$.extend(erpnext.journal_entry, {
toggle_fields_based_on_currency: function(frm) {
toggle_fields_based_on_currency: function (frm) {
var fields = ["currency_section", "account_currency", "exchange_rate", "debit", "credit"];
var grid = frm.get_field("accounts").grid;
if(grid) grid.set_column_disp(fields, frm.doc.multi_currency);
if (grid) grid.set_column_disp(fields, frm.doc.multi_currency);
// dynamic label
var field_label_map = {
"debit_in_account_currency": "Debit",
"credit_in_account_currency": "Credit"
debit_in_account_currency: "Debit",
credit_in_account_currency: "Credit",
};
$.each(field_label_map, function (fieldname, label) {
frm.fields_dict.accounts.grid.update_docfield_property(
fieldname,
'label',
frm.doc.multi_currency ? (label + " in Account Currency") : label
"label",
frm.doc.multi_currency ? label + " in Account Currency" : label
);
})
});
},
set_debit_credit_in_company_currency: function(frm, cdt, cdn) {
set_debit_credit_in_company_currency: function (frm, cdt, cdn) {
var row = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, "debit",
flt(flt(row.debit_in_account_currency)*row.exchange_rate, precision("debit", row)));
frappe.model.set_value(
cdt,
cdn,
"debit",
flt(flt(row.debit_in_account_currency) * row.exchange_rate, precision("debit", row))
);
frappe.model.set_value(cdt, cdn, "credit",
flt(flt(row.credit_in_account_currency)*row.exchange_rate, precision("credit", row)));
frappe.model.set_value(
cdt,
cdn,
"credit",
flt(flt(row.credit_in_account_currency) * row.exchange_rate, precision("credit", row))
);
cur_frm.cscript.update_totals(frm.doc);
},
set_exchange_rate: function(frm, cdt, cdn) {
set_exchange_rate: function (frm, cdt, cdn) {
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
var row = locals[cdt][cdn];
if(row.account_currency == company_currency || !frm.doc.multi_currency) {
if (row.account_currency == company_currency || !frm.doc.multi_currency) {
row.exchange_rate = 1;
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
} else if (!row.exchange_rate || row.exchange_rate == 1 || row.account_type == "Bank") {
@@ -504,50 +553,70 @@ $.extend(erpnext.journal_entry, {
reference_name: cstr(row.reference_name),
debit: flt(row.debit_in_account_currency),
credit: flt(row.credit_in_account_currency),
exchange_rate: row.exchange_rate
exchange_rate: row.exchange_rate,
},
callback: function(r) {
if(r.message) {
callback: function (r) {
if (r.message) {
row.exchange_rate = r.message;
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
}
}
})
},
});
} else {
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
}
refresh_field("exchange_rate", cdn, "accounts");
},
quick_entry: function(frm) {
quick_entry: function (frm) {
var naming_series_options = frm.fields_dict.naming_series.df.options;
var naming_series_default = frm.fields_dict.naming_series.df.default || naming_series_options.split("\n")[0];
var naming_series_default =
frm.fields_dict.naming_series.df.default || naming_series_options.split("\n")[0];
var dialog = new frappe.ui.Dialog({
title: __("Quick Journal Entry"),
fields: [
{fieldtype: "Currency", fieldname: "debit", label: __("Amount"), reqd: 1},
{fieldtype: "Link", fieldname: "debit_account", label: __("Debit Account"), reqd: 1,
{ fieldtype: "Currency", fieldname: "debit", label: __("Amount"), reqd: 1 },
{
fieldtype: "Link",
fieldname: "debit_account",
label: __("Debit Account"),
reqd: 1,
options: "Account",
get_query: function() {
get_query: function () {
return erpnext.journal_entry.account_query(frm);
}
},
},
{fieldtype: "Link", fieldname: "credit_account", label: __("Credit Account"), reqd: 1,
{
fieldtype: "Link",
fieldname: "credit_account",
label: __("Credit Account"),
reqd: 1,
options: "Account",
get_query: function() {
get_query: function () {
return erpnext.journal_entry.account_query(frm);
}
},
},
{fieldtype: "Date", fieldname: "posting_date", label: __("Date"), reqd: 1,
default: frm.doc.posting_date},
{fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark")},
{fieldtype: "Select", fieldname: "naming_series", label: __("Series"), reqd: 1,
options: naming_series_options, default: naming_series_default},
]
{
fieldtype: "Date",
fieldname: "posting_date",
label: __("Date"),
reqd: 1,
default: frm.doc.posting_date,
},
{ fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark") },
{
fieldtype: "Select",
fieldname: "naming_series",
label: __("Series"),
reqd: 1,
options: naming_series_options,
default: naming_series_default,
},
],
});
dialog.set_primary_action(__("Save"), function() {
dialog.set_primary_action(__("Save"), function () {
var btn = this;
var values = dialog.get_values();
@@ -564,11 +633,21 @@ $.extend(erpnext.journal_entry, {
var debit_row = frm.fields_dict.accounts.grid.add_new_row();
frappe.model.set_value(debit_row.doctype, debit_row.name, "account", values.debit_account);
frappe.model.set_value(debit_row.doctype, debit_row.name, "debit_in_account_currency", values.debit);
frappe.model.set_value(
debit_row.doctype,
debit_row.name,
"debit_in_account_currency",
values.debit
);
var credit_row = frm.fields_dict.accounts.grid.add_new_row();
frappe.model.set_value(credit_row.doctype, credit_row.name, "account", values.credit_account);
frappe.model.set_value(credit_row.doctype, credit_row.name, "credit_in_account_currency", values.debit);
frappe.model.set_value(
credit_row.doctype,
credit_row.name,
"credit_in_account_currency",
values.debit
);
frm.save();
@@ -578,36 +657,39 @@ $.extend(erpnext.journal_entry, {
dialog.show();
},
account_query: function(frm) {
account_query: function (frm) {
var filters = {
company: frm.doc.company,
is_group: 0
is_group: 0,
};
if(!frm.doc.multi_currency) {
if (!frm.doc.multi_currency) {
$.extend(filters, {
account_currency: ['in', [frappe.get_doc(":Company", frm.doc.company).default_currency, null]]
account_currency: [
"in",
[frappe.get_doc(":Company", frm.doc.company).default_currency, null],
],
});
}
return { filters: filters };
},
reverse_journal_entry: function() {
reverse_journal_entry: function () {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.make_reverse_journal_entry",
frm: cur_frm
})
frm: cur_frm,
});
},
});
$.extend(erpnext.journal_entry, {
set_account_balance: function(frm, dt, dn) {
set_account_details: function (frm, dt, dn) {
var d = locals[dt][dn];
if(d.account) {
if(!frm.doc.company) frappe.throw(__("Please select Company first"));
if(!frm.doc.posting_date) frappe.throw(__("Please select Posting Date first"));
if (d.account) {
if (!frm.doc.company) frappe.throw(__("Please select Company first"));
if (!frm.doc.posting_date) frappe.throw(__("Please select Posting Date first"));
return frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_balance_and_party_type",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_details_and_party_type",
args: {
account: d.account,
date: frm.doc.posting_date,
@@ -615,15 +697,14 @@ $.extend(erpnext.journal_entry, {
debit: flt(d.debit_in_account_currency),
credit: flt(d.credit_in_account_currency),
exchange_rate: d.exchange_rate,
cost_center: d.cost_center
},
callback: function(r) {
if(r.message) {
callback: function (r) {
if (r.message) {
$.extend(d, r.message);
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, dt, dn);
refresh_field('accounts');
refresh_field("accounts");
}
}
},
});
}
},

View File

@@ -64,7 +64,8 @@
"stock_entry",
"subscription_section",
"auto_repeat",
"amended_from"
"amended_from",
"repost_required"
],
"fields": [
{
@@ -543,6 +544,15 @@
"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",
@@ -558,6 +568,7 @@
}
],
"modified": "2023-11-23 12:11:04.128015",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",

View File

@@ -13,6 +13,10 @@ from erpnext.accounts.deferred_revenue import get_deferred_booking_accounts
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import (
get_party_account_based_on_invoice_discounting,
)
from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import (
validate_docs_for_deferred_accounting,
validate_docs_for_voucher_types,
)
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import (
get_party_tax_withholding_details,
)
@@ -140,7 +144,6 @@ class JournalEntry(AccountsController):
self.set_print_format_fields()
self.validate_credit_debit_note()
self.validate_empty_accounts_table()
self.set_account_and_party_balance()
self.validate_inter_company_accounts()
self.validate_depr_entry_voucher_type()
@@ -150,6 +153,24 @@ class JournalEntry(AccountsController):
if not self.title:
self.title = self.get_title()
def validate_for_repost(self):
validate_docs_for_voucher_types(["Journal Entry"])
validate_docs_for_deferred_accounting([self.name], [])
def submit(self):
if len(self.accounts) > 100 and not frappe.job:
msgprint(_("The task has been enqueued as a background job."), alert=True)
self.queue_action("submit", timeout=4600)
else:
return self._submit()
def cancel(self):
if len(self.accounts) > 100 and not frappe.job:
msgprint(_("The task has been enqueued as a background job."), alert=True)
self.queue_action("cancel", timeout=4600)
else:
return self._cancel()
def on_submit(self):
self.validate_cheque_info()
self.check_credit_limit()
@@ -159,6 +180,15 @@ class JournalEntry(AccountsController):
self.update_inter_company_jv()
self.update_invoice_discounting()
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)
def on_cancel(self):
# References for this Journal are removed on the `on_cancel` event in accounts_controller
super(JournalEntry, self).on_cancel()
@@ -187,8 +217,8 @@ class JournalEntry(AccountsController):
def update_advance_paid(self):
advance_paid = frappe._dict()
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
"advance_payment_receivable_doctypes"
) + frappe.get_hooks("advance_payment_payable_doctypes")
for d in self.get("accounts"):
if d.is_advance:
if d.reference_type in advance_payment_doctypes:
@@ -548,17 +578,28 @@ class JournalEntry(AccountsController):
elif d.party_type == "Supplier" and flt(d.credit) > 0:
frappe.throw(_("Row {0}: Advance against Supplier must be debit").format(d.idx))
def system_generated_gain_loss(self):
return (
self.voucher_type == "Exchange Gain Or Loss"
and self.multi_currency
and self.is_system_generated
)
def validate_against_jv(self):
for d in self.get("accounts"):
if d.reference_type == "Journal Entry":
account_root_type = frappe.get_cached_value("Account", d.account, "root_type")
if account_root_type == "Asset" and flt(d.debit) > 0:
if account_root_type == "Asset" and flt(d.debit) > 0 and not self.system_generated_gain_loss():
frappe.throw(
_(
"Row #{0}: For {1}, you can select reference document only if account gets credited"
).format(d.idx, d.account)
)
elif account_root_type == "Liability" and flt(d.credit) > 0:
elif (
account_root_type == "Liability"
and flt(d.credit) > 0
and not self.system_generated_gain_loss()
):
frappe.throw(
_(
"Row #{0}: For {1}, you can select reference document only if account gets debited"
@@ -590,7 +631,7 @@ class JournalEntry(AccountsController):
for jvd in against_entries:
if flt(jvd[dr_or_cr]) > 0:
valid = True
if not valid:
if not valid and not self.system_generated_gain_loss():
frappe.throw(
_("Against Journal Entry {0} does not have any unmatched {1} entry").format(
d.reference_name, dr_or_cr
@@ -1138,24 +1179,11 @@ class JournalEntry(AccountsController):
if not self.get("accounts"):
frappe.throw(_("Accounts table cannot be blank."))
def set_account_and_party_balance(self):
account_balance = {}
party_balance = {}
for d in self.get("accounts"):
if d.account not in account_balance:
account_balance[d.account] = get_balance_on(account=d.account, date=self.posting_date)
if (d.party_type, d.party) not in party_balance:
party_balance[(d.party_type, d.party)] = get_balance_on(
party_type=d.party_type, party=d.party, date=self.posting_date, company=self.company
)
d.account_balance = account_balance[d.account]
d.party_balance = party_balance[(d.party_type, d.party)]
@frappe.whitelist()
def get_default_bank_cash_account(company, account_type=None, mode_of_payment=None, account=None):
def get_default_bank_cash_account(
company, account_type=None, mode_of_payment=None, account=None, ignore_permissions=False
):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
if mode_of_payment:
@@ -1193,7 +1221,7 @@ def get_default_bank_cash_account(company, account_type=None, mode_of_payment=No
return frappe._dict(
{
"account": account,
"balance": get_balance_on(account),
"balance": get_balance_on(account, ignore_account_permission=ignore_permissions),
"account_currency": account_details.account_currency,
"account_type": account_details.account_type,
}
@@ -1318,8 +1346,6 @@ def get_payment_entry(ref_doc, args):
"account_type": frappe.get_cached_value("Account", args.get("party_account"), "account_type"),
"account_currency": args.get("party_account_currency")
or get_account_currency(args.get("party_account")),
"balance": get_balance_on(args.get("party_account")),
"party_balance": get_balance_on(party=args.get("party"), party_type=args.get("party_type")),
"exchange_rate": exchange_rate,
args.get("amount_field_party"): args.get("amount"),
"is_advance": args.get("is_advance"),
@@ -1467,30 +1493,23 @@ def get_outstanding(args):
@frappe.whitelist()
def get_party_account_and_balance(company, party_type, party, cost_center=None):
def get_party_account_and_currency(company, party_type, party):
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)
account = get_party_account(party_type, party, company)
account_balance = get_balance_on(account=account, cost_center=cost_center)
party_balance = get_balance_on(
party_type=party_type, party=party, company=company, cost_center=cost_center
)
return {
"account": account,
"balance": account_balance,
"party_balance": party_balance,
"account_currency": frappe.get_cached_value("Account", account, "account_currency"),
}
@frappe.whitelist()
def get_account_balance_and_party_type(
account, date, company, debit=None, credit=None, exchange_rate=None, cost_center=None
def get_account_details_and_party_type(
account, date, company, debit=None, credit=None, exchange_rate=None
):
"""Returns dict of account balance and party type to be set in Journal Entry on selection of account."""
"""Returns dict of account details and party type to be set in Journal Entry on selection of account."""
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)
@@ -1510,7 +1529,6 @@ def get_account_balance_and_party_type(
party_type = ""
grid_values = {
"balance": get_balance_on(account, date, cost_center=cost_center),
"party_type": party_type,
"account_type": account_details.account_type,
"account_currency": account_details.account_currency or company_currency,

View File

@@ -1,18 +1,8 @@
frappe.listview_settings["Journal Entry"] = {
add_fields: [
"voucher_type",
"posting_date",
"total_debit",
"company",
"user_remark",
],
add_fields: ["voucher_type", "posting_date", "total_debit", "company", "user_remark"],
get_indicator: function (doc) {
if (doc.docstatus === 1) {
return [
__(doc.voucher_type),
"blue",
`voucher_type,=,${doc.voucher_type}`,
];
return [__(doc.voucher_type), "blue", `voucher_type,=,${doc.voucher_type}`];
}
},
};

View File

@@ -166,43 +166,37 @@ class TestJournalEntry(unittest.TestCase):
jv.get("accounts")[1].credit_in_account_currency = 5000
jv.submit()
gl_entries = frappe.db.sql(
"""select account, account_currency, debit, credit,
debit_in_account_currency, credit_in_account_currency
from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s
order by account asc""",
jv.name,
as_dict=1,
)
self.voucher_no = jv.name
self.assertTrue(gl_entries)
self.fields = [
"account",
"account_currency",
"debit",
"debit_in_account_currency",
"credit",
"credit_in_account_currency",
]
expected_values = {
"_Test Bank USD - _TC": {
"account_currency": "USD",
"debit": 5000,
"debit_in_account_currency": 100,
"credit": 0,
"credit_in_account_currency": 0,
},
"_Test Bank - _TC": {
self.expected_gle = [
{
"account": "_Test Bank - _TC",
"account_currency": "INR",
"debit": 0,
"debit_in_account_currency": 0,
"credit": 5000,
"credit_in_account_currency": 5000,
},
}
{
"account": "_Test Bank USD - _TC",
"account_currency": "USD",
"debit": 5000,
"debit_in_account_currency": 100,
"credit": 0,
"credit_in_account_currency": 0,
},
]
for field in (
"account_currency",
"debit",
"debit_in_account_currency",
"credit",
"credit_in_account_currency",
):
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][field], gle[field])
self.check_gl_entries()
# cancel
jv.cancel()
@@ -228,43 +222,37 @@ class TestJournalEntry(unittest.TestCase):
rjv.posting_date = nowdate()
rjv.submit()
gl_entries = frappe.db.sql(
"""select account, account_currency, debit, credit,
debit_in_account_currency, credit_in_account_currency
from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s
order by account asc""",
rjv.name,
as_dict=1,
)
self.voucher_no = rjv.name
self.assertTrue(gl_entries)
self.fields = [
"account",
"account_currency",
"debit",
"credit",
"debit_in_account_currency",
"credit_in_account_currency",
]
expected_values = {
"_Test Bank USD - _TC": {
self.expected_gle = [
{
"account": "_Test Bank USD - _TC",
"account_currency": "USD",
"debit": 0,
"debit_in_account_currency": 0,
"credit": 5000,
"credit_in_account_currency": 100,
},
"Sales - _TC": {
{
"account": "Sales - _TC",
"account_currency": "INR",
"debit": 5000,
"debit_in_account_currency": 5000,
"credit": 0,
"credit_in_account_currency": 0,
},
}
]
for field in (
"account_currency",
"debit",
"debit_in_account_currency",
"credit",
"credit_in_account_currency",
):
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][field], gle[field])
self.check_gl_entries()
def test_disallow_change_in_account_currency_for_a_party(self):
# create jv in USD
@@ -344,23 +332,25 @@ class TestJournalEntry(unittest.TestCase):
jv.insert()
jv.submit()
expected_values = {
"_Test Cash - _TC": {"cost_center": cost_center},
"_Test Bank - _TC": {"cost_center": cost_center},
}
self.voucher_no = jv.name
gl_entries = frappe.db.sql(
"""select account, cost_center, debit, credit
from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s
order by account asc""",
jv.name,
as_dict=1,
)
self.fields = [
"account",
"cost_center",
]
self.assertTrue(gl_entries)
self.expected_gle = [
{
"account": "_Test Bank - _TC",
"cost_center": cost_center,
},
{
"account": "_Test Cash - _TC",
"cost_center": cost_center,
},
]
for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
self.check_gl_entries()
def test_jv_with_project(self):
from erpnext.projects.doctype.project.test_project import make_project
@@ -387,23 +377,22 @@ class TestJournalEntry(unittest.TestCase):
jv.insert()
jv.submit()
expected_values = {
"_Test Cash - _TC": {"project": project_name},
"_Test Bank - _TC": {"project": project_name},
}
self.voucher_no = jv.name
gl_entries = frappe.db.sql(
"""select account, project, debit, credit
from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s
order by account asc""",
jv.name,
as_dict=1,
)
self.fields = ["account", "project"]
self.assertTrue(gl_entries)
self.expected_gle = [
{
"account": "_Test Bank - _TC",
"project": project_name,
},
{
"account": "_Test Cash - _TC",
"project": project_name,
},
]
for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["project"], gle.project)
self.check_gl_entries()
def test_jv_account_and_party_balance_with_cost_centre(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
@@ -426,6 +415,79 @@ class TestJournalEntry(unittest.TestCase):
account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=cost_center)
self.assertEqual(expected_account_balance, account_balance)
def test_repost_accounting_entries(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
# Configure Repost Accounting Ledger for JVs
settings = frappe.get_doc("Repost Accounting Ledger Settings")
if not [x for x in settings.allowed_types if x.document_type == "Journal Entry"]:
settings.append("allowed_types", {"document_type": "Journal Entry", "allowed": True})
settings.save()
# Create JV with defaut cost center - _Test Cost Center
jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, save=False)
jv.multi_currency = 0
jv.submit()
# Check GL entries before reposting
self.voucher_no = jv.name
self.fields = [
"account",
"debit_in_account_currency",
"credit_in_account_currency",
"cost_center",
]
self.expected_gle = [
{
"account": "_Test Bank - _TC",
"debit_in_account_currency": 0,
"credit_in_account_currency": 100,
"cost_center": "_Test Cost Center - _TC",
},
{
"account": "_Test Cash - _TC",
"debit_in_account_currency": 100,
"credit_in_account_currency": 0,
"cost_center": "_Test Cost Center - _TC",
},
]
self.check_gl_entries()
# 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"
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"
self.check_gl_entries()
def check_gl_entries(self):
gl = frappe.qb.DocType("GL Entry")
query = frappe.qb.from_(gl)
for field in self.fields:
query = query.select(gl[field])
query = query.where(
(gl.voucher_type == "Journal Entry")
& (gl.voucher_no == self.voucher_no)
& (gl.is_cancelled == 0)
).orderby(gl.account)
gl_entries = query.run(as_dict=True)
for i in range(len(self.expected_gle)):
for field in self.fields:
self.assertEqual(self.expected_gle[i][field], gl_entries[i][field])
def make_journal_entry(
account1,

View File

@@ -9,12 +9,10 @@
"field_order": [
"account",
"account_type",
"balance",
"col_break1",
"bank_account",
"party_type",
"party",
"party_balance",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
@@ -64,17 +62,7 @@
"print_hide": 1
},
{
"fieldname": "balance",
"fieldtype": "Currency",
"label": "Account Balance",
"no_copy": 1,
"oldfieldname": "balance",
"oldfieldtype": "Data",
"options": "account_currency",
"print_hide": 1,
"read_only": 1
},
{
"allow_on_submit": 1,
"default": ":Company",
"description": "If Income or Expense",
"fieldname": "cost_center",
@@ -107,14 +95,6 @@
"label": "Party",
"options": "party_type"
},
{
"fieldname": "party_balance",
"fieldtype": "Currency",
"label": "Party Balance",
"options": "account_currency",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "currency_section",
"fieldtype": "Section Break",
@@ -223,6 +203,7 @@
"no_copy": 1
},
{
"allow_on_submit": 1,
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
@@ -286,7 +267,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-12-03 23:21:22.205409",
"modified": "2024-02-05 01:10:50.224840",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",

View File

@@ -2,78 +2,85 @@
// For license information, please see license.txt
frappe.ui.form.on("Journal Entry Template", {
onload: function(frm) {
if(frm.is_new()) {
onload: function (frm) {
if (frm.is_new()) {
frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry_template.journal_entry_template.get_naming_series",
callback: function(r){
if(r.message) {
callback: function (r) {
if (r.message) {
frm.set_df_property("naming_series", "options", r.message.split("\n"));
frm.set_value("naming_series", r.message.split("\n")[0]);
frm.refresh_field("naming_series");
}
}
},
});
}
},
refresh: function(frm) {
refresh: function (frm) {
frappe.model.set_default_values(frm.doc);
frm.set_query("account" ,"accounts", function(){
frm.set_query("account", "accounts", function () {
var filters = {
company: frm.doc.company,
is_group: 0
is_group: 0,
};
if(!frm.doc.multi_currency) {
if (!frm.doc.multi_currency) {
$.extend(filters, {
account_currency: ['in', [frappe.get_doc(":Company", frm.doc.company).default_currency, null]]
account_currency: [
"in",
[frappe.get_doc(":Company", frm.doc.company).default_currency, null],
],
});
}
return { filters: filters };
});
},
voucher_type: function(frm) {
var add_accounts = function(doc, r) {
$.each(r, function(i, d) {
voucher_type: function (frm) {
var add_accounts = function (doc, r) {
$.each(r, function (i, d) {
var row = frappe.model.add_child(doc, "Journal Entry Template Account", "accounts");
row.account = d.account;
});
refresh_field("accounts");
};
if(!frm.doc.company) return;
if (!frm.doc.company) return;
frm.trigger("clear_child");
switch(frm.doc.voucher_type){
switch (frm.doc.voucher_type) {
case "Bank Entry":
case "Cash Entry":
frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
args: {
"account_type": (frm.doc.voucher_type=="Bank Entry" ?
"Bank" : (frm.doc.voucher_type=="Cash Entry" ? "Cash" : null)),
"company": frm.doc.company
account_type:
frm.doc.voucher_type == "Bank Entry"
? "Bank"
: frm.doc.voucher_type == "Cash Entry"
? "Cash"
: null,
company: frm.doc.company,
},
callback: function(r) {
if(r.message) {
callback: function (r) {
if (r.message) {
// If default company bank account not set
if(!$.isEmptyObject(r.message)){
if (!$.isEmptyObject(r.message)) {
add_accounts(frm.doc, [r.message]);
}
}
}
},
});
break;
default:
frm.trigger("clear_child");
}
},
clear_child: function(frm){
clear_child: function (frm) {
frappe.model.clear_table(frm.doc, "accounts");
frm.refresh_field("accounts");
}
},
});

View File

@@ -1,9 +1,9 @@
// Copyright (c) 2021, Wahni Green Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Ledger Merge', {
setup: function(frm) {
frappe.realtime.on('ledger_merge_refresh', ({ ledger_merge }) => {
frappe.ui.form.on("Ledger Merge", {
setup: function (frm) {
frappe.realtime.on("ledger_merge_refresh", ({ ledger_merge }) => {
if (ledger_merge !== frm.doc.name) return;
frappe.model.clear_doc(frm.doc.doctype, frm.doc.name);
frappe.model.with_doc(frm.doc.doctype, frm.doc.name).then(() => {
@@ -11,29 +11,29 @@ frappe.ui.form.on('Ledger Merge', {
});
});
frappe.realtime.on('ledger_merge_progress', data => {
frappe.realtime.on("ledger_merge_progress", (data) => {
if (data.ledger_merge !== frm.doc.name) return;
let message = __('Merging {0} of {1}', [data.current, data.total]);
let message = __("Merging {0} of {1}", [data.current, data.total]);
let percent = Math.floor((data.current * 100) / data.total);
frm.dashboard.show_progress(__('Merge Progress'), percent, message);
frm.page.set_indicator(__('In Progress'), 'orange');
frm.dashboard.show_progress(__("Merge Progress"), percent, message);
frm.page.set_indicator(__("In Progress"), "orange");
});
frm.set_query("account", function(doc) {
if (!doc.company) frappe.throw(__('Please set Company'));
if (!doc.root_type) frappe.throw(__('Please set Root Type'));
frm.set_query("account", function (doc) {
if (!doc.company) frappe.throw(__("Please set Company"));
if (!doc.root_type) frappe.throw(__("Please set Root Type"));
return {
filters: {
root_type: doc.root_type,
company: doc.company
}
company: doc.company,
},
};
});
frm.set_query('account', 'merge_accounts', function(doc) {
if (!doc.company) frappe.throw(__('Please set Company'));
if (!doc.root_type) frappe.throw(__('Please set Root Type'));
if (!doc.account) frappe.throw(__('Please set Account'));
frm.set_query("account", "merge_accounts", function (doc) {
if (!doc.company) frappe.throw(__("Please set Company"));
if (!doc.root_type) frappe.throw(__("Please set Root Type"));
if (!doc.account) frappe.throw(__("Please set Account"));
let acc = [doc.account];
frm.doc.merge_accounts.forEach((row) => {
acc.push(row.account);
@@ -43,86 +43,86 @@ frappe.ui.form.on('Ledger Merge', {
is_group: doc.is_group,
root_type: doc.root_type,
name: ["not in", acc],
company: doc.company
}
company: doc.company,
},
};
});
},
refresh: function(frm) {
refresh: function (frm) {
frm.page.hide_icon_group();
frm.trigger('set_merge_status');
frm.trigger('update_primary_action');
frm.trigger("set_merge_status");
frm.trigger("update_primary_action");
},
after_save: function(frm) {
after_save: function (frm) {
setTimeout(() => {
frm.trigger('update_primary_action');
frm.trigger("update_primary_action");
}, 500);
},
update_primary_action: function(frm) {
update_primary_action: function (frm) {
if (frm.is_dirty()) {
frm.enable_save();
return;
}
frm.disable_save();
if (frm.doc.status !== 'Success') {
if (frm.doc.status !== "Success") {
if (!frm.is_new()) {
let label = frm.doc.status === 'Pending' ? __('Start Merge') : __('Retry');
let label = frm.doc.status === "Pending" ? __("Start Merge") : __("Retry");
frm.page.set_primary_action(label, () => frm.events.start_merge(frm));
} else {
frm.page.set_primary_action(__('Save'), () => frm.save());
frm.page.set_primary_action(__("Save"), () => frm.save());
}
}
},
start_merge: function(frm) {
start_merge: function (frm) {
frm.call({
method: 'form_start_merge',
method: "form_start_merge",
args: { docname: frm.doc.name },
btn: frm.page.btn_primary
}).then(r => {
btn: frm.page.btn_primary,
}).then((r) => {
if (r.message === true) {
frm.disable_save();
}
});
},
set_merge_status: function(frm) {
set_merge_status: function (frm) {
if (frm.doc.status == "Pending") return;
let successful_records = 0;
frm.doc.merge_accounts.forEach((row) => {
if (row.merged) successful_records += 1;
});
let message_args = [successful_records, frm.doc.merge_accounts.length];
frm.dashboard.set_headline(__('Successfully merged {0} out of {1}.', message_args));
frm.dashboard.set_headline(__("Successfully merged {0} out of {1}.", message_args));
},
root_type: function(frm) {
frm.set_value('account', '');
frm.set_value('merge_accounts', []);
root_type: function (frm) {
frm.set_value("account", "");
frm.set_value("merge_accounts", []);
},
company: function(frm) {
frm.set_value('account', '');
frm.set_value('merge_accounts', []);
}
company: function (frm) {
frm.set_value("account", "");
frm.set_value("merge_accounts", []);
},
});
frappe.ui.form.on('Ledger Merge Accounts', {
merge_accounts_add: function(frm) {
frm.trigger('update_primary_action');
frappe.ui.form.on("Ledger Merge Accounts", {
merge_accounts_add: function (frm) {
frm.trigger("update_primary_action");
},
merge_accounts_remove: function(frm) {
frm.trigger('update_primary_action');
merge_accounts_remove: function (frm) {
frm.trigger("update_primary_action");
},
account: function(frm, cdt, cdn) {
account: function (frm, cdt, cdn) {
let row = frappe.get_doc(cdt, cdn);
row.account_name = row.account;
frm.refresh_field('merge_accounts');
frm.trigger('update_primary_action');
}
frm.refresh_field("merge_accounts");
frm.trigger("update_primary_action");
},
});

View File

@@ -1,8 +1,6 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Loyalty Point Entry', {
refresh: function(frm) {
}
frappe.ui.form.on("Loyalty Point Entry", {
refresh: function (frm) {},
});

View File

@@ -3,30 +3,37 @@
frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Loyalty Program', {
setup: function(frm) {
var help_content =
`<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);">
frappe.ui.form.on("Loyalty Program", {
setup: function (frm) {
var help_content = `<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);">
<tr><td>
<h4>
<i class="fa fa-hand-right"></i>
${__('Notes')}
${__("Notes")}
</h4>
<ul>
<li>
${__("Loyalty Points will be calculated from the spent done (via the Sales Invoice), based on collection factor mentioned.")}
${__(
"Loyalty Points will be calculated from the spent done (via the Sales Invoice), based on collection factor mentioned."
)}
</li>
<li>
${__("There can be multiple tiered collection factor based on the total spent. But the conversion factor for redemption will always be same for all the tier.")}
${__(
"There can be multiple tiered collection factor based on the total spent. But the conversion factor for redemption will always be same for all the tier."
)}
</li>
<li>
${__("In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent")}
${__(
"In the case of multi-tier program, Customers will be auto assigned to the concerned tier as per their spent"
)}
</li>
<li>
${__("If unlimited expiry for the Loyalty Points, keep the Expiry Duration empty or 0.")}
</li>
<li>
${__("If Auto Opt In is checked, then the customers will be automatically linked with the concerned Loyalty Program (on save)")}
${__(
"If Auto Opt In is checked, then the customers will be automatically linked with the concerned Loyalty Program (on save)"
)}
</li>
<li>
${__("One customer can be part of only single Loyalty Program.")}
@@ -37,14 +44,14 @@ frappe.ui.form.on('Loyalty Program', {
set_field_options("loyalty_program_help", help_content);
},
onload: function(frm) {
frm.set_query("expense_account", function(doc) {
onload: function (frm) {
frm.set_query("expense_account", function (doc) {
return {
filters: {
"root_type": "Expense",
'is_group': 0,
'company': doc.company
}
root_type: "Expense",
is_group: 0,
company: doc.company,
},
};
});
@@ -52,13 +59,15 @@ frappe.ui.form.on('Loyalty Program', {
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
refresh: function (frm) {
if (frm.doc.loyalty_program_type === "Single Tier Program" && frm.doc.collection_rules.length > 1) {
frappe.throw(__("Please select the Multiple Tier Program type for more than one collection rules."));
frappe.throw(
__("Please select the Multiple Tier Program type for more than one collection rules.")
);
}
},
company: function(frm) {
company: function (frm) {
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
}
},
});

View File

@@ -1,16 +1,16 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on('Mode of Payment', {
setup: function(frm) {
frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
frappe.ui.form.on("Mode of Payment", {
setup: function (frm) {
frm.set_query("default_account", "accounts", function (doc, cdt, cdn) {
let d = locals[cdt][cdn];
return {
filters: [
['Account', 'account_type', 'in', 'Bank, Cash, Receivable'],
['Account', 'is_group', '=', 0],
['Account', 'company', '=', d.company]
]
["Account", "account_type", "in", "Bank, Cash, Receivable"],
["Account", "is_group", "=", 0],
["Account", "company", "=", d.company],
],
};
});
},

View File

@@ -1,16 +1,16 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on('Monthly Distribution', {
frappe.ui.form.on("Monthly Distribution", {
onload(frm) {
if(frm.doc.__islocal) {
return frm.call('get_months').then(() => {
frm.refresh_field('percentages');
if (frm.doc.__islocal) {
return frm.call("get_months").then(() => {
frm.refresh_field("percentages");
});
}
},
refresh(frm) {
frm.toggle_display('distribution_id', frm.doc.__islocal);
}
frm.toggle_display("distribution_id", frm.doc.__islocal);
},
});

View File

@@ -1,173 +1,77 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:distribution_id",
"beta": 0,
"creation": "2013-01-10 16:34:05",
"custom": 0,
"description": "**Monthly Distribution** helps you distribute the Budget/Target across months if you have seasonality in your business.",
"docstatus": 0,
"doctype": "DocType",
"editable_grid": 0,
"engine": "InnoDB",
"actions": [],
"autoname": "field:distribution_id",
"creation": "2013-01-10 16:34:05",
"description": "Helps you distribute the Budget/Target across months if you have seasonality in your business.",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"distribution_id",
"fiscal_year",
"percentages"
],
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Name of the Monthly Distribution",
"fieldname": "distribution_id",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Distribution Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "distribution_id",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"description": "Name of the Monthly Distribution",
"fieldname": "distribution_id",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Distribution Name",
"oldfieldname": "distribution_id",
"oldfieldtype": "Data",
"reqd": 1,
"unique": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fiscal_year",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Fiscal Year",
"length": 0,
"no_copy": 0,
"oldfieldname": "fiscal_year",
"oldfieldtype": "Select",
"options": "Fiscal Year",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
"fieldname": "fiscal_year",
"fieldtype": "Link",
"in_filter": 1,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Fiscal Year",
"oldfieldname": "fiscal_year",
"oldfieldtype": "Select",
"options": "Fiscal Year",
"search_index": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "percentages",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Monthly Distribution Percentages",
"length": 0,
"no_copy": 0,
"oldfieldname": "budget_distribution_details",
"oldfieldtype": "Table",
"options": "Monthly Distribution Percentage",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
"fieldname": "percentages",
"fieldtype": "Table",
"label": "Monthly Distribution Percentages",
"oldfieldname": "budget_distribution_details",
"oldfieldtype": "Table",
"options": "Monthly Distribution Percentage"
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-bar-chart",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-11-21 14:54:35.998761",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Monthly Distribution",
"name_case": "Title Case",
"owner": "Administrator",
],
"icon": "fa fa-bar-chart",
"idx": 1,
"links": [],
"modified": "2024-01-30 13:57:55.802744",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Monthly Distribution",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 2,
"print": 0,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"permlevel": 2,
"read": 1,
"report": 1,
"role": "Accounts Manager"
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@@ -1,48 +1,52 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Opening Invoice Creation Tool', {
setup: function(frm) {
frm.set_query('party_type', 'invoices', function(doc, cdt, cdn) {
frappe.ui.form.on("Opening Invoice Creation Tool", {
setup: function (frm) {
frm.set_query("party_type", "invoices", function (doc, cdt, cdn) {
return {
filters: {
'name': ['in', 'Customer, Supplier']
}
name: ["in", "Customer, Supplier"],
},
};
});
if (frm.doc.company) {
frm.trigger('setup_company_filters');
frm.trigger("setup_company_filters");
}
frappe.realtime.on('opening_invoice_creation_progress', data => {
frappe.realtime.on("opening_invoice_creation_progress", (data) => {
if (!frm.doc.import_in_progress) {
frm.dashboard.reset();
frm.doc.import_in_progress = true;
}
if (data.count == data.total) {
setTimeout(() => {
frm.doc.import_in_progress = false;
frm.clear_table("invoices");
frm.refresh_fields();
frm.page.clear_indicator();
frm.dashboard.hide_progress();
frappe.msgprint(__("Opening {0} Invoices created", [frm.doc.invoice_type]));
}, 1500, data.title);
setTimeout(
() => {
frm.doc.import_in_progress = false;
frm.clear_table("invoices");
frm.refresh_fields();
frm.page.clear_indicator();
frm.dashboard.hide_progress();
frappe.msgprint(__("Opening {0} Invoices created", [frm.doc.invoice_type]));
},
1500,
data.title
);
return;
}
frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message);
frm.page.set_indicator(__('In Progress'), 'orange');
frm.page.set_indicator(__("In Progress"), "orange");
});
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
refresh: function (frm) {
frm.disable_save();
!frm.doc.import_in_progress && frm.trigger("make_dashboard");
frm.page.set_primary_action(__('Create Invoices'), () => {
frm.page.set_primary_action(__("Create Invoices"), () => {
let btn_primary = frm.page.btn_primary.get(0);
return frm.call({
doc: frm.doc,
@@ -58,100 +62,98 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
}
},
setup_company_filters: function(frm) {
frm.set_query('cost_center', 'invoices', function(doc, cdt, cdn) {
setup_company_filters: function (frm) {
frm.set_query("cost_center", "invoices", function (doc, cdt, cdn) {
return {
filters: {
'company': doc.company
}
company: doc.company,
},
};
});
frm.set_query('cost_center', function(doc) {
frm.set_query("cost_center", function (doc) {
return {
filters: {
'company': doc.company
}
company: doc.company,
},
};
});
frm.set_query('temporary_opening_account', 'invoices', function(doc, cdt, cdn) {
frm.set_query("temporary_opening_account", "invoices", function (doc, cdt, cdn) {
return {
filters: {
'company': doc.company
}
}
company: doc.company,
},
};
});
},
company: function(frm) {
company: function (frm) {
if (frm.doc.company) {
frm.trigger('setup_company_filters');
frm.trigger("setup_company_filters");
frappe.call({
method: 'erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool.get_temporary_opening_account',
method: "erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool.get_temporary_opening_account",
args: {
company: frm.doc.company
company: frm.doc.company,
},
callback: (r) => {
if (r.message) {
frm.doc.__onload.temporary_opening_account = r.message;
frm.trigger('update_invoice_table');
frm.trigger("update_invoice_table");
}
}
})
},
});
}
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
invoice_type: function(frm) {
invoice_type: function (frm) {
$.each(frm.doc.invoices, (idx, row) => {
row.party_type = frm.doc.invoice_type == "Sales"? "Customer": "Supplier";
row.party_type = frm.doc.invoice_type == "Sales" ? "Customer" : "Supplier";
row.party = "";
});
frm.refresh_fields();
},
make_dashboard: function(frm) {
make_dashboard: function (frm) {
let max_count = frm.doc.__onload.max_count;
let opening_invoices_summary = frm.doc.__onload.opening_invoices_summary;
if(!$.isEmptyObject(opening_invoices_summary)) {
if (!$.isEmptyObject(opening_invoices_summary)) {
let section = frm.dashboard.add_section(
frappe.render_template('opening_invoice_creation_tool_dashboard', {
frappe.render_template("opening_invoice_creation_tool_dashboard", {
data: opening_invoices_summary,
max_count: max_count
max_count: max_count,
}),
__("Opening Invoices Summary")
);
section.on('click', '.invoice-link', function() {
let doctype = $(this).attr('data-type');
let company = $(this).attr('data-company');
frappe.set_route('List', doctype,
{'is_opening': 'Yes', 'company': company, 'docstatus': 1});
section.on("click", ".invoice-link", function () {
let doctype = $(this).attr("data-type");
let company = $(this).attr("data-company");
frappe.set_route("List", doctype, { is_opening: "Yes", company: company, docstatus: 1 });
});
frm.dashboard.show();
}
},
update_invoice_table: function(frm) {
update_invoice_table: function (frm) {
$.each(frm.doc.invoices, (idx, row) => {
if (!row.temporary_opening_account) {
row.temporary_opening_account = frm.doc.__onload.temporary_opening_account;
}
if(!row.cost_center) {
if (!row.cost_center) {
row.cost_center = frm.doc.cost_center;
}
row.party_type = frm.doc.invoice_type == "Sales"? "Customer": "Supplier";
row.party_type = frm.doc.invoice_type == "Sales" ? "Customer" : "Supplier";
});
}
},
});
frappe.ui.form.on('Opening Invoice Creation Tool Item', {
frappe.ui.form.on("Opening Invoice Creation Tool Item", {
invoices_add: (frm) => {
frm.trigger('update_invoice_table');
}
frm.trigger("update_invoice_table");
},
});

View File

@@ -1,33 +1,34 @@
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Party Link', {
refresh: function(frm) {
frm.set_query('primary_role', () => {
frappe.ui.form.on("Party Link", {
refresh: function (frm) {
frm.set_query("primary_role", () => {
return {
filters: {
name: ['in', ['Customer', 'Supplier']]
}
name: ["in", ["Customer", "Supplier"]],
},
};
});
frm.set_query('secondary_role', () => {
let party_types = Object.keys(frappe.boot.party_account_types)
.filter(p => p != frm.doc.primary_role);
frm.set_query("secondary_role", () => {
let party_types = Object.keys(frappe.boot.party_account_types).filter(
(p) => p != frm.doc.primary_role
);
return {
filters: {
name: ['in', party_types]
}
name: ["in", party_types],
},
};
});
},
primary_role(frm) {
frm.set_value('primary_party', '');
frm.set_value('secondary_role', '');
frm.set_value("primary_party", "");
frm.set_value("secondary_role", "");
},
secondary_role(frm) {
frm.set_value('secondary_party', '');
}
frm.set_value("secondary_party", "");
},
});

File diff suppressed because it is too large Load Diff

View File

@@ -87,12 +87,14 @@
"status",
"custom_remarks",
"remarks",
"base_in_words",
"column_break_16",
"letter_head",
"print_heading",
"bank",
"bank_account_no",
"payment_order",
"in_words",
"subscription_section",
"auto_repeat",
"amended_from",
@@ -747,6 +749,20 @@
"hidden": 1,
"label": "Book Advance Payments in Separate Party Account",
"read_only": 1
},
{
"fieldname": "base_in_words",
"fieldtype": "Small Text",
"label": "In Words (Company Currency)",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "in_words",
"fieldtype": "Small Text",
"label": "In Words",
"print_hide": 1,
"read_only": 1
}
],
"index_web_pages_for_search": 1,

View File

@@ -178,6 +178,7 @@ class PaymentEntry(AccountsController):
self.validate_paid_invoices()
self.ensure_supplier_is_not_blocked()
self.set_status()
self.set_total_in_words()
def on_submit(self):
if self.difference_amount:
@@ -470,7 +471,10 @@ class PaymentEntry(AccountsController):
)
def set_missing_ref_details(
self, force: bool = False, update_ref_details_only_for: list | None = None
self,
force: bool = False,
update_ref_details_only_for: list | None = None,
ref_exchange_rate: float | None = None,
) -> None:
for d in self.get("references"):
if d.allocated_amount:
@@ -483,6 +487,8 @@ class PaymentEntry(AccountsController):
ref_details = get_reference_details(
d.reference_doctype, d.reference_name, self.party_account_currency
)
if ref_exchange_rate:
ref_details.update({"exchange_rate": ref_exchange_rate})
for field, value in ref_details.items():
if d.exchange_gain_loss:
@@ -786,6 +792,21 @@ class PaymentEntry(AccountsController):
self.db_set("status", self.status, update_modified=True)
def set_total_in_words(self):
from frappe.utils import money_in_words
if self.payment_type in ("Pay", "Internal Transfer"):
base_amount = abs(self.base_paid_amount)
amount = abs(self.paid_amount)
currency = self.paid_from_account_currency
elif self.payment_type == "Receive":
base_amount = abs(self.base_received_amount)
amount = abs(self.received_amount)
currency = self.paid_to_account_currency
self.base_in_words = money_in_words(base_amount, self.company_currency)
self.in_words = money_in_words(amount, currency)
def set_tax_withholding(self):
if self.party_type != "Supplier":
return
@@ -927,8 +948,8 @@ class PaymentEntry(AccountsController):
def calculate_base_allocated_amount_for_reference(self, d) -> float:
base_allocated_amount = 0
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
"advance_payment_receivable_doctypes"
) + frappe.get_hooks("advance_payment_payable_doctypes")
if d.reference_doctype in advance_payment_doctypes:
# When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type.
# This is so there are no Exchange Gain/Loss generated for such doctypes
@@ -1016,19 +1037,19 @@ class PaymentEntry(AccountsController):
)
base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
if self.payment_type == "Receive":
self.difference_amount = base_party_amount - self.base_received_amount
elif self.payment_type == "Pay":
self.difference_amount = self.base_paid_amount - base_party_amount
else:
self.difference_amount = self.base_paid_amount - flt(self.base_received_amount)
total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
included_taxes = self.get_included_taxes()
if self.payment_type == "Receive":
self.difference_amount = base_party_amount - self.base_received_amount + included_taxes
elif self.payment_type == "Pay":
self.difference_amount = self.base_paid_amount - base_party_amount - included_taxes
else:
self.difference_amount = self.base_paid_amount - flt(self.base_received_amount) - included_taxes
total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
self.difference_amount = flt(
self.difference_amount - total_deductions - included_taxes, self.precision("difference_amount")
self.difference_amount - total_deductions, self.precision("difference_amount")
)
def get_included_taxes(self):
@@ -1250,7 +1271,13 @@ class PaymentEntry(AccountsController):
references = [x for x in self.get("references") if x.name == entry.name]
for ref in references:
if ref.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Journal Entry"):
if ref.reference_doctype in (
"Sales Invoice",
"Purchase Invoice",
"Journal Entry",
"Sales Order",
"Purchase Order",
):
self.add_advance_gl_for_reference(gl_entries, ref)
def add_advance_gl_for_reference(self, gl_entries, invoice):
@@ -1264,14 +1291,15 @@ class PaymentEntry(AccountsController):
"voucher_detail_no": invoice.name,
}
posting_date = frappe.db.get_value(
invoice.reference_doctype, invoice.reference_name, "posting_date"
)
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 = "credit" if invoice.reference_doctype == "Sales Invoice" else "debit"
dr_or_cr = "credit" if invoice.reference_doctype in ["Sales Invoice", "Sales Order"] else "debit"
args_dict["account"] = invoice.account
args_dict[dr_or_cr] = invoice.allocated_amount
args_dict[dr_or_cr + "_in_account_currency"] = invoice.allocated_amount
@@ -1428,8 +1456,8 @@ class PaymentEntry(AccountsController):
def update_advance_paid(self):
if self.payment_type in ("Receive", "Pay") and self.party:
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
"advance_payment_receivable_doctypes"
) + frappe.get_hooks("advance_payment_payable_doctypes")
for d in self.get("references"):
if d.allocated_amount and d.reference_doctype in advance_payment_doctypes:
frappe.get_doc(
@@ -2176,6 +2204,11 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
else:
outstanding_amount = flt(total_amount) - flt(ref_doc.get("advance_paid"))
if reference_doctype in ["Sales Order", "Purchase Order"]:
party_type = "Customer" if reference_doctype == "Sales Order" else "Supplier"
party_field = "customer" if reference_doctype == "Sales Order" else "supplier"
party = ref_doc.get(party_field)
account = get_party_account(party_type, party, ref_doc.company)
else:
# Get the exchange rate based on the posting date of the ref doc.
exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
@@ -2204,6 +2237,7 @@ def get_payment_entry(
party_type=None,
payment_type=None,
reference_date=None,
ignore_permissions=False,
):
doc = frappe.get_doc(dt, dn)
over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance")
@@ -2226,14 +2260,14 @@ def get_payment_entry(
)
# bank or cash
bank = get_bank_cash_account(doc, bank_account)
bank = get_bank_cash_account(doc, bank_account, ignore_permissions=ignore_permissions)
# if default bank or cash account is not set in company master and party has default company bank account, fetch it
if party_type in ["Customer", "Supplier"] and not bank:
party_bank_account = get_party_bank_account(party_type, doc.get(scrub(party_type)))
if party_bank_account:
account = frappe.db.get_value("Bank Account", party_bank_account, "account")
bank = get_bank_cash_account(doc, account)
bank = get_bank_cash_account(doc, account, ignore_permissions=ignore_permissions)
paid_amount, received_amount = set_paid_amount_and_received_amount(
dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc
@@ -2373,9 +2407,13 @@ def update_accounting_dimensions(pe, doc):
pe.set(dimension, doc.get(dimension))
def get_bank_cash_account(doc, bank_account):
def get_bank_cash_account(doc, bank_account, ignore_permissions=False):
bank = get_default_bank_cash_account(
doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"), account=bank_account
doc.company,
"Bank",
mode_of_payment=doc.get("mode_of_payment"),
account=bank_account,
ignore_permissions=ignore_permissions,
)
if not bank:

View File

@@ -1,14 +1,13 @@
frappe.listview_settings['Payment Entry'] = {
onload: function(listview) {
frappe.listview_settings["Payment Entry"] = {
onload: function (listview) {
if (listview.page.fields_dict.party_type) {
listview.page.fields_dict.party_type.get_query = function() {
listview.page.fields_dict.party_type.get_query = function () {
return {
"filters": {
"name": ["in", Object.keys(frappe.boot.party_account_types)],
}
filters: {
name: ["in", Object.keys(frappe.boot.party_account_types)],
},
};
};
}
}
},
};

View File

@@ -1070,6 +1070,8 @@ class TestPaymentEntry(FrappeTestCase):
self.assertRaises(frappe.ValidationError, pe_draft.submit)
def test_details_update_on_reference_table(self):
from erpnext.accounts.party import get_party_account
so = make_sales_order(
customer="_Test Customer USD", currency="USD", qty=1, rate=100, do_not_submit=True
)
@@ -1084,6 +1086,7 @@ class TestPaymentEntry(FrappeTestCase):
ref_details = get_reference_details(so.doctype, so.name, pe.paid_from_account_currency)
expected_response = {
"account": get_party_account("Customer", so.customer, so.company),
"total_amount": 5000.0,
"outstanding_amount": 5000.0,
"exchange_rate": 1.0,

View File

@@ -1,11 +1,11 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on('Payment Gateway Account', {
frappe.ui.form.on("Payment Gateway Account", {
refresh(frm) {
erpnext.utils.check_payments_app();
if(!frm.doc.__islocal) {
frm.set_df_property('payment_gateway', 'read_only', 1);
if (!frm.doc.__islocal) {
frm.set_df_property("payment_gateway", "read_only", 1);
}
}
},
});

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Payment Ledger Entry', {
frappe.ui.form.on("Payment Ledger Entry", {
// refresh: function(frm) {
// }
});

View File

@@ -1,61 +1,69 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Payment Order', {
setup: function(frm) {
frm.set_query("company_bank_account", function() {
frappe.ui.form.on("Payment Order", {
setup: function (frm) {
frm.set_query("company_bank_account", function () {
return {
filters: {
"is_company_account":1
}
}
is_company_account: 1,
},
};
});
frm.set_df_property('references', 'cannot_add_rows', true);
frm.set_df_property("references", "cannot_add_rows", true);
},
refresh: function(frm) {
refresh: function (frm) {
if (frm.doc.docstatus == 0) {
frm.add_custom_button(__('Payment Request'), function() {
frm.trigger("get_from_payment_request");
}, __("Get Payments from"));
frm.add_custom_button(
__("Payment Request"),
function () {
frm.trigger("get_from_payment_request");
},
__("Get Payments from")
);
frm.add_custom_button(__('Payment Entry'), function() {
frm.trigger("get_from_payment_entry");
}, __("Get Payments from"));
frm.add_custom_button(
__("Payment Entry"),
function () {
frm.trigger("get_from_payment_entry");
},
__("Get Payments from")
);
frm.trigger('remove_button');
frm.trigger("remove_button");
}
// payment Entry
if (frm.doc.docstatus===1 && frm.doc.payment_order_type==='Payment Request') {
frm.add_custom_button(__('Create Payment Entries'), function() {
if (frm.doc.docstatus === 1 && frm.doc.payment_order_type === "Payment Request") {
frm.add_custom_button(__("Create Payment Entries"), function () {
frm.trigger("make_payment_records");
});
}
},
remove_row_if_empty: function(frm) {
remove_row_if_empty: function (frm) {
// remove if first row is empty
if (frm.doc.references.length > 0 && !frm.doc.references[0].reference_name) {
frm.doc.references = [];
}
},
remove_button: function(frm) {
remove_button: function (frm) {
// remove custom button of order type that is not imported
let label = ["Payment Request", "Payment Entry"];
if (frm.doc.references.length > 0 && frm.doc.payment_order_type) {
label = label.reduce(x => {
x!= frm.doc.payment_order_type;
label = label.reduce((x) => {
x != frm.doc.payment_order_type;
return x;
});
frm.remove_custom_button(label, "Get from");
}
},
get_from_payment_entry: function(frm) {
get_from_payment_entry: function (frm) {
frm.trigger("remove_row_if_empty");
erpnext.utils.map_current_doc({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.make_payment_order",
@@ -63,7 +71,7 @@ frappe.ui.form.on('Payment Order', {
target: frm,
date_field: "posting_date",
setters: {
party: frm.doc.supplier || ""
party: frm.doc.supplier || "",
},
get_query_filters: {
bank: frm.doc.bank,
@@ -71,70 +79,79 @@ frappe.ui.form.on('Payment Order', {
payment_type: ["!=", "Receive"],
bank_account: frm.doc.company_bank_account,
paid_from: frm.doc.account,
payment_order_status: ["=", "Initiated"]
}
payment_order_status: ["=", "Initiated"],
},
});
},
get_from_payment_request: function(frm) {
get_from_payment_request: function (frm) {
frm.trigger("remove_row_if_empty");
erpnext.utils.map_current_doc({
method: "erpnext.accounts.doctype.payment_request.payment_request.make_payment_order",
source_doctype: "Payment Request",
target: frm,
setters: {
party: frm.doc.supplier || ""
party: frm.doc.supplier || "",
},
get_query_filters: {
bank: frm.doc.bank,
docstatus: 1,
status: ["=", "Initiated"],
}
},
});
},
make_payment_records: function(frm){
make_payment_records: function (frm) {
var dialog = new frappe.ui.Dialog({
title: __("For Supplier"),
fields: [
{"fieldtype": "Link", "label": __("Supplier"), "fieldname": "supplier", "options":"Supplier",
"get_query": function () {
{
fieldtype: "Link",
label: __("Supplier"),
fieldname: "supplier",
options: "Supplier",
get_query: function () {
return {
query:"erpnext.accounts.doctype.payment_order.payment_order.get_supplier_query",
filters: {'parent': frm.doc.name}
}
}, "reqd": 1
query: "erpnext.accounts.doctype.payment_order.payment_order.get_supplier_query",
filters: { parent: frm.doc.name },
};
},
reqd: 1,
},
{"fieldtype": "Link", "label": __("Mode of Payment"), "fieldname": "mode_of_payment", "options":"Mode of Payment",
"get_query": function () {
{
fieldtype: "Link",
label: __("Mode of Payment"),
fieldname: "mode_of_payment",
options: "Mode of Payment",
get_query: function () {
return {
query:"erpnext.accounts.doctype.payment_order.payment_order.get_mop_query",
filters: {'parent': frm.doc.name}
}
}
}
]
query: "erpnext.accounts.doctype.payment_order.payment_order.get_mop_query",
filters: { parent: frm.doc.name },
};
},
},
],
});
dialog.set_primary_action(__("Submit"), function() {
dialog.set_primary_action(__("Submit"), function () {
var args = dialog.get_values();
if(!args) return;
if (!args) return;
return frappe.call({
method: "erpnext.accounts.doctype.payment_order.payment_order.make_payment_records",
args: {
"name": frm.doc.name,
"supplier": args.supplier,
"mode_of_payment": args.mode_of_payment
name: frm.doc.name,
supplier: args.supplier,
mode_of_payment: args.mode_of_payment,
},
freeze: true,
callback: function(r) {
callback: function (r) {
dialog.hide();
frm.refresh();
}
})
})
},
});
});
dialog.show();
},

View File

@@ -4,9 +4,13 @@
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import getdate
from erpnext.accounts.doctype.bank_transaction.test_bank_transaction import create_bank_account
from erpnext.accounts.doctype.bank_transaction.test_bank_transaction import (
create_bank_account,
create_gl_account,
)
from erpnext.accounts.doctype.payment_entry.payment_entry import (
get_payment_entry,
make_payment_order,
@@ -14,28 +18,32 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import (
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
class TestPaymentOrder(unittest.TestCase):
class TestPaymentOrder(FrappeTestCase):
def setUp(self):
create_bank_account()
# generate and use a uniq hash identifier for 'Bank Account' and it's linked GL 'Account' to avoid validation error
uniq_identifier = frappe.generate_hash(length=10)
self.gl_account = create_gl_account("_Test Bank " + uniq_identifier)
self.bank_account = create_bank_account(
gl_account=self.gl_account, bank_account_name="Checking Account " + uniq_identifier
)
def tearDown(self):
for bt in frappe.get_all("Payment Order"):
doc = frappe.get_doc("Payment Order", bt.name)
doc.cancel()
doc.delete()
frappe.db.rollback()
def test_payment_order_creation_against_payment_entry(self):
purchase_invoice = make_purchase_invoice()
payment_entry = get_payment_entry(
"Purchase Invoice", purchase_invoice.name, bank_account="_Test Bank - _TC"
"Purchase Invoice", purchase_invoice.name, bank_account=self.gl_account
)
payment_entry.reference_no = "_Test_Payment_Order"
payment_entry.reference_date = getdate()
payment_entry.party_bank_account = "Checking Account - Citi Bank"
payment_entry.party_bank_account = self.bank_account
payment_entry.insert()
payment_entry.submit()
doc = create_payment_order_against_payment_entry(payment_entry, "Payment Entry")
doc = create_payment_order_against_payment_entry(
payment_entry, "Payment Entry", self.bank_account
)
reference_doc = doc.get("references")[0]
self.assertEqual(reference_doc.reference_name, payment_entry.name)
self.assertEqual(reference_doc.reference_doctype, "Payment Entry")
@@ -43,13 +51,13 @@ class TestPaymentOrder(unittest.TestCase):
self.assertEqual(reference_doc.amount, 250)
def create_payment_order_against_payment_entry(ref_doc, order_type):
def create_payment_order_against_payment_entry(ref_doc, order_type, bank_account):
payment_order = frappe.get_doc(
dict(
doctype="Payment Order",
company="_Test Company",
payment_order_type=order_type,
company_bank_account="Checking Account - Citi Bank",
company_bank_account=bank_account,
)
)
doc = make_payment_order(ref_doc.name, payment_order)

View File

@@ -2,97 +2,94 @@
// For license information, please see license.txt
frappe.provide("erpnext.accounts");
erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationController extends frappe.ui.form.Controller {
erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationController extends (
frappe.ui.form.Controller
) {
onload() {
const default_company = frappe.defaults.get_default('company');
this.frm.set_value('company', default_company);
const default_company = frappe.defaults.get_default("company");
this.frm.set_value("company", default_company);
this.frm.set_value('party_type', '');
this.frm.set_value('party', '');
this.frm.set_value('receivable_payable_account', '');
this.frm.set_value("party_type", "");
this.frm.set_value("party", "");
this.frm.set_value("receivable_payable_account", "");
this.frm.set_query("party_type", () => {
return {
"filters": {
"name": ["in", Object.keys(frappe.boot.party_account_types)],
}
}
});
this.frm.set_query('receivable_payable_account', () => {
return {
filters: {
"company": this.frm.doc.company,
"is_group": 0,
"account_type": frappe.boot.party_account_types[this.frm.doc.party_type],
"root_type": this.frm.doc.party_type == 'Customer' ? "Asset" : "Liability"
}
name: ["in", Object.keys(frappe.boot.party_account_types)],
},
};
});
this.frm.set_query('default_advance_account', () => {
this.frm.set_query("receivable_payable_account", () => {
return {
filters: {
"company": this.frm.doc.company,
"is_group": 0,
"account_type": this.frm.doc.party_type == 'Customer' ? "Receivable": "Payable",
"root_type": this.frm.doc.party_type == 'Customer' ? "Liability": "Asset"
}
company: this.frm.doc.company,
is_group: 0,
account_type: frappe.boot.party_account_types[this.frm.doc.party_type],
root_type: this.frm.doc.party_type == "Customer" ? "Asset" : "Liability",
},
};
});
this.frm.set_query('bank_cash_account', () => {
this.frm.set_query("default_advance_account", () => {
return {
filters:[
['Account', 'company', '=', this.frm.doc.company],
['Account', 'is_group', '=', 0],
['Account', 'account_type', 'in', ['Bank', 'Cash']]
]
filters: {
company: this.frm.doc.company,
is_group: 0,
account_type: this.frm.doc.party_type == "Customer" ? "Receivable" : "Payable",
root_type: this.frm.doc.party_type == "Customer" ? "Liability" : "Asset",
},
};
});
this.frm.set_query("bank_cash_account", () => {
return {
filters: [
["Account", "company", "=", this.frm.doc.company],
["Account", "is_group", "=", 0],
["Account", "account_type", "in", ["Bank", "Cash"]],
],
};
});
this.frm.set_query("cost_center", () => {
return {
"filters": {
"company": this.frm.doc.company,
"is_group": 0
}
}
filters: {
company: this.frm.doc.company,
is_group: 0,
},
};
});
}
refresh() {
this.frm.disable_save();
this.frm.set_df_property('invoices', 'cannot_delete_rows', true);
this.frm.set_df_property('payments', 'cannot_delete_rows', true);
this.frm.set_df_property('allocation', 'cannot_delete_rows', true);
this.frm.set_df_property('invoices', 'cannot_add_rows', true);
this.frm.set_df_property('payments', 'cannot_add_rows', true);
this.frm.set_df_property('allocation', 'cannot_add_rows', true);
this.frm.set_df_property("invoices", "cannot_delete_rows", true);
this.frm.set_df_property("payments", "cannot_delete_rows", true);
this.frm.set_df_property("allocation", "cannot_delete_rows", true);
this.frm.set_df_property("invoices", "cannot_add_rows", true);
this.frm.set_df_property("payments", "cannot_add_rows", true);
this.frm.set_df_property("allocation", "cannot_add_rows", true);
if (this.frm.doc.receivable_payable_account) {
this.frm.add_custom_button(__('Get Unreconciled Entries'), () =>
this.frm.add_custom_button(__("Get Unreconciled Entries"), () =>
this.frm.trigger("get_unreconciled_entries")
);
this.frm.change_custom_button_type(__('Get Unreconciled Entries'), null, 'primary');
this.frm.change_custom_button_type(__("Get Unreconciled Entries"), null, "primary");
}
if (this.frm.doc.invoices.length && this.frm.doc.payments.length) {
this.frm.add_custom_button(__('Allocate'), () =>
this.frm.trigger("allocate")
);
this.frm.change_custom_button_type(__('Allocate'), null, 'primary');
this.frm.change_custom_button_type(__('Get Unreconciled Entries'), null, 'default');
this.frm.add_custom_button(__("Allocate"), () => this.frm.trigger("allocate"));
this.frm.change_custom_button_type(__("Allocate"), null, "primary");
this.frm.change_custom_button_type(__("Get Unreconciled Entries"), null, "default");
}
if (this.frm.doc.allocation.length) {
this.frm.add_custom_button(__('Reconcile'), () =>
this.frm.trigger("reconcile")
);
this.frm.change_custom_button_type(__('Reconcile'), null, 'primary');
this.frm.change_custom_button_type(__('Get Unreconciled Entries'), null, 'default');
this.frm.change_custom_button_type(__('Allocate'), null, 'default');
this.frm.add_custom_button(__("Reconcile"), () => this.frm.trigger("reconcile"));
this.frm.change_custom_button_type(__("Reconcile"), null, "primary");
this.frm.change_custom_button_type(__("Get Unreconciled Entries"), null, "default");
this.frm.change_custom_button_type(__("Allocate"), null, "default");
}
this.frm.trigger("set_query_for_dimension_filters");
@@ -101,31 +98,39 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
if (this.frm.doc.receivable_payable_account) {
this.frm.call({
doc: this.frm.doc,
method: 'is_auto_process_enabled',
method: "is_auto_process_enabled",
callback: (r) => {
if (r.message) {
this.frm.call({
'method': "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.is_any_doc_running",
"args": {
for_filter: {
company: this.frm.doc.company,
party_type: this.frm.doc.party_type,
party: this.frm.doc.party,
receivable_payable_account: this.frm.doc.receivable_payable_account
this.frm
.call({
method: "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.is_any_doc_running",
args: {
for_filter: {
company: this.frm.doc.company,
party_type: this.frm.doc.party_type,
party: this.frm.doc.party,
receivable_payable_account: this.frm.doc.receivable_payable_account,
},
},
})
.then((r) => {
if (r.message) {
let doc_link = frappe.utils.get_form_link(
"Process Payment Reconciliation",
r.message,
true
);
let msg = __(
"Payment Reconciliation Job: {0} is running for this party. Can't reconcile now.",
[doc_link]
);
this.frm.dashboard.add_comment(msg, "yellow");
}
}
}).then(r => {
if (r.message) {
let doc_link = frappe.utils.get_form_link("Process Payment Reconciliation", r.message, true);
let msg = __("Payment Reconciliation Job: {0} is running for this party. Can't reconcile now.", [doc_link]);
this.frm.dashboard.add_comment(msg, "yellow");
}
});
});
}
}
},
});
}
}
set_query_for_dimension_filters() {
frappe.call({
@@ -135,29 +140,29 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
},
callback: (r) => {
if (!r.exc && r.message) {
r.message.forEach(x => {
r.message.forEach((x) => {
this.frm.set_query(x.fieldname, () => {
return {
'filters': x.filters
filters: x.filters,
};
});
});
}
}
},
});
}
company() {
this.frm.set_value('party', '');
this.frm.set_value('receivable_payable_account', '');
this.frm.set_value("party", "");
this.frm.set_value("receivable_payable_account", "");
}
party_type() {
this.frm.set_value('party', '');
this.frm.set_value("party", "");
}
party() {
this.frm.set_value('receivable_payable_account', '');
this.frm.set_value("receivable_payable_account", "");
this.frm.trigger("clear_child_tables");
if (!this.frm.doc.receivable_payable_account && this.frm.doc.party_type && this.frm.doc.party) {
@@ -167,7 +172,7 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
company: this.frm.doc.company,
party_type: this.frm.doc.party_type,
party: this.frm.doc.party,
include_advance: 1
include_advance: 1,
},
callback: (r) => {
if (!r.exc && r.message) {
@@ -175,7 +180,7 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
this.frm.set_value("default_advance_account", r.message[1]);
}
this.frm.refresh();
}
},
});
}
}
@@ -193,7 +198,6 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
this.frm.trigger("get_unreconciled_entries");
}
clear_child_tables() {
this.frm.clear_table("invoices");
this.frm.clear_table("payments");
@@ -205,52 +209,52 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
this.frm.clear_table("allocation");
return this.frm.call({
doc: this.frm.doc,
method: 'get_unreconciled_entries',
method: "get_unreconciled_entries",
callback: () => {
if (!(this.frm.doc.payments.length || this.frm.doc.invoices.length)) {
frappe.throw({message: __("No Unreconciled Invoices and Payments found for this party and account")});
} else if (!(this.frm.doc.invoices.length)) {
frappe.throw({message: __("No Outstanding Invoices found for this party")});
} else if (!(this.frm.doc.payments.length)) {
frappe.throw({message: __("No Unreconciled Payments found for this party")});
frappe.throw({
message: __("No Unreconciled Invoices and Payments found for this party and account"),
});
} else if (!this.frm.doc.invoices.length) {
frappe.throw({ message: __("No Outstanding Invoices found for this party") });
} else if (!this.frm.doc.payments.length) {
frappe.throw({ message: __("No Unreconciled Payments found for this party") });
}
this.frm.refresh();
}
},
});
}
allocate() {
let payments = this.frm.fields_dict.payments.grid.get_selected_children();
if (!(payments.length)) {
if (!payments.length) {
payments = this.frm.doc.payments;
}
let invoices = this.frm.fields_dict.invoices.grid.get_selected_children();
if (!(invoices.length)) {
if (!invoices.length) {
invoices = this.frm.doc.invoices;
}
return this.frm.call({
doc: this.frm.doc,
method: 'allocate_entries',
method: "allocate_entries",
args: {
payments: payments,
invoices: invoices
invoices: invoices,
},
callback: () => {
this.frm.refresh();
}
},
});
}
reconcile() {
var show_dialog = this.frm.doc.allocation.filter(d => d.difference_amount);
var show_dialog = this.frm.doc.allocation.filter((d) => d.difference_amount);
if (show_dialog && show_dialog.length) {
this.data = [];
const dialog = new frappe.ui.Dialog({
title: __("Select Difference Account"),
size: 'extra-large',
size: "extra-large",
fields: [
{
fieldname: "allocation",
@@ -262,77 +266,89 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
get_data: () => {
return this.data;
},
fields: [{
fieldtype:'Data',
fieldname:"docname",
in_list_view: 1,
hidden: 1
}, {
fieldtype:'Data',
fieldname:"reference_name",
label: __("Voucher No"),
in_list_view: 1,
read_only: 1
}, {
fieldtype:'Date',
fieldname:"gain_loss_posting_date",
label: __("Posting Date"),
in_list_view: 1,
reqd: 1,
}, {
fieldtype:'Link',
options: 'Account',
in_list_view: 1,
label: __("Difference Account"),
fieldname: 'difference_account',
reqd: 1,
get_query: () => {
return {
filters: {
company: this.frm.doc.company,
is_group: 0
}
}
}
}, {
fieldtype:'Currency',
in_list_view: 1,
label: __("Difference Amount"),
fieldname: 'difference_amount',
read_only: 1
}]
fields: [
{
fieldtype: "Data",
fieldname: "docname",
in_list_view: 1,
hidden: 1,
},
{
fieldtype: "Data",
fieldname: "reference_name",
label: __("Voucher No"),
in_list_view: 1,
read_only: 1,
},
{
fieldtype: "Date",
fieldname: "gain_loss_posting_date",
label: __("Posting Date"),
in_list_view: 1,
reqd: 1,
},
{
fieldtype: "Link",
options: "Account",
in_list_view: 1,
label: __("Difference Account"),
fieldname: "difference_account",
reqd: 1,
get_query: () => {
return {
filters: {
company: this.frm.doc.company,
is_group: 0,
},
};
},
},
{
fieldtype: "Currency",
in_list_view: 1,
label: __("Difference Amount"),
fieldname: "difference_amount",
read_only: 1,
},
],
},
{
fieldtype: 'HTML',
options: "<b> New Journal Entry will be posted for the difference amount </b>"
}
fieldtype: "HTML",
options: "<b> New Journal Entry will be posted for the difference amount </b>",
},
],
primary_action: () => {
const args = dialog.get_values()["allocation"];
args.forEach(d => {
frappe.model.set_value("Payment Reconciliation Allocation", d.docname,
"difference_account", d.difference_account);
frappe.model.set_value("Payment Reconciliation Allocation", d.docname,
"gain_loss_posting_date", d.gain_loss_posting_date);
args.forEach((d) => {
frappe.model.set_value(
"Payment Reconciliation Allocation",
d.docname,
"difference_account",
d.difference_account
);
frappe.model.set_value(
"Payment Reconciliation Allocation",
d.docname,
"gain_loss_posting_date",
d.gain_loss_posting_date
);
});
this.reconcile_payment_entries();
dialog.hide();
},
primary_action_label: __('Reconcile Entries')
primary_action_label: __("Reconcile Entries"),
});
this.frm.doc.allocation.forEach(d => {
this.frm.doc.allocation.forEach((d) => {
if (d.difference_amount) {
dialog.fields_dict.allocation.df.data.push({
'docname': d.name,
'reference_name': d.reference_name,
'difference_amount': d.difference_amount,
'difference_account': d.difference_account,
'gain_loss_posting_date': d.gain_loss_posting_date
docname: d.name,
reference_name: d.reference_name,
difference_amount: d.difference_amount,
difference_account: d.difference_account,
gain_loss_posting_date: d.gain_loss_posting_date,
});
}
});
@@ -348,41 +364,39 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
reconcile_payment_entries() {
return this.frm.call({
doc: this.frm.doc,
method: 'reconcile',
method: "reconcile",
callback: () => {
this.frm.clear_table("allocation");
this.frm.refresh();
}
},
});
}
};
frappe.ui.form.on('Payment Reconciliation Allocation', {
allocated_amount: function(frm, cdt, cdn) {
frappe.ui.form.on("Payment Reconciliation Allocation", {
allocated_amount: function (frm, cdt, cdn) {
let row = locals[cdt][cdn];
// filter invoice
let invoice = frm.doc.invoices.filter((x) => (x.invoice_number == row.invoice_number));
let invoice = frm.doc.invoices.filter((x) => x.invoice_number == row.invoice_number);
// filter payment
let payment = frm.doc.payments.filter((x) => (x.reference_name == row.reference_name));
let payment = frm.doc.payments.filter((x) => x.reference_name == row.reference_name);
frm.call({
doc: frm.doc,
method: 'calculate_difference_on_allocation_change',
method: "calculate_difference_on_allocation_change",
args: {
payment_entry: payment,
invoice: invoice,
allocated_amount: row.allocated_amount
allocated_amount: row.allocated_amount,
},
callback: (r) => {
if (r.message) {
row.difference_amount = r.message;
frm.refresh();
}
}
},
});
}
},
});
extend_cscript(cur_frm.cscript, new erpnext.accounts.PaymentReconciliationController({frm: cur_frm}));
extend_cscript(cur_frm.cscript, new erpnext.accounts.PaymentReconciliationController({ frm: cur_frm }));

View File

@@ -41,6 +41,7 @@
{
"fieldname": "company",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Company",
"options": "Company",
"reqd": 1
@@ -229,7 +230,7 @@
"is_virtual": 1,
"issingle": 1,
"links": [],
"modified": "2023-12-14 13:38:16.264013",
"modified": "2024-01-18 11:56:20.234667",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation",

View File

@@ -633,7 +633,12 @@ class PaymentReconciliation(Document):
journals_map = frappe._dict(
frappe.db.get_all(
"Journal Entry Account",
filters={"parent": ("in", journals), "account": ("in", [self.receivable_payable_account])},
filters={
"parent": ("in", journals),
"account": ("in", [self.receivable_payable_account]),
"party_type": self.party_type,
"party": self.party,
},
fields=[
"parent as `name`",
"exchange_rate",

View File

@@ -56,6 +56,7 @@ class TestPaymentReconciliation(FrappeTestCase):
self.expense_account = "Cost of Goods Sold - _PR"
self.debit_to = "Debtors - _PR"
self.creditors = "Creditors - _PR"
self.cash = "Cash - _PR"
# create bank account
if frappe.db.exists("Account", "HDFC - _PR"):
@@ -486,6 +487,91 @@ class TestPaymentReconciliation(FrappeTestCase):
self.assertEqual(len(pr.get("invoices")), 0)
self.assertEqual(len(pr.get("payments")), 0)
def test_payment_against_foreign_currency_journal(self):
transaction_date = nowdate()
self.supplier = "_Test Supplier USD"
self.supplier2 = make_supplier("_Test Supplier2 USD", "USD")
amount = 100
exc_rate1 = 80
exc_rate2 = 83
je = frappe.new_doc("Journal Entry")
je.posting_date = transaction_date
je.company = self.company
je.user_remark = "test"
je.multi_currency = 1
je.set(
"accounts",
[
{
"account": self.creditors_usd,
"party_type": "Supplier",
"party": self.supplier,
"exchange_rate": exc_rate1,
"cost_center": self.cost_center,
"credit": amount * exc_rate1,
"credit_in_account_currency": amount,
},
{
"account": self.creditors_usd,
"party_type": "Supplier",
"party": self.supplier2,
"exchange_rate": exc_rate2,
"cost_center": self.cost_center,
"credit": amount * exc_rate2,
"credit_in_account_currency": amount,
},
{
"account": self.expense_account,
"cost_center": self.cost_center,
"debit": (amount * exc_rate1) + (amount * exc_rate2),
"debit_in_account_currency": (amount * exc_rate1) + (amount * exc_rate2),
},
],
)
je.save().submit()
pe = self.create_payment_entry(amount=amount, posting_date=transaction_date)
pe.payment_type = "Pay"
pe.party_type = "Supplier"
pe.party = self.supplier
pe.paid_to = self.creditors_usd
pe.paid_from = self.cash
pe.paid_amount = 8000
pe.received_amount = 100
pe.target_exchange_rate = exc_rate1
pe.paid_to_account_currency = "USD"
pe.save().submit()
pr = self.create_payment_reconciliation(party_is_customer=False)
pr.receivable_payable_account = self.creditors_usd
pr.minimum_invoice_amount = pr.maximum_invoice_amount = amount
pr.from_invoice_date = pr.to_invoice_date = transaction_date
pr.from_payment_date = pr.to_payment_date = transaction_date
pr.get_unreconciled_entries()
invoices = [x.as_dict() for x in pr.get("invoices")]
payments = [x.as_dict() for x in pr.get("payments")]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
# There should no difference_amount as the Journal and Payment have same exchange rate - 'exc_rate1'
for row in pr.allocation:
self.assertEqual(flt(row.get("difference_amount")), 0.0)
pr.reconcile()
# check PR tool output
self.assertEqual(len(pr.get("invoices")), 0)
self.assertEqual(len(pr.get("payments")), 0)
journals = frappe.db.get_all(
"Journal Entry Account",
filters={"reference_type": je.doctype, "reference_name": je.name, "docstatus": 1},
fields=["parent"],
)
self.assertEqual([], journals)
def test_journal_against_invoice(self):
transaction_date = nowdate()
amount = 100
@@ -591,6 +677,70 @@ class TestPaymentReconciliation(FrappeTestCase):
self.assertEqual(si.status, "Paid")
self.assertEqual(si.outstanding_amount, 0)
def test_invoice_status_after_cr_note_cancellation(self):
# This test case is made after the 'always standalone Credit/Debit notes' feature is introduced
transaction_date = nowdate()
amount = 100
si = 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.return_against = si.name
cr_note = cr_note.save().submit()
pr = self.create_payment_reconciliation()
pr.get_unreconciled_entries()
invoices = [x.as_dict() for x in pr.get("invoices")]
payments = [x.as_dict() for x in pr.get("payments")]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.reconcile()
pr.get_unreconciled_entries()
self.assertEqual(pr.get("invoices"), [])
self.assertEqual(pr.get("payments"), [])
journals = frappe.db.get_all(
"Journal Entry",
filters={
"is_system_generated": 1,
"docstatus": 1,
"voucher_type": "Credit Note",
"reference_type": si.doctype,
"reference_name": si.name,
},
pluck="name",
)
self.assertEqual(len(journals), 1)
# assert status and outstanding
si.reload()
self.assertEqual(si.status, "Credit Note Issued")
self.assertEqual(si.outstanding_amount, 0)
cr_note.reload()
cr_note.cancel()
# 'Credit Note' Journal should be auto cancelled
journals = frappe.db.get_all(
"Journal Entry",
filters={
"is_system_generated": 1,
"docstatus": 1,
"voucher_type": "Credit Note",
"reference_type": si.doctype,
"reference_name": si.name,
},
pluck="name",
)
self.assertEqual(len(journals), 0)
# assert status and outstanding
si.reload()
self.assertEqual(si.status, "Unpaid")
self.assertEqual(si.outstanding_amount, 100)
def test_cr_note_partial_against_invoice(self):
transaction_date = nowdate()
amount = 100
@@ -1184,3 +1334,17 @@ def make_customer(customer_name, currency=None):
return customer.name
else:
return customer_name
def make_supplier(supplier_name, currency=None):
if not frappe.db.exists("Supplier", supplier_name):
supplier = frappe.new_doc("Supplier")
supplier.supplier_name = supplier_name
supplier.type = "Individual"
if currency:
supplier.default_currency = currency
supplier.save()
return supplier.name
else:
return supplier_name

View File

@@ -1,83 +1,99 @@
cur_frm.add_fetch("payment_gateway_account", "payment_account", "payment_account")
cur_frm.add_fetch("payment_gateway_account", "payment_gateway", "payment_gateway")
cur_frm.add_fetch("payment_gateway_account", "message", "message")
cur_frm.add_fetch("payment_gateway_account", "payment_account", "payment_account");
cur_frm.add_fetch("payment_gateway_account", "payment_gateway", "payment_gateway");
cur_frm.add_fetch("payment_gateway_account", "message", "message");
frappe.ui.form.on("Payment Request", {
setup: function(frm) {
frm.set_query("party_type", function() {
setup: function (frm) {
frm.set_query("party_type", function () {
return {
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
};
});
}
})
},
});
frappe.ui.form.on("Payment Request", "onload", function(frm, dt, dn){
frappe.ui.form.on("Payment Request", "onload", function (frm, dt, dn) {
if (frm.doc.reference_doctype) {
frappe.call({
method:"erpnext.accounts.doctype.payment_request.payment_request.get_print_format_list",
args: {"ref_doctype": frm.doc.reference_doctype},
callback:function(r){
set_field_options("print_format", r.message["print_format"])
}
})
method: "erpnext.accounts.doctype.payment_request.payment_request.get_print_format_list",
args: { ref_doctype: frm.doc.reference_doctype },
callback: function (r) {
set_field_options("print_format", r.message["print_format"]);
},
});
}
})
});
frappe.ui.form.on("Payment Request", "refresh", function(frm) {
if(frm.doc.payment_request_type == 'Inward' && frm.doc.payment_channel !== "Phone" &&
!in_list(["Initiated", "Paid"], frm.doc.status) && !frm.doc.__islocal && frm.doc.docstatus==1){
frm.add_custom_button(__('Resend Payment Email'), function(){
frappe.ui.form.on("Payment Request", "refresh", function (frm) {
if (frm.doc.status == "Failed") {
frm.set_intro(__("Failure: {0}", [frm.doc.failed_reason]), "red");
}
if (
frm.doc.payment_request_type == "Inward" &&
frm.doc.payment_channel !== "Phone" &&
!in_list(["Initiated", "Paid"], frm.doc.status) &&
!frm.doc.__islocal &&
frm.doc.docstatus == 1
) {
frm.add_custom_button(__("Resend Payment Email"), function () {
frappe.call({
method: "erpnext.accounts.doctype.payment_request.payment_request.resend_payment_email",
args: {"docname": frm.doc.name},
args: { docname: frm.doc.name },
freeze: true,
freeze_message: __("Sending"),
callback: function(r){
if(!r.exc) {
callback: function (r) {
if (!r.exc) {
frappe.msgprint(__("Message Sent"));
}
}
},
});
});
}
if((!frm.doc.payment_gateway_account || frm.doc.payment_request_type == "Outward") && frm.doc.status == "Initiated") {
frm.add_custom_button(__('Create Payment Entry'), function(){
if (
(!frm.doc.payment_gateway_account || frm.doc.payment_request_type == "Outward") &&
frm.doc.status == "Initiated"
) {
frm.add_custom_button(__("Create Payment Entry"), function () {
frappe.call({
method: "erpnext.accounts.doctype.payment_request.payment_request.make_payment_entry",
args: {"docname": frm.doc.name},
args: { docname: frm.doc.name },
freeze: true,
callback: function(r){
if(!r.exc) {
callback: function (r) {
if (!r.exc) {
var doc = frappe.model.sync(r.message);
frappe.set_route("Form", r.message.doctype, r.message.name);
}
}
},
});
}).addClass("btn-primary");
}
});
frappe.ui.form.on("Payment Request", "is_a_subscription", function(frm) {
frappe.ui.form.on("Payment Request", "is_a_subscription", function (frm) {
frm.toggle_reqd("payment_gateway_account", frm.doc.is_a_subscription);
frm.toggle_reqd("subscription_plans", frm.doc.is_a_subscription);
if (frm.doc.is_a_subscription && frm.doc.reference_doctype && frm.doc.reference_name) {
frappe.call({
method: "erpnext.accounts.doctype.payment_request.payment_request.get_subscription_details",
args: {"reference_doctype": frm.doc.reference_doctype, "reference_name": frm.doc.reference_name},
args: { reference_doctype: frm.doc.reference_doctype, reference_name: frm.doc.reference_name },
freeze: true,
callback: function(data){
if(!data.exc) {
$.each(data.message || [], function(i, v){
var d = frappe.model.add_child(frm.doc, "Subscription Plan Detail", "subscription_plans");
callback: function (data) {
if (!data.exc) {
$.each(data.message || [], function (i, v) {
var d = frappe.model.add_child(
frm.doc,
"Subscription Plan Detail",
"subscription_plans"
);
d.qty = v.qty;
d.plan = v.plan;
});
frm.refresh_field("subscription_plans");
}
}
},
});
}
});

View File

@@ -7,6 +7,7 @@
"field_order": [
"payment_request_type",
"transaction_date",
"failed_reason",
"column_break_2",
"naming_series",
"mode_of_payment",
@@ -389,13 +390,22 @@
"options": "Payment Request",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "failed_reason",
"fieldtype": "Data",
"hidden": 1,
"label": "Reason for Failure",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-09-27 09:51:42.277638",
"modified": "2024-01-20 00:37:06.988919",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",
@@ -433,4 +443,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -3,6 +3,7 @@ import json
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.query_builder.functions import Sum
from frappe.utils import flt, nowdate
from frappe.utils.background_jobs import enqueue
@@ -106,6 +107,8 @@ class PaymentRequest(Document):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if not hasattr(ref_doc, "order_type") or getattr(ref_doc, "order_type") != "Shopping Cart":
ref_amount = get_amount(ref_doc, self.payment_account)
if not ref_amount:
frappe.throw(_("Payment Entry is already created"))
if existing_payment_request_amount + flt(self.grand_total) > ref_amount:
frappe.throw(
@@ -170,8 +173,8 @@ class PaymentRequest(Document):
self.request_phone_payment()
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
"advance_payment_receivable_doctypes"
) + frappe.get_hooks("advance_payment_payable_doctypes")
if self.reference_doctype in advance_payment_doctypes:
# set advance payment status
ref_doc.set_total_advance_paid()
@@ -216,8 +219,8 @@ class PaymentRequest(Document):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
"advance_payment_receivable_doctypes"
) + frappe.get_hooks("advance_payment_payable_doctypes")
if self.reference_doctype in advance_payment_doctypes:
# set advance payment status
ref_doc.set_total_advance_paid()
@@ -453,6 +456,8 @@ def make_payment_request(**args):
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":
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
@@ -543,6 +548,7 @@ def get_amount(ref_doc, payment_account=None):
dt = ref_doc.doctype
if dt in ["Sales Order", "Purchase Order"]:
grand_total = flt(ref_doc.rounded_total) or flt(ref_doc.grand_total)
grand_total -= get_paid_amount_against_order(dt, ref_doc.name)
elif dt in ["Sales Invoice", "Purchase Invoice"]:
if not ref_doc.get("is_pos"):
if ref_doc.party_account_currency == ref_doc.currency:
@@ -562,10 +568,7 @@ def get_amount(ref_doc, payment_account=None):
elif dt == "Fees":
grand_total = ref_doc.outstanding_amount
if grand_total > 0:
return grand_total
else:
frappe.throw(_("Payment Entry is already created"))
return grand_total
def get_existing_payment_request_amount(ref_dt, ref_dn):
@@ -748,3 +751,27 @@ def validate_payment(doc, method=None):
doc.reference_docname
)
)
def get_paid_amount_against_order(dt, dn):
pe_ref = frappe.qb.DocType("Payment Entry Reference")
if dt == "Sales Order":
inv_dt, inv_field = "Sales Invoice Item", "sales_order"
else:
inv_dt, inv_field = "Purchase Invoice Item", "purchase_order"
inv_item = frappe.qb.DocType(inv_dt)
return (
frappe.qb.from_(pe_ref)
.select(
Sum(pe_ref.allocated_amount),
)
.where(
(pe_ref.docstatus == 1)
& (
(pe_ref.reference_name == dn)
| pe_ref.reference_name.isin(
frappe.qb.from_(inv_item).select(inv_item.parent).where(inv_item[inv_field] == dn).distinct()
)
)
)
).run()[0][0] or 0

View File

@@ -1,23 +1,21 @@
frappe.listview_settings['Payment Request'] = {
frappe.listview_settings["Payment Request"] = {
add_fields: ["status"],
get_indicator: function(doc) {
if(doc.status == "Draft") {
get_indicator: function (doc) {
if (doc.status == "Draft") {
return [__("Draft"), "gray", "status,=,Draft"];
}
if(doc.status == "Requested") {
if (doc.status == "Requested") {
return [__("Requested"), "green", "status,=,Requested"];
}
else if(doc.status == "Initiated") {
} else if (doc.status == "Initiated") {
return [__("Initiated"), "green", "status,=,Initiated"];
}
else if(doc.status == "Partially Paid") {
} else if (doc.status == "Partially Paid") {
return [__("Partially Paid"), "orange", "status,=,Partially Paid"];
}
else if(doc.status == "Paid") {
} else if (doc.status == "Paid") {
return [__("Paid"), "blue", "status,=,Paid"];
}
else if(doc.status == "Cancelled") {
} else if (doc.status == "Failed") {
return [__("Failed"), "red", "status,=,Failed"];
} else if (doc.status == "Cancelled") {
return [__("Cancelled"), "red", "status,=,Cancelled"];
}
}
}
},
};

View File

@@ -1,22 +1,24 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Payment Term', {
frappe.ui.form.on("Payment Term", {
onload(frm) {
frm.trigger('set_dynamic_description');
frm.trigger("set_dynamic_description");
},
discount(frm) {
frm.trigger('set_dynamic_description');
frm.trigger("set_dynamic_description");
},
discount_type(frm) {
frm.trigger('set_dynamic_description');
frm.trigger("set_dynamic_description");
},
set_dynamic_description(frm) {
if (frm.doc.discount) {
let description = __("{0}% of total invoice value will be given as discount.", [frm.doc.discount]);
if (frm.doc.discount_type == 'Amount') {
let description = __("{0}% of total invoice value will be given as discount.", [
frm.doc.discount,
]);
if (frm.doc.discount_type == "Amount") {
description = __("{0} will be given as discount.", [frm.doc.discount]);
}
frm.set_df_property("discount", "description", description);
}
}
},
});

View File

@@ -1,12 +1,18 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Payment Terms Template', {
refresh: function(frm) {
frm.fields_dict.terms.grid.toggle_reqd("payment_term", frm.doc.allocate_payment_based_on_payment_terms);
frappe.ui.form.on("Payment Terms Template", {
refresh: function (frm) {
frm.fields_dict.terms.grid.toggle_reqd(
"payment_term",
frm.doc.allocate_payment_based_on_payment_terms
);
},
allocate_payment_based_on_payment_terms: function(frm) {
frm.fields_dict.terms.grid.toggle_reqd("payment_term", frm.doc.allocate_payment_based_on_payment_terms);
}
allocate_payment_based_on_payment_terms: function (frm) {
frm.fields_dict.terms.grid.toggle_reqd(
"payment_term",
frm.doc.allocate_payment_based_on_payment_terms
);
},
});

View File

@@ -1,38 +1,41 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on('Period Closing Voucher', {
onload: function(frm) {
frappe.ui.form.on("Period Closing Voucher", {
onload: function (frm) {
if (!frm.doc.transaction_date) frm.doc.transaction_date = frappe.datetime.obj_to_str(new Date());
},
setup: function(frm) {
frm.set_query("closing_account_head", function() {
setup: function (frm) {
frm.set_query("closing_account_head", function () {
return {
filters: [
['Account', 'company', '=', frm.doc.company],
['Account', 'is_group', '=', '0'],
['Account', 'freeze_account', '=', 'No'],
['Account', 'root_type', 'in', 'Liability, Equity']
]
}
["Account", "company", "=", frm.doc.company],
["Account", "is_group", "=", "0"],
["Account", "freeze_account", "=", "No"],
["Account", "root_type", "in", "Liability, Equity"],
],
};
});
},
refresh: function(frm) {
if(frm.doc.docstatus > 0) {
frm.add_custom_button(__('Ledger'), function() {
frappe.route_options = {
"voucher_no": frm.doc.name,
"from_date": frm.doc.posting_date,
"to_date": moment(frm.doc.modified).format('YYYY-MM-DD'),
"company": frm.doc.company,
"group_by": "",
"show_cancelled_entries": frm.doc.docstatus === 2
};
frappe.set_route("query-report", "General Ledger");
}, "fa fa-table");
refresh: function (frm) {
if (frm.doc.docstatus > 0) {
frm.add_custom_button(
__("Ledger"),
function () {
frappe.route_options = {
voucher_no: frm.doc.name,
from_date: frm.doc.posting_date,
to_date: moment(frm.doc.modified).format("YYYY-MM-DD"),
company: frm.doc.company,
group_by: "",
show_cancelled_entries: frm.doc.docstatus === 2,
};
frappe.set_route("query-report", "General Ledger");
},
"fa fa-table"
);
}
}
})
},
});

View File

@@ -1,36 +1,37 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('POS Closing Entry', {
onload: function(frm) {
frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
frm.set_query("pos_profile", function(doc) {
frappe.ui.form.on("POS Closing Entry", {
onload: function (frm) {
frm.ignore_doctypes_on_cancel_all = ["POS Invoice Merge Log"];
frm.set_query("pos_profile", function (doc) {
return {
filters: { 'user': doc.user }
filters: { user: doc.user },
};
});
frm.set_query("user", function(doc) {
frm.set_query("user", function (doc) {
return {
query: "erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry.get_cashiers",
filters: { 'parent': doc.pos_profile }
filters: { parent: doc.pos_profile },
};
});
frm.set_query("pos_opening_entry", function(doc) {
return { filters: { 'status': 'Open', 'docstatus': 1 } };
frm.set_query("pos_opening_entry", function (doc) {
return { filters: { status: "Open", docstatus: 1 } };
});
if (frm.doc.docstatus === 0 && !frm.doc.amended_from) frm.set_value("period_end_date", frappe.datetime.now_datetime());
if (frm.doc.docstatus === 0 && !frm.doc.amended_from)
frm.set_value("period_end_date", frappe.datetime.now_datetime());
frappe.realtime.on('closing_process_complete', async function(data) {
frappe.realtime.on("closing_process_complete", async function (data) {
await frm.reload_doc();
if (frm.doc.status == 'Failed' && frm.doc.error_message) {
if (frm.doc.status == "Failed" && frm.doc.error_message) {
frappe.msgprint({
title: __('POS Closing Failed'),
title: __("POS Closing Failed"),
message: frm.doc.error_message,
indicator: 'orange',
clear: true
indicator: "orange",
clear: true,
});
}
});
@@ -47,23 +48,23 @@ frappe.ui.form.on('POS Closing Entry', {
}
},
refresh: function(frm) {
if (frm.doc.docstatus == 1 && frm.doc.status == 'Failed') {
refresh: function (frm) {
if (frm.doc.docstatus == 1 && frm.doc.status == "Failed") {
const issue = '<a id="jump_to_error" style="text-decoration: underline;">issue</a>';
frm.dashboard.set_headline(
__('POS Closing failed while running in a background process. You can resolve the {0} and retry the process again.', [issue]));
__(
"POS Closing failed while running in a background process. You can resolve the {0} and retry the process again.",
[issue]
)
);
$('#jump_to_error').on('click', (e) => {
$("#jump_to_error").on("click", (e) => {
e.preventDefault();
frappe.utils.scroll_to(
cur_frm.get_field("error_message").$wrapper,
true,
30
);
frappe.utils.scroll_to(cur_frm.get_field("error_message").$wrapper, true, 30);
});
frm.add_custom_button(__('Retry'), function () {
frm.call('retry', {}, () => {
frm.add_custom_button(__("Retry"), function () {
frm.call("retry", {}, () => {
frm.reload_doc();
});
});
@@ -71,48 +72,54 @@ frappe.ui.form.on('POS Closing Entry', {
},
pos_opening_entry(frm) {
if (frm.doc.pos_opening_entry && frm.doc.period_start_date && frm.doc.period_end_date && frm.doc.user) {
if (
frm.doc.pos_opening_entry &&
frm.doc.period_start_date &&
frm.doc.period_end_date &&
frm.doc.user
) {
reset_values(frm);
frappe.run_serially([
() => frm.trigger("set_opening_amounts"),
() => frm.trigger("get_pos_invoices")
() => frm.trigger("get_pos_invoices"),
]);
}
},
set_opening_amounts(frm) {
return frappe.db.get_doc("POS Opening Entry", frm.doc.pos_opening_entry)
return frappe.db
.get_doc("POS Opening Entry", frm.doc.pos_opening_entry)
.then(({ balance_details }) => {
balance_details.forEach(detail => {
balance_details.forEach((detail) => {
frm.add_child("payment_reconciliation", {
mode_of_payment: detail.mode_of_payment,
opening_amount: detail.opening_amount,
expected_amount: detail.opening_amount
expected_amount: detail.opening_amount,
});
})
});
});
},
get_pos_invoices(frm) {
return frappe.call({
method: 'erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry.get_pos_invoices',
method: "erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry.get_pos_invoices",
args: {
start: frappe.datetime.get_datetime_as_string(frm.doc.period_start_date),
end: frappe.datetime.get_datetime_as_string(frm.doc.period_end_date),
pos_profile: frm.doc.pos_profile,
user: frm.doc.user
user: frm.doc.user,
},
callback: (r) => {
let pos_docs = r.message;
set_form_data(pos_docs, frm);
refresh_fields(frm);
set_html_data(frm);
}
},
});
},
before_save: async function(frm) {
frappe.dom.freeze(__('Processing Sales! Please Wait...'));
before_save: async function (frm) {
frappe.dom.freeze(__("Processing Sales! Please Wait..."));
frm.set_value("grand_total", 0);
frm.set_value("net_total", 0);
@@ -125,12 +132,12 @@ frappe.ui.form.on('POS Closing Entry', {
await Promise.all([
frappe.call({
method: 'erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry.get_pos_invoices',
method: "erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry.get_pos_invoices",
args: {
start: frappe.datetime.get_datetime_as_string(frm.doc.period_start_date),
end: frappe.datetime.get_datetime_as_string(frm.doc.period_end_date),
pos_profile: frm.doc.pos_profile,
user: frm.doc.user
user: frm.doc.user,
},
callback: (r) => {
let pos_invoices = r.message;
@@ -143,22 +150,22 @@ frappe.ui.form.on('POS Closing Entry', {
refresh_fields(frm);
set_html_data(frm);
}
}
})
])
},
}),
]);
frappe.dom.unfreeze();
}
},
});
frappe.ui.form.on('POS Closing Entry Detail', {
frappe.ui.form.on("POS Closing Entry Detail", {
closing_amount: (frm, cdt, cdn) => {
const row = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, "difference", flt(row.closing_amount - row.expected_amount));
}
})
},
});
function set_form_data(data, frm) {
data.forEach(d => {
data.forEach((d) => {
add_to_pos_transaction(d, frm);
frm.doc.grand_total += flt(d.grand_total);
frm.doc.net_total += flt(d.net_total);
@@ -173,13 +180,15 @@ function add_to_pos_transaction(d, frm) {
pos_invoice: d.name,
posting_date: d.posting_date,
grand_total: d.grand_total,
customer: d.customer
})
customer: d.customer,
});
}
function refresh_payments(d, frm) {
d.payments.forEach(p => {
const payment = frm.doc.payment_reconciliation.find(pay => pay.mode_of_payment === p.mode_of_payment);
d.payments.forEach((p) => {
const payment = frm.doc.payment_reconciliation.find(
(pay) => pay.mode_of_payment === p.mode_of_payment
);
if (p.account == d.account_for_change_amount) {
p.amount -= flt(d.change_amount);
}
@@ -192,25 +201,25 @@ function refresh_payments(d, frm) {
mode_of_payment: p.mode_of_payment,
opening_amount: 0,
expected_amount: p.amount,
closing_amount: 0
})
closing_amount: 0,
});
}
})
});
}
function refresh_taxes(d, frm) {
d.taxes.forEach(t => {
const tax = frm.doc.taxes.find(tx => tx.account_head === t.account_head && tx.rate === t.rate);
d.taxes.forEach((t) => {
const tax = frm.doc.taxes.find((tx) => tx.account_head === t.account_head && tx.rate === t.rate);
if (tax) {
tax.amount += flt(t.tax_amount);
} else {
frm.add_child("taxes", {
account_head: t.account_head,
rate: t.rate,
amount: t.tax_amount
})
amount: t.tax_amount,
});
}
})
});
}
function reset_values(frm) {
@@ -232,13 +241,13 @@ function refresh_fields(frm) {
}
function set_html_data(frm) {
if (frm.doc.docstatus === 1 && frm.doc.status == 'Submitted') {
if (frm.doc.docstatus === 1 && frm.doc.status == "Submitted") {
frappe.call({
method: "get_payment_reconciliation_details",
doc: frm.doc,
callback: (r) => {
frm.get_field("payment_reconciliation_details").$wrapper.html(r.message);
}
},
});
}
}

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