Compare commits

..

523 Commits

Author SHA1 Message Date
Sahil Khan
a9e9efbd23 Merge branch 'hotfix' 2019-05-07 14:45:45 +05:30
Sahil Khan
2f175e6d85 bumped to version 11.1.26 2019-05-07 15:01:01 +05:50
rohitwaghchaure
df817a858b Merge pull request #17510 from rohitwaghchaure/fixed_lead_dashbord_quotation_redirect
fix: quotation link in the lead dashboard not working and filter from the dashboard was not set in the list view
2019-05-07 14:30:16 +05:30
Rohit Waghchaure
4a73059ed3 fix: quotation link in the lead dashboard not working and filter from the dashboard was not applying 2019-05-07 14:29:39 +05:30
rohitwaghchaure
552615525c Merge pull request #17511 from deepeshgarg007/quotation-refactor-fixes
fix: Dynamic Link fieldname fix in quotation
2019-05-07 14:25:38 +05:30
deepeshgarg007
25e408fd2a fix:Contact person query fix in quotation 2019-05-07 12:43:20 +05:30
rohitwaghchaure
375a6f67ae Merge pull request #17505 from rohitwaghchaure/customer_not_found_in_qtn
fix: not able to make sales order from the lead quotation
2019-05-06 19:26:24 +05:30
Rohit Waghchaure
ead8d82a84 fix: not able to make sales order from the lead quotation 2019-05-06 17:16:57 +05:30
Deepesh Garg
2c229c6403 Merge pull request #17495 from sagarvora/ewb_fixes
fix(regional): imporvements to e-Way Bill JSON generation
2019-05-06 12:31:31 +05:30
Sagar Vora
5fb78a375d fix(regional): imporvements to e-Way Bill JSON generation
- Set pincode correctly in 'Bill To - Ship To' scenario
- Python 2 compatibility (convert to int after rounding)
- Avoid execeeding max character limit in tax amounts by rounding the same to two digits
2019-05-06 11:32:37 +05:30
Tyler Matteson
8fcad571f5 Batch naming series hotfix (#17483)
* fix: not able to make sales order from quotation

* fix: batch naming series unicode() call is py3 incompatible
2019-05-04 23:49:24 +05:30
Himanshu
53d7e667dd fix: patch to remove scheduling tool (#17472)
* fix: patch to remove scheduling tool

* fix: drop table

* patch: delete table if exists

* fix: remove drop table

* use orm
2019-05-04 22:42:35 +05:30
Rohan
7395716476 fix(stock): Allow expired batches to be flushed out of the system (#17477) 2019-05-04 22:40:42 +05:30
Rushabh Mehta
c068b6a885 fix: unlink task rather than deleting it (#17486) 2019-05-04 22:39:00 +05:30
Himanshu Warekar
02d28c5908 fix: use list comprehension 2019-05-04 22:35:08 +05:30
Rohan
90d0d24d1a Update erpnext/selling/doctype/customer/customer.py
Co-Authored-By: hrwX <himanshuwarekar@yahoo.com>
2019-05-04 22:35:08 +05:30
Himanshu Warekar
6aab14f9cf fix: calculate percentage only if sales team exist 2019-05-04 22:35:08 +05:30
Himanshu Warekar
163dbdca34 fix: allocated percentage should be equal to 100 2019-05-04 22:35:08 +05:30
Himanshu Warekar
dcc99a2644 fix: python side validation 2019-05-04 22:35:08 +05:30
Rohit Waghchaure
f5297cf386 fix: not able to make sales order from quotation 2019-05-03 15:52:59 +05:30
Mangesh-Khairnar
9f7fd16882 feat: unlink task from project on task deletion 2019-05-03 13:06:19 +05:30
Nabin Hait
5296ab1f87 Merge pull request #16783 from sahil28297/default_warehouse_for_sales_return
fix: set warehouse from def_warehouse_for_sales_return in sales return
2019-05-03 09:27:04 +05:30
Nabin Hait
e42c14f2cb Merge pull request #17469 from rohitwaghchaure/fixed_sales_order_issue_from_quotation
fix: not able to make sales order from quotation
2019-05-03 09:19:27 +05:30
Rohit Waghchaure
4ef10fd6c3 fix: not able to make sales order from quotation 2019-05-03 01:48:45 +05:30
sahil28297
4c0d0e226b Merge branch 'hotfix' into default_warehouse_for_sales_return 2019-05-03 00:05:22 +05:30
Deepesh Garg
094caaa03e Merge pull request #17465 from deepeshgarg007/inactive-items-fix-hotfix
fix: Inactive sales item report fix
2019-05-02 23:50:57 +05:30
Nabin Hait
ce51553d29 Merge pull request #16907 from sagarvora/ewb
feat(regional 🇮🇳): auto-generate e-Way Bill JSON from Sales Invoice
2019-05-02 21:55:24 +05:30
Nabin Hait
f41fc21274 Merge branch 'hotfix' into ewb 2019-05-02 21:54:38 +05:30
Nabin Hait
1f49b77529 Merge pull request #17460 from nabinhait/project-billing-summary
Refactor: Project billing summary Report
2019-05-02 21:48:35 +05:30
deepeshgarg007
a0012f8c48 fix: Inactive sales item report fix 2019-05-02 19:32:43 +05:30
Nabin Hait
4b1c3ad7ac refactor: Project and billing summary 2019-05-02 18:11:27 +05:30
Anurag Mishra
a063803224 fix: handling case if from date and to date are equal in billing reports 2019-05-02 18:11:27 +05:30
Saurabh
63c7fd90a5 Merge branch 'hotfix' 2019-05-02 16:58:24 +05:30
Saurabh
c9c02c7c85 bumped to version 11.1.25 2019-05-02 17:28:24 +06:00
Nabin Hait
bc7ef1937e Merge pull request #17455 from saurabh6790/multiple_fixes
fix: data pulling based on quotation_to and party_name
2019-05-02 16:01:07 +05:30
Nabin Hait
75b63c5b4c Update set_missing_title_for_quotation.py 2019-05-02 16:00:49 +05:30
Saurabh
625191d20a fix: provision to setup customer name on quotation save and patch for the same 2019-05-02 15:50:01 +05:30
Saurabh
1417c7e828 fix: data pulling based on quotation_to and party_name 2019-05-02 14:12:29 +05:30
Saurabh
a4bbc68945 Merge pull request #17449 from nabinhait/auto-account-creation-company-tree
fix: Validate parent account of child company while creating new account based on parent company
2019-05-02 12:26:23 +05:30
Nabin Hait
2d7a591c61 Merge branch 'hotfix' into auto-account-creation-company-tree 2019-05-02 09:56:53 +05:30
Nabin Hait
448a5e1c9c Merge pull request #17447 from nabinhait/woocommerce-multilingual-fix
fix: Multilingual handling in woocommerce integration
2019-05-01 21:15:07 +05:30
Nabin Hait
7be75adc3f fix: Validate parent account of child company while creating new account based on parent company 2019-05-01 20:26:09 +05:30
Nabin Hait
fafee7cf61 Merge pull request #17442 from nabinhait/work-order-bom-image
feat: Added item image in work order and bom
2019-05-01 19:31:24 +05:30
Nabin Hait
16aa23e454 fix: Multilingual handling in woocommerce integration 2019-05-01 19:17:59 +05:30
Nabin Hait
a4d5c5414d Merge pull request #17440 from nabinhait/pe-ref-exchange-rate
fix: Always fetch exchange rate from ref document
2019-05-01 17:17:46 +05:30
Nabin Hait
b104e3595c feat: Added item image in work order and bom 2019-05-01 16:37:32 +05:30
Deepesh Garg
5a06dd1ed1 Merge pull request #17436 from deepeshgarg007/name_fix_hotfix
fix: Rename Inactive Items report to Inactive Sales Items
2019-05-01 16:29:02 +05:30
Nabin Hait
27fe55efe1 fix: Always fetch exchange rate from ref document 2019-05-01 15:32:30 +05:30
Sahil Khan
9089b242ba Merge branch 'hotfix' 2019-05-01 15:13:26 +05:30
Sahil Khan
98e511d236 bumped to version 11.1.24 2019-05-01 15:33:26 +05:50
Nabin Hait
93784d3804 Merge pull request #17430 from nabinhait/deferred-accounting-long-job
fix: Deferred accounting posting moved to long job
2019-05-01 15:04:34 +05:30
Deepesh Garg
d29fde0bf3 Merge branch 'hotfix' into name_fix_hotfix 2019-05-01 14:27:17 +05:30
deepeshgarg007
8326925fe8 fix: Rename Inactive Items report to Inactive Sales Item 2019-05-01 13:36:08 +05:30
rohitwaghchaure
a924b636a4 Merge pull request #17412 from rohitwaghchaure/dont_raise_user_permissions
fix: while saving employee user getting user permissions error
2019-05-01 12:54:52 +05:30
Nabin Hait
3526ed975c moved deferred accounting monthly job to long job 2019-05-01 12:49:44 +05:30
Nabin Hait
d0faec3cc0 Merge pull request #17419 from nabinhait/ss-fixes
fix: a few fixes in payroll
2019-05-01 12:16:51 +05:30
Nabin Hait
661a5ce332 Merge pull request #17393 from ashish-greycube/hotfix_allow_bank_account_import
fix: allow_import_of_bank_account_by_account_manager
2019-05-01 11:17:12 +05:30
Nabin Hait
b289aa3548 Merge pull request #17387 from ashish-greycube/hotfix_correct_party_type
fix: show only party_type doctypes in Party Type field of bank account
2019-05-01 11:15:16 +05:30
Nabin Hait
4ed521162e Merge pull request #17374 from Alchez/hotfix-projects-subject-filter
feat(projects): Add subject filter to Issue and Task
2019-05-01 11:14:08 +05:30
Nabin Hait
8865d05b4c Merge pull request #17396 from chdecultot/hotfix
fix: Multiple corrections to the bank reconciliation tool
2019-05-01 10:59:39 +05:30
Nabin Hait
4df46737ef fix: Null handling 2019-05-01 10:59:02 +05:30
Deepesh Garg
09ac547a80 Merge branch 'hotfix' into ewb 2019-04-30 10:28:57 +05:30
Faris Ansari
c1bbaf07a4 fix: Map item_code to title (#17402)
When making Project from Sales Order, description was mapped
with Task title which can exceed 140 characters easily.
Description should be mapped with description as it is html field.
2019-04-30 10:18:39 +05:30
Nabin Hait
73a081d806 fix: a few fixes in payroll 2019-04-30 00:48:11 +05:30
rohitwaghchaure
e1df414f8b Merge pull request #17413 from rohitwaghchaure/duplicate_error_if_project_created_from_so
hotfix: while making project from sales order, getting duplicate project error
2019-04-29 22:21:18 +05:30
Rohit Waghchaure
cefef3b62d fix: while making project from sales order, getting duplicate project error 2019-04-29 20:34:46 +05:30
Rohit Waghchaure
bd4ee60d1e fix: while saving employee user getting user permissions error 2019-04-29 19:11:17 +05:30
Sahil Khan
f6a9eec23a Merge branch 'hotfix' 2019-04-29 16:35:41 +05:30
Sahil Khan
5742d0836e bumped to version 11.1.23 2019-04-29 16:55:41 +05:50
deepeshgarg007
0555223797 Merge branch 'hotfix' of https://github.com/frappe/erpnext into ewb 2019-04-28 23:22:48 +05:30
deepeshgarg007
de93efb304 fix: Added test cases for ewb json creation 2019-04-28 23:14:02 +05:30
deepeshgarg007
6856033d3c fix: Code cleanup and fixes 2019-04-28 23:13:26 +05:30
Faris Ansari
0735165ef3 fix: Make Customer and lead field dynamic in quotations and opportunity (#17097)
fix: Make Customer and lead field dynamic in quotations and opportunity
2019-04-28 20:46:39 +05:30
Charles-Henri Decultot
1aa5462f36 fix: Codacy 2019-04-26 20:52:12 +02:00
Charles-Henri Decultot
f83514418e fix: Codacy 2019-04-26 20:02:38 +02:00
Charles-Henri Decultot
3c13e8e8b9 fix: Codacy 2019-04-26 18:56:47 +02:00
Charles-Henri Decultot
de0955b8ed fix: Remove leftover method 2019-04-26 14:59:10 +02:00
Charles-Henri Decultot
82af75b853 fix: Hotfix conflict resolved 2019-04-26 14:57:26 +02:00
ashish-greycube
d3ce4f815d codacy review 2019-04-26 14:10:46 +05:30
ashish-greycube
85bf9203ed fix: allow_import_of_bank_account_by_account_manager 2019-04-26 13:56:26 +05:30
rohitwaghchaure
db12f75681 Merge pull request #17385 from surajshetty3416/fix-price-list-hotfix
fix: Price list conversion for other UOM from stock UOM item price
2019-04-26 12:06:46 +05:30
ashish-greycube
3763169978 show only party_type doctypes in Party Type field of bank account 2019-04-26 11:51:34 +05:30
Suraj Shetty
36a8c431f5 fix: Typo 2019-04-26 11:18:26 +05:30
Suraj Shetty
5a67431daa fix: Price list for UOM other than stock UOM
-Fixes conversion from default UOM item price to  other UOMs
2019-04-26 11:18:13 +05:30
Nabin Hait
c4e92b3004 Merge pull request #17381 from nabinhait/tax-exemption
refactor: Employee Tax Exemption
2019-04-26 00:20:27 +05:30
Nabin Hait
2d90e8a2de fix: test cases 2019-04-25 22:29:49 +05:30
Sagar Vora
4dacb89da6 fix: test case and semicolons 2019-04-25 21:45:26 +05:30
Sagar Vora
c552d74746 fix: add missing semicolons 2019-04-25 21:45:26 +05:30
Sagar Vora
2697c2d869 feat(regional | India): auto-generate e-Way Bill JSON from Sales Invoice 2019-04-25 21:45:26 +05:30
Nabin Hait
4a950abf2e fix: test cases 2019-04-25 21:42:01 +05:30
Nabin Hait
7f10f4eea1 Merge pull request #17376 from rohitwaghchaure/trial_balance_error_finance_book
fix: Trial balance finance book issue
2019-04-25 20:35:09 +05:30
Nabin Hait
5c93260eec Merge pull request #17377 from nabinhait/pos-advance-hotfix
fix: Don't allocate advance if pos
2019-04-25 20:33:59 +05:30
Nabin Hait
485d9c133a fix: test cases 2019-04-25 19:54:20 +05:30
deepeshgarg007
891d9aeee9 fix: Remove method from validation 2019-04-25 19:19:01 +05:30
deepeshgarg007
51f0d6d409 fix: Remove fetch_from from customer name 2019-04-25 18:56:08 +05:30
Nabin Hait
80374be724 refactor: Employee Tax Exemption 2019-04-25 18:44:32 +05:30
Nabin Hait
619bf561da fix: Don't allocate advance if pos 2019-04-25 17:47:26 +05:30
Rohit Waghchaure
13c15d0222 fix: Trial balance finance book issue 2019-04-25 17:46:44 +05:30
deepeshgarg007
3d31bccaf6 fix: Change dynamic_field name and minor fixes 2019-04-25 17:29:21 +05:30
deepeshgarg007
3959bf34ee Merge branch 'hotfix' of https://github.com/frappe/erpnext into quotation-fix 2019-04-25 14:57:56 +05:30
Rohan Bansal
1897ed38df enhance(projects): Add subject filter to Issue and Task 2019-04-25 13:40:24 +05:30
rohitwaghchaure
126c4efb2c Merge pull request #17357 from rohitwaghchaure/fix_straight_line_asset_depreciation
fix: Straight line asset depreciation not working if Expected Value After Useful Life is defined
2019-04-25 10:23:15 +05:30
Rohit Waghchaure
7d0bc2bd5a fixed test cases 2019-04-25 01:26:27 +05:30
Nabin Hait
0c70ae44c3 Merge pull request #17366 from chdecultot/plaid_settings_erro
fix: Better error message for plaid setting
2019-04-24 23:15:02 +05:30
Nabin Hait
024dc4a4c9 Merge pull request #17316 from alyf-de/validate_iban
feat(accounts): validate Bank Account's IBAN
2019-04-24 22:57:04 +05:30
Deepesh Garg
e3567ff31b Merge pull request #17363 from deepeshgarg007/inactive_items_hotfix
feat: Inactive items hotfix
2019-04-24 22:30:34 +05:30
Charles-Henri Decultot
97842ca804 fix: cleanup development 2019-04-24 18:15:46 +02:00
Charles-Henri Decultot
d14799a9fa fix: verbose error message when api keys are not setup 2019-04-24 18:06:14 +02:00
Raffael Meyer
e534221245 fix: validate IBAN only if it exists 2019-04-24 16:22:34 +02:00
Raffael Meyer
4acfec901e Merge branch 'hotfix' of https://github.com/frappe/erpnext into validate_iban 2019-04-24 16:15:35 +02:00
deepeshgarg007
a981a8a153 fix: Ignore sql injections 2019-04-24 15:14:23 +05:30
deepeshgarg007
11e1c60cd3 fix: Typo fixes 2019-04-24 15:13:59 +05:30
deepeshgarg007
fe7baae9f7 fix: Ordering and datatype fixes in inactive items report 2019-04-24 15:13:46 +05:30
deepeshgarg007
da64113b9a feat: Logic for query and report creation for inactive items 2019-04-24 15:13:28 +05:30
rohitwaghchaure
fb76cb7a78 Merge pull request #17301 from rohitwaghchaure/fixed_received_qty_showing_incorrect
fix: received qty in the purchase order item showing incorrect if user has returned the rejected quantity
2019-04-24 15:08:39 +05:30
deepeshgarg007
1bd69b4490 fix: Reordered and deleted unnecessary filters 2019-04-24 15:06:48 +05:30
deepeshgarg007
62d51d82ea feat: Added filters and columns for inactive items report 2019-04-24 15:06:23 +05:30
deepeshgarg007
6ddc554965 fix: Merge branch hotfix into quotation-fix 2019-04-24 14:53:30 +05:30
Rohit Waghchaure
5a6fc77751 fix: Straight line asset depreciation not working if Expected Value After Useful Life is defined 2019-04-24 11:40:37 +05:30
Nabin Hait
733db826ec Merge branch 'hotfix' into validate_iban 2019-04-23 21:39:47 +05:30
Nabin Hait
6643156df6 Merge pull request #17347 from nabinhait/invoice-advances
fix: don't allocate advances if POS
2019-04-23 21:36:29 +05:30
Nabin Hait
6022f2bcf8 Merge pull request #17349 from rohitwaghchaure/invoiced_items_gross_margin_api
feat: Get invoiced item's gross margin using API
2019-04-23 21:36:02 +05:30
Nabin Hait
b890492dc0 Merge pull request #17348 from nabinhait/salary-slip-rounded
fix: Rounded tax amount in salary slip
2019-04-23 21:35:34 +05:30
Rohit Waghchaure
6ea108f01d feat: Get invoiced item's gross margin using API 2019-04-23 18:56:26 +05:30
Nabin Hait
628bed1f5a Merge branch 'hotfix' into validate_iban 2019-04-23 18:41:46 +05:30
Nabin Hait
4c0e3aa097 Merge pull request #17341 from Alchez/hotfix-return-deliveries
fix(selling): Fix method to also consider return documents
2019-04-23 18:41:11 +05:30
Nabin Hait
631e334a3f Merge pull request #17338 from chdecultot/bank_reco_corrections
fix: Bank reconciliation corrections
2019-04-23 18:40:03 +05:30
Nabin Hait
8f4d92eba2 Merge branch 'hotfix' into validate_iban 2019-04-23 18:39:12 +05:30
Deepesh Garg
2f4193757e fix: Stock Ledger report fix (#17342) 2019-04-23 17:30:11 +05:30
Rohan Bansal
cba64988df fix(selling): Fix method to also consider return documents 2019-04-23 16:39:09 +05:30
Nabin Hait
17e6fce486 fix: Rounded tax amount in salary slip 2019-04-23 15:51:28 +05:30
Nabin Hait
05fb3f2d75 fix: don't allocate advances if POS 2019-04-23 15:49:38 +05:30
Charles-Henri Decultot
af6360b273 Bank reconciliation corrections 2019-04-23 10:44:32 +02:00
Nabin Hait
043a47a9c0 Merge pull request #17329 from nabinhait/income-tax-period-factor
fix: Income tax period factor considering joining and relieving date
2019-04-22 21:07:35 +05:30
Nabin Hait
23e424911c Merge branch 'hotfix' into income-tax-period-factor 2019-04-22 19:28:13 +05:30
Saif
a5fbeaa3d3 fix: Remove duplicate/incorrect patch 2019-04-22 17:29:36 +05:00
Nabin Hait
8aeb4b04bd fix: Income tax period factor considering joining and relieving date 2019-04-22 17:39:02 +05:30
Raffael Meyer
f3b07495f6 fix typo 2019-04-22 12:38:22 +02:00
Raffael Meyer
70f89462a8 fix: consider empty iban 2019-04-22 12:27:12 +02:00
Nabin Hait
bbc7f474c3 Merge pull request #17327 from Anurag810/bom_prowser_patch
fix: (Patch) Removed page Bom-Browser
2019-04-22 15:54:35 +05:30
Anurag Mishra
26fe30685a Merge branch 'hotfix' into bom_prowser_patch 2019-04-22 15:53:05 +05:30
Anurag Mishra
7bdd27f7e2 chore: used frappe.delete_doc_if_exists 2019-04-22 15:50:12 +05:30
Nabin Hait
96ec4aeda0 Merge pull request #17287 from alyf-de/skr
feat(accounts): add German CoA with numbers
2019-04-22 15:44:48 +05:30
Nabin Hait
cce65d41b8 Merge pull request #17325 from PawanMeh/fix_17324
fix: Attendance list not showing employee name
2019-04-22 14:58:07 +05:30
Nabin Hait
a44d46e535 Merge pull request #17320 from nabinhait/payroll-based-on-payment-days
fix: Renamed depends_on_lwp to depends_on_payment_days
2019-04-22 14:55:37 +05:30
Anurag Mishra
4f16d17d21 fix: resolve conflicts 2019-04-22 14:48:15 +05:30
Anurag Mishra
759bb0eb62 fix: (Patch) Removed page Bom-Browser 2019-04-22 14:46:00 +05:30
Sahil Khan
d7aa71aa70 Merge branch 'hotfix' 2019-04-22 14:05:43 +05:30
Sahil Khan
32207ad722 bumped to version 11.1.22 2019-04-22 14:25:43 +05:50
hello@openetech.com
8a32ad206a [fix] #17324 2019-04-22 13:58:30 +05:30
Nabin Hait
16bd2ed967 Merge pull request #17319 from SaiFi0102/Revert-Allocate-Advance-Automatically-V11
fix: Set Allocate Advance Automatically disabled by default (v11)
2019-04-22 13:32:30 +05:30
Nabin Hait
393b12a37f fix: Renamed depends_on_lwp to depends_on_payment_days 2019-04-22 13:26:18 +05:30
Saif Ur Rehman
d1332f6c24 fix: Set Allocate Advance Automatically disabled by default 2019-04-22 12:17:25 +05:00
Saurabh
f36fa088f8 Merge pull request #17302 from sahil28297/new_site_sync
fix(site_sync): return more data in level
2019-04-22 12:46:20 +05:30
Saurabh
bb63103183 Merge branch 'hotfix' into new_site_sync 2019-04-22 12:46:13 +05:30
Anurag Mishra
7760db7563 fix: sales order status for order type 'Maintenance' (#17119)
* fix: Sales order Status for order type 'Maintenance'

* fix: test case for sales order
2019-04-22 12:15:11 +05:30
Saurabh
0ea1e67ce7 Merge branch 'hotfix' into new_site_sync 2019-04-22 11:59:52 +05:30
Nabin Hait
587b52dcd4 Merge pull request #17080 from auliabismar/patch-2
fix: Renumber Aktiva, remove excess 0
2019-04-22 11:21:15 +05:30
Nabin Hait
efcdf2fd42 Merge pull request #17255 from Anurag810/patch_for_salary_structure
fix: (Patch)make salary details submitable if  salary structure is submitted
2019-04-22 11:17:28 +05:30
Nabin Hait
010a05df48 Update set_salary_details_submitable.py 2019-04-22 11:16:47 +05:30
Nabin Hait
58d565a882 Merge pull request #17292 from prasadarr/listing-fixes-hotfix
fix: Allow system manager to access share ledger
2019-04-22 11:13:17 +05:30
Nabin Hait
b655b07f20 Merge pull request #17309 from nabinhait/ar-fix
fix: Total row alignment in AR report
2019-04-22 11:11:45 +05:30
Sahil Khan
afb59fa5c0 fix: import iteritems 2019-04-22 10:47:37 +05:30
Sahil Khan
cb4b86512d fix: syntax error 2019-04-22 10:10:50 +05:30
Raffael Meyer
49f919a4fc fix test's error message 2019-04-22 05:32:35 +02:00
Raffael Meyer
4a9127f9a6 feat(accounts): validate IBAN 2019-04-22 03:46:25 +02:00
Kenneth Sequeira
c4a670c8c8 add salutation in contact display for lead (#17312) 2019-04-20 21:44:38 +05:30
Don-Leopardo
a26e2c064a fix: Campaign Efficiency report only works in english (#17284)
* fix column translation and match

* fix float results

* fix import missing
2019-04-20 21:12:23 +05:30
Sahil Khan
3889d0f0a0 fix: refactor level 2019-04-20 14:26:49 +05:30
rohitwaghchaure
4e81fb20b9 fix: Move erpnext related methods from frappe to erpnext (#17293) 2019-04-20 11:50:45 +05:30
Nabin Hait
dfba52b834 fix: Total row alignment in AR report 2019-04-20 10:57:04 +05:30
Nabin Hait
f665e42e2a Merge pull request #17307 from surajshetty3416/fix-employee-permission-hotfix
fix: Do not create employee user permission if already exists
2019-04-20 01:44:30 +05:30
Nabin Hait
560cc66a36 Merge pull request #17279 from rohitwaghchaure/requested_items_tobe_ordered_issue_for_multi_uom
fix: Requested Items To Be Ordered report showing records even if material request is fully ordered
2019-04-20 01:27:46 +05:30
Suraj Shetty
d08953b72b fix: Do not create employee user permission if already exists 2019-04-19 21:57:39 +05:30
Nabin Hait
34e4ac2398 Merge pull request #17296 from chdecultot/reconciliation_correction
fix: Reconciliation dashboard py3 and matching corrections
2019-04-19 20:02:54 +05:30
Sahil Khan
3dbaa3c2d9 fix(site_sync): return more data in level 2019-04-19 16:31:23 +05:30
Rohit Waghchaure
613d82e12f fix: received qty in the purchase order item showing incorrect if user has returned the rejected quantity 2019-04-19 16:28:19 +05:30
Anurag Mishra
4f2fa173c9 fix: Reopen button does not appear in delivery note (#17295) 2019-04-19 16:06:17 +05:30
Rohit Waghchaure
d36e635e60 fix: Requested Items To Be Ordered report showing records even if material request is fully ordered 2019-04-19 14:54:59 +05:30
Charles-Henri Decultot
e86d21ea15 Py3 and matching corrections 2019-04-19 10:09:06 +02:00
Nabin Hait
b6fda118b9 Merge pull request #17280 from rohitwaghchaure/credit_will_not_be_converted_if_debit_amount_is_there
fix: credit amount not be consider if debit amount is present in the general ledger
2019-04-19 13:18:33 +05:30
Nabin Hait
2c607e5562 Merge pull request #17290 from alyf-de/company_test
fix(test): provide a helpful error message
2019-04-19 13:10:46 +05:30
Nabin Hait
95fce2395a Merge pull request #17289 from sunhoww/patch-1
fix: scan_barcode field adding invalid items
2019-04-19 13:07:06 +05:30
Nabin Hait
0f0dcd9035 Merge pull request #17285 from rohitwaghchaure/task_not_able_to_search_by_name_in_global_search
fix: task name was not able to search by name in global search
2019-04-19 13:06:24 +05:30
Prasad R
ce291c253b fix: show 2 missing doctypes in Accounts
Pricing Term and Exchage Rate Revaluation were missing, added in list
2019-04-19 12:17:19 +05:30
Prasad R
e85c6ad236 fix: Allow system manager to access share ledger 2019-04-19 11:07:19 +05:30
Raffael Meyer
df16cdcf31 fix(test): provide a helpful error message 2019-04-19 00:21:44 +02:00
Raffael Meyer
00303858df fix missing account types 2019-04-19 00:09:37 +02:00
Sun Howwrongbum
6f54a7b7d8 fix: scan_barcode field adding invalid items 2019-04-19 01:44:35 +05:30
Raffael Meyer
fba8bfc0d0 feat(accounts): add German CoA with numbers 2019-04-18 21:27:22 +02:00
Rohit Waghchaure
4db4f21d16 fix: task name was not able to search by name in global search 2019-04-18 22:34:19 +05:30
Rohit Waghchaure
abf9ef0244 fix: credit amount in account's currency not be consider if debit amount is present in the general ledger 2019-04-18 22:01:45 +05:30
Suraj Shetty
22ad81fb57 fix: Remove unwanted parent & parenttype field (#17274) 2019-04-18 15:45:47 +05:30
Shivam Mishra
923c5462a2 Merge pull request #17267 from fproldan/bundlestock
fix: Incorrect stock in "Available Stock for Packing Items" report
2019-04-18 11:04:55 +05:30
Francisco Roldán
753b3d1c28 Merge branch 'hotfix' into bundlestock 2019-04-17 11:44:40 -03:00
Nabin Hait
b9046edb85 Merge pull request #17259 from frappe/kennethsequeira-patch-2
fix: Improve Validation Message in BOM
2019-04-17 17:35:42 +05:30
Nabin Hait
7932eba733 Merge pull request #17266 from deepeshgarg007/gstr1-fixes
fix: GSTR-1 B2C Small report fix
2019-04-17 17:33:20 +05:30
Nabin Hait
5ba9c82922 Merge branch 'hotfix' into gstr1-fixes 2019-04-17 17:33:13 +05:30
Nabin Hait
fc48ce7073 Merge pull request #17250 from saurabh6790/patches_fix
fix: woocommerce settings patch
2019-04-17 17:30:14 +05:30
Nabin Hait
8b9a84b568 Merge pull request #17253 from hrwX/sales_percentage_validate_v11
fix(Customer): validate percentage total
2019-04-17 17:28:50 +05:30
Deepesh Garg
cc4e6a25f6 Merge branch 'hotfix' into kennethsequeira-patch-2 2019-04-17 17:24:45 +05:30
Nabin Hait
17923863de Merge pull request #17256 from Anurag810/fix_report_of_billing_summary
fix: total error arissing due to blank link field
2019-04-17 17:23:19 +05:30
Nabin Hait
32efea5e38 Merge pull request #17262 from rohitwaghchaure/finance_book_blank_issue
fix: If finance book filter is not set then show all the entries
2019-04-17 17:22:33 +05:30
Deepesh Garg
87a2c1d27d Merge branch 'hotfix' into kennethsequeira-patch-2 2019-04-17 17:16:37 +05:30
Nabin Hait
c581d67bba Merge pull request #17120 from hrwX/payment_terms_fix
fix(Purchase Order): fetch payment terms
2019-04-17 17:16:30 +05:30
Himanshu Warekar
1865e0df7c refactor: fetch payment terms in account settings 2019-04-17 15:35:43 +05:30
Himanshu Warekar
308ae1f155 fix: codacy fixes 2019-04-17 12:42:00 +05:30
Himanshu Warekar
2b54cee4aa fix: test case 2019-04-17 12:09:19 +05:30
Himanshu Warekar
ba47f89702 fix: added a single value to fetch payment terms 2019-04-17 11:24:04 +05:30
Nabin Hait
0ea32faf3d Merge pull request #17268 from nabinhait/pr-pi-onload
fix: Pull items from PR to PI
2019-04-16 23:45:48 +05:30
Nabin Hait
7be0736154 fix: removed debug 2019-04-16 23:05:39 +05:30
Nabin Hait
97bf12734a fix: Pull items from PR to PI 2019-04-16 22:11:22 +05:30
deepeshgarg007
4bccd692e5 fix: GSTR1 B2C report fix 2019-04-16 20:50:46 +05:30
NahuelOperto
07f8e6bbfc fix get_item_warehouse_quantity_map method 2019-04-16 11:36:19 -03:00
Rohit Waghchaure
15c7a05879 fix: If finance book filter is not set then show all the entries 2019-04-16 19:28:11 +05:30
Kenneth Sequeira
82e76b2c0c Improve Validation Message in BOM
Update following validation message:

"Price not found for item {0} and price list {1}" to "Price not found for item {0} in price list {1}"
2019-04-16 18:00:21 +05:30
Anurag Mishra
d6757b7af6 fix: total error arissing due to blank link field 2019-04-16 17:39:40 +05:30
Anurag Mishra
b380a02d09 fix: make salary details submitable if salary structure is submitted 2019-04-16 17:07:07 +05:30
Himanshu Warekar
64980fed59 fix: validate percentage total 2019-04-16 16:29:13 +05:30
Saurabh
7df8c0ef82 fix: woocommerce settings patch 2019-04-16 15:57:21 +05:30
deepeshgarg007
28fe73640b fix: Dynamic link fixes in quotation and opportunity 2019-04-16 15:21:51 +05:30
deepeshgarg007
7cfe247b2e Merge branch 'hotfix' of https://github.com/frappe/erpnext into quotation-fix 2019-04-16 13:38:15 +05:30
Saurabh
332b4171c0 Merge branch 'hotfix' 2019-04-16 13:34:52 +05:30
Saurabh
e5544b8c86 bumped to version 11.1.21 2019-04-16 14:04:52 +06:00
sahil28297
38e5e7f616 Merge pull request #17246 from frappe/revert-17226-site_sync
Revert "feat(site_sync): return erpnext data in level"
2019-04-16 13:22:18 +05:30
sahil28297
a595346769 Revert "feat(site_sync): return erpnext data in level" 2019-04-16 13:21:24 +05:30
Nabin Hait
8dace802dc Merge pull request #17243 from hrwX/delivery_note_fix_v11
fix(Delivery Note): show get items even if note has been amended
2019-04-16 13:19:58 +05:30
Himanshu
ac6259dfe8 fix: let user delete the elements of items 2019-04-16 13:18:47 +05:30
Nabin Hait
f801cc953b Merge pull request #17152 from Alchez/hotfix-company-address-label
fix(selling): Add missing label to company address field
2019-04-16 12:45:40 +05:30
Nabin Hait
c117048fde Merge pull request #17226 from sahil28297/site_sync
feat(site_sync): return erpnext data in level
2019-04-16 12:42:45 +05:30
Himanshu Warekar
73fd508ccf fix: show get items even if note has been amended 2019-04-16 12:15:49 +05:30
deepeshgarg007
7cc972969f Merge branch 'hotfix' of https://github.com/frappe/erpnext into quotation-fix 2019-04-16 10:32:32 +05:30
Nabin Hait
734c32b970 Merge pull request #17234 from nabinhait/pr-to-pi
fix: Invoice against partially returned DN/PR
2019-04-16 09:46:24 +05:30
Nabin Hait
fa862e6814 Merge pull request #17236 from hrwX/remove_asset_permission_v11
fix(Asset): Remove user permission for employee in asset
2019-04-16 09:45:54 +05:30
deepeshgarg007
d333d2e6eb fix: Change enquiry_from to opportunity_from in multiple files 2019-04-16 08:53:29 +05:30
deepeshgarg007
3b78a018aa Merge branch hotfix into quotation-fix 2019-04-16 08:46:07 +05:30
Himanshu Warekar
cc581d21f0 Merge branch 'hotfix' of https://github.com/frappe/erpnext into remove_asset_permission_v11 2019-04-15 22:54:42 +05:30
Himanshu Warekar
dca60888ce fix: remove user permission for emp in asset 2019-04-15 22:52:50 +05:30
Nabin Hait
b2465c7a69 fix: Invoice against partially returned DN/PR 2019-04-15 21:02:16 +05:30
rohitwaghchaure
14477c7f51 Merge pull request #17161 from karthikeyan5/hotfix-woocommerce-fix
fix(woocommerce integration): 403 error and adding defaults
2019-04-15 19:34:54 +05:30
deepeshgarg007
f0ee3d26a7 fix: Styling and indentation fixes 2019-04-15 19:20:59 +05:30
deepeshgarg007
2e87202b3b Merge branch 'hotfix' of https://github.com/frappe/erpnext into quotation-fix 2019-04-15 17:58:54 +05:30
Nabin Hait
1024b55f99 Fixed merge conflict 2019-04-15 11:41:54 +05:30
Nabin Hait
9ba7b678fe fix: Bank reconciliation cleanup 2019-04-15 11:33:06 +05:30
Nabin Hait
a8c8e6b78a Merge pull request #16752 from nabinhait/limit-cond-fix
fix: Limit conditions while fetching payment entries
2019-04-15 10:19:12 +05:30
Nabin Hait
ce107086e7 Merge pull request #17083 from frappe/revert-16926-salary-slip-fix
Revert "fix(Salary Slip): Consider Leave without Pay for calculation"
2019-04-15 10:14:12 +05:30
Nabin Hait
49d1449d2b Merge branch 'hotfix' into revert-16926-salary-slip-fix 2019-04-15 10:13:31 +05:30
Nabin Hait
2f6789e54d Merge pull request #17228 from rohitwaghchaure/pos_not_working_if_user_can_access_more_than_one_company
fix: POS not working if user has access of multiple company
2019-04-15 10:12:51 +05:30
Nabin Hait
f2893e5701 Merge pull request #17215 from nabinhait/project-task-opt-tests
perf: Project task optimization
2019-04-15 10:11:16 +05:30
Nabin Hait
870410c9d5 Merge pull request #17180 from netchampfaris/duplicate-variant-check
fix: Validate variant attributes only if is_new
2019-04-15 10:09:12 +05:30
Nabin Hait
30bca30f20 Merge pull request #17185 from netchampfaris/allow-items-not-in-stock
feat: Allow items not in stock to be added in cart
2019-04-15 10:07:49 +05:30
Nabin Hait
80f1d5f63d Merge pull request #17217 from netchampfaris/item-price-packing-unit
fix: Set default value for Packing Unit as 0
2019-04-15 10:07:00 +05:30
Nabin Hait
76d4fa9f2b Merge pull request #17221 from nabinhait/supplier-sales-analytics
fix: supplier wise sales analytics report
2019-04-15 10:05:43 +05:30
Nabin Hait
e17c9d9978 Merge pull request #17225 from hrwX/naming_series
fix(Naming Series): Naming series
2019-04-15 10:05:17 +05:30
deepeshgarg007
e8883e20cd fix: Remove comments and unused code 2019-04-14 22:39:58 +05:30
deepeshgarg007
af4d588f64 fix: Make customer and lead dynamic_link in opportunity 2019-04-14 22:35:06 +05:30
deepeshgarg007
4f0a4a1a2d fix: Customer dashboard fixes 2019-04-14 22:35:06 +05:30
deepeshgarg007
7f7a1b48ed fix: Test case fixes inquotation 2019-04-14 22:35:06 +05:30
deepeshgarg007
f094662f5e fix:Test record fixes 2019-04-14 22:35:06 +05:30
deepeshgarg007
e2fc03e561 fix: Cart test fixes 2019-04-14 22:35:06 +05:30
deepeshgarg007
3987b4b714 fix: Test case fixes in quotation for dynamic column 2019-04-14 22:35:06 +05:30
deepeshgarg007
e889a58724 fix: Patch typo fix and set label in refresh 2019-04-14 22:35:06 +05:30
deepeshgarg007
1638994436 fix: Patch to move customer and lead 2019-04-14 22:35:06 +05:30
deepeshgarg007
ff99492481 fix: Removed redundant code 2019-04-14 22:33:52 +05:30
deepeshgarg007
a65af7a2f5 fix: Quotation Query fix in lead.py 2019-04-14 22:33:52 +05:30
deepeshgarg007
6ba48c58e8 fix: Server side handling of quotation to and get_query fix 2019-04-14 22:33:52 +05:30
deepeshgarg007
3b4f481ca4 fix: Make Customer and lead field dynamic 2019-04-14 22:33:52 +05:30
Rohit Waghchaure
548e93b2d3 fix: POS not working if user has access of multiple company 2019-04-14 19:39:11 +05:30
sahil28297
76eb9b32b3 Merge branch 'hotfix' into site_sync 2019-04-14 18:58:28 +05:30
Sahil Khan
0ac4cfa9b1 fix(site_sync): remove duplicate entry 2019-04-14 18:29:49 +05:30
Himanshu
dc34393b8a fix: allow braces for custom field names 2019-04-14 00:54:24 +05:30
Himanshu
023a865e1e Merge pull request #7 from frappe/hotfix
Hotfix
2019-04-14 00:49:41 +05:30
rohitwaghchaure
d2a7ec1add Merge pull request #17222 from Anurag810/pay_fix
fix: handle for party type member in payment entry(v11)
2019-04-13 00:10:30 +05:30
rohitwaghchaure
564ee5399c Merge pull request #17223 from rohitwaghchaure/user_permissions_are_not_working_for_stock_ledger
fix: user permissions are not working on stock ledger report
2019-04-13 00:09:58 +05:30
karthikeyan5
2518a2ab16 fix(woocommerce integration): travis fix 2019-04-12 19:35:07 +05:30
karthikeyan5
df3e8853ae fix(woocommerce integration): fix strange travis error
the patch was working locally. But, in was failing on travis. The strange thing was that the patch running in travis was looking for woocommerce_settings in the path 'frappe.core.doctype.woocommerce_settings.woocommerce_settings'
2019-04-12 19:35:07 +05:30
karthikeyan5
a0b7ff60b8 fix(woocommerce integration): possible travis fix
possible fix for travis patch error "Error: No module named woocommerce_settings.woocommerce_settings)"
2019-04-12 19:35:07 +05:30
karthikeyan5
97383716e6 fix(woocommerce integration): error in new-site
resolving "Could not find UOM: Nos" error in travis
2019-04-12 19:35:06 +05:30
karthikeyan5
f788117b3e fix(woocommerce integration): defaults in settings 2019-04-12 19:35:06 +05:30
karthikeyan5
6784335e2c fix(woocommerce integration): fixing 403 error 2019-04-12 19:35:06 +05:30
Rohit Waghchaure
c5c9dc5f6d fix: user permissions are not working on stock ledger report 2019-04-12 16:58:51 +05:30
Nabin Hait
819e24ddde fix: supplier wise sales analytics report 2019-04-12 15:11:11 +05:30
Anurag Mishra
313ed4feeb fix: handle for party type member in payment entry 2019-04-12 15:11:06 +05:30
Nabin Hait
5157fa9233 Merge pull request #17150 from nabinhait/ar-credit-note
fix: Show standalone credit note in Accounts receivable report
2019-04-12 14:18:17 +05:30
Faris Ansari
774b96495f fix: Set default value for Packing Unit as 0
The default value 1 assumes Items will be always packed in integer
quantities. This is not the usual case.
2019-04-12 12:38:04 +05:30
Nabin Hait
ea4c2c9e7d fix: task optimisation and test case fixes 2019-04-12 11:33:28 +05:30
Nabin Hait
b42bbf1b6f perf: Optimisation of project and task updation 2019-04-12 11:33:28 +05:30
Nabin Hait
c768febac6 Merge pull request #17206 from rohitwaghchaure/fix_pending_so_items_for_purchase_reques_report
fix: Pending SO Items For Purchase Request report not showing the so, requested and pending quantity correctly
2019-04-12 11:11:16 +05:30
Nabin Hait
0449d30423 Merge pull request #16976 from ESS-LLP/patient_hotfix
fix: Patient relation - patient link is not showing
2019-04-12 11:08:24 +05:30
Nabin Hait
f17dfb0ebe Merge pull request #17157 from Anurag810/vedmata-print-fixes
fix: Vedmata print fixes
2019-04-12 11:07:24 +05:30
Nabin Hait
13273412d1 Merge pull request #17207 from Anurag810/timesheet_report_amount_fixes
fix: timesheet report not showing total amount correctly
2019-04-12 11:05:12 +05:30
Nabin Hait
f198b1d032 Merge branch 'hotfix' into timesheet_report_amount_fixes 2019-04-12 11:05:03 +05:30
Nabin Hait
9512a43d44 Merge pull request #17187 from nabinhait/rounding-adjustment-gle
fix: Rounding Adjustment GL Entry
2019-04-12 11:00:29 +05:30
Anurag Mishra
50db128ff1 fix: timesheet report not showing total amount correctly 2019-04-11 16:07:38 +05:30
Rohit Waghchaure
5eaf7d0517 fix: Pending SO Items For Purchase Request not showing the so quantity correctly if so has duplicate items 2019-04-11 13:56:40 +05:30
Nabin Hait
760b01912a Merge branch 'hotfix' into limit-cond-fix 2019-04-11 11:47:48 +05:30
Nabin Hait
4c331206f1 Merge branch 'hotfix' into patient_hotfix 2019-04-11 11:46:53 +05:30
Nabin Hait
02181c017a Merge branch 'hotfix' into patch-2 2019-04-11 11:46:39 +05:30
Nabin Hait
7fece8f431 Merge branch 'hotfix' into revert-16926-salary-slip-fix 2019-04-11 11:46:35 +05:30
Nabin Hait
bd7a165318 Merge branch 'hotfix' into ar-credit-note 2019-04-11 11:46:16 +05:30
Nabin Hait
4114365017 Merge branch 'hotfix' into hotfix-company-address-label 2019-04-11 11:46:08 +05:30
Nabin Hait
aace25ac2b Merge branch 'hotfix' into vedmata-print-fixes 2019-04-11 11:46:00 +05:30
Nabin Hait
697f1186c0 Merge branch 'hotfix' into duplicate-variant-check 2019-04-11 11:45:49 +05:30
Nabin Hait
55bee7a393 Merge branch 'hotfix' into allow-items-not-in-stock 2019-04-11 11:45:42 +05:30
Nabin Hait
c151b58acd Merge branch 'hotfix' into rounding-adjustment-gle 2019-04-11 11:45:36 +05:30
Nabin Hait
0f62b13dd8 Merge pull request #17159 from rohitwaghchaure/sales_return_not_working_for_bundle_items
fix: sales return not working for product bundle items
2019-04-11 11:44:57 +05:30
Nabin Hait
961d7ace4a Merge pull request #17189 from nabinhait/sales-person
fix: Made employee optional in sales person
2019-04-11 11:37:08 +05:30
Nabin Hait
38351587fc Merge pull request #17197 from nabinhait/training-feedback
fix: training feedback code cleanup
2019-04-11 11:36:50 +05:30
rohitwaghchaure
4898d1936b Merge pull request #17200 from Anurag810/pos_running
fix: order by idx(v11)
2019-04-11 10:57:05 +05:30
rohitwaghchaure
22d6eb3eaa Merge pull request #17191 from rohitwaghchaure/asset_depreciation_rate_hotfix
fix: Asset depreciation formula for WDV method, user was not able to edit schedule table for Manula method
2019-04-11 09:58:02 +05:30
rohitwaghchaure
6cd114b467 Merge pull request #17198 from rohitwaghchaure/fix_auto_assign_payment_entry_to_invoice
fix: don't assign the advance payment entries if Allocate Advances Automatically is disabled
2019-04-11 09:57:45 +05:30
rohitwaghchaure
2521b1347b Merge pull request #17201 from rohitwaghchaure/fix_test_cases_for_item_variant
Fix: item variant test cases
2019-04-10 19:16:51 +05:30
Rohit Waghchaure
f3a9552e48 fix: item variant test cases 2019-04-10 17:57:09 +05:30
Anurag Mishra
5ab5f77fd4 fix: order by idx 2019-04-10 17:53:45 +05:30
Rohit Waghchaure
49907e746b fix: test cases 2019-04-10 17:33:32 +05:30
Rohit Waghchaure
45d0b31d44 fix: test cases 2019-04-10 17:25:08 +05:30
Rohit Waghchaure
b286fc99b8 fix: don't assign the advance payment entries if Allocate Advances Automatically is disabled 2019-04-10 16:16:30 +05:30
Nabin Hait
c8c678f747 fix: training feedback code cleanup 2019-04-10 15:56:16 +05:30
Sahil Khan
ef73452abe feat(sync_site): return erpnext data in levels 2019-04-10 15:29:49 +05:30
Rohit Waghchaure
bb0d4e37b9 fix: Asset depreciation formula for WDV method, user was not able to edit schedule table for Manula method 2019-04-10 03:14:11 +05:30
Nabin Hait
b305f38869 fix: Made employee optional in sales person 2019-04-09 20:06:11 +05:30
Nabin Hait
ff73090ad2 fix: Rounding Adjustment GL Entry 2019-04-09 19:24:54 +05:30
Faris Ansari
b63adcbac7 feat: Allow items not in stock to be added in cart 2019-04-09 18:41:31 +05:30
Nabin Hait
7dcdb93596 Merge pull request #17178 from Anurag810/timesheet_report_fixes
fix: timesheet_report (WN-SUP41913)
2019-04-09 17:28:22 +05:30
Faris Ansari
f492d5f61d fix: Validate variant attributes only if is_new 2019-04-09 15:19:10 +05:30
Anurag Mishra
22867f7fa5 fix: added currency 2019-04-09 15:06:49 +05:30
Anurag Mishra
3e8b8a4359 fix: filters and some conditions 2019-04-09 14:34:56 +05:30
Anurag Mishra
17fbafa390 fix: filters,added total,only submitted doc,considered fraction 2019-04-09 11:31:11 +05:30
Faris Ansari
aac7719dd9 fix: Translated string method in Jinja (#17174) 2019-04-08 21:50:58 +05:30
Rushabh Mehta
2cce72412d Merge pull request #17168 from frappe/revert-17086-check-version-hf
Revert "fix: Raise exception if apps are on incompatible branches"
2019-04-08 17:11:15 +05:30
Rushabh Mehta
1412a681f3 Revert "fix: Raise exception if apps are on incompatible branches" 2019-04-08 17:10:56 +05:30
Saurabh
b0c939d280 Merge branch 'hotfix' 2019-04-08 15:09:04 +05:30
Saurabh
00a5e7a1d0 bumped to version 11.1.20 2019-04-08 15:39:03 +06:00
Nabin Hait
f1698bb2df fix: unique variant based on 2019-04-08 14:59:43 +05:30
Anurag Mishra
4ac386d0fe fix: Removed Extra page on generating pdf in print formats 2019-04-08 11:43:24 +05:30
Anurag Mishra
4753bd4519 fix: UI on generating pdf in print format 2019-04-08 10:53:19 +05:30
Nabin Hait
79c9d5d24a Merge pull request #17146 from Anurag810/timesheet-report
feat: Timesheet report
2019-04-08 10:33:44 +05:30
Rohit Waghchaure
3771db92b8 fix: sales return not working for bundle items 2019-04-06 17:34:40 +05:30
Anurag Mishra
76815cf2be fix: removed before from accounts_controlle.pyr and fetch the gl from frontend 2019-04-06 12:07:40 +05:30
Rohan Bansal
936d147b4b fix(selling): Add missing label to company address field 2019-04-05 18:15:04 +05:30
Nabin Hait
20090306f6 fix: Show standalone credit note in Accounts receivable report 2019-04-05 18:06:07 +05:30
Saurabh
c32f8eb0cb Merge branch 'hotfix' 2019-04-05 16:59:22 +05:30
Saurabh
63fabc3723 bumped to version 11.1.19 2019-04-05 17:29:22 +06:00
Nabin Hait
d70476fbc8 Merge pull request #17139 from hrwX/pe_supp_inv_v11
fix(Payment Entry): Return Bill No for Payment Entry
2019-04-05 15:59:43 +05:30
Nabin Hait
8cf76e74e0 Merge pull request #17133 from hrwX/validate_stock_transaction_v11
fix(Item): check transactions for batch, serial check
2019-04-05 15:41:35 +05:30
Nabin Hait
843e440191 Merge branch 'hotfix' into validate_stock_transaction_v11 2019-04-05 15:41:26 +05:30
Nabin Hait
1580e24946 Merge pull request #17137 from netchampfaris/item-group-clean-description
fix(Item Group): Don't clean description html
2019-04-05 15:39:44 +05:30
Nabin Hait
603dce428b Merge pull request #17144 from nabinhait/variant-fix
fix: Default variant Based on
2019-04-05 15:38:15 +05:30
Anurag Mishra
0dc62e8747 fix: Removed raw query and used frappe.get_all 2019-04-05 14:36:43 +05:30
Anurag Mishra
f71c147ea8 Added mandatory feilds to the report 2019-04-05 14:36:43 +05:30
Anurag Mishra
5c17e7760b fix: readability 2019-04-05 14:36:43 +05:30
Anurag Mishra
b57c024ff7 feat: Project Billing Summary for timesheet 2019-04-05 14:36:43 +05:30
Anurag Mishra
61aab377b6 Minor Fixes 2019-04-05 14:36:42 +05:30
Anurag Mishra
3d27aabdeb Commonify code 2019-04-05 14:36:42 +05:30
Anurag Mishra
94514ffee9 feat: timesheet Employee Summary Report 2019-04-05 14:36:42 +05:30
rohitwaghchaure
e334413b34 Merge pull request #17141 from rohitwaghchaure/incorrect_pos_profile_selected_if
fix: incorrect auto POS profile selected in the sales invoice
2019-04-05 13:04:05 +05:30
Anurag Mishra
a1a7beb12e fix: Print Auditing print format 2019-04-05 12:35:46 +05:30
Nabin Hait
a3357e4e86 fix: Default variant Based on 2019-04-05 12:10:36 +05:30
Himanshu Warekar
9f2847e86c fix: test case fixes for travis 2019-04-05 11:40:37 +05:30
Rohit Waghchaure
4324f43a06 always set the company from the POS Profile 2019-04-05 09:54:55 +05:30
Rohit Waghchaure
f7a83cb4f5 fix: incorrect POS profile selected 2019-04-05 00:42:48 +05:30
Himanshu Warekar
6443d7dd10 refactor: declare bill_on at function start 2019-04-04 19:54:23 +05:30
Himanshu Warekar
ad32324c4c fix: get bill_no 2019-04-04 19:50:23 +05:30
Faris Ansari
7a0a05d8f1 fix(Item Group): Don't clean description html 2019-04-04 15:53:16 +05:30
Himanshu Warekar
44d8224a3b fix: test case fix 2019-04-04 15:40:36 +05:30
Himanshu Warekar
7f253b679a pull from hotfix 2019-04-04 15:19:44 +05:30
Himanshu Warekar
28db545947 fix: check transactions for batch, serial check 2019-04-04 15:02:25 +05:30
Nabin Hait
82bd388993 Merge pull request #17122 from frappe/asbasawaraj-remove-location-from-abbreviation-doctypes
fix: Removed Location from Abbreviation Update DocTypes
2019-04-04 11:50:33 +05:30
Nabin Hait
e0a9835f30 Merge pull request #16987 from SaiFi0102/Party-Ledger-Summary-Fix
fix(Party Ledger Summary): Show all adjustment entries as columns
2019-04-04 11:45:36 +05:30
Nabin Hait
0747273ea4 Merge pull request #17028 from sagarvora/field_order
fix(accounts): dependent field should be displayed after source link field
2019-04-04 11:45:01 +05:30
Nabin Hait
9eeb3715f0 Merge pull request #16992 from hrwX/cost_center
fix(Purchase Invoice): Cost Centre as per company
2019-04-04 11:43:35 +05:30
Nabin Hait
2df623c693 Merge pull request #17072 from kennethsequeira/auto-re-val
fix: spelling in validation message for Auto-reorder
2019-04-04 11:40:08 +05:30
Nabin Hait
1e5664ba5f Update item.py 2019-04-04 11:39:55 +05:30
Nabin Hait
f4ae29320f Merge pull request #17087 from deepeshgarg007/payment_entry
Party type validation in payment entry
2019-04-04 11:39:00 +05:30
Nabin Hait
f86a01446f Merge pull request #17086 from adityahase/check-version-hf
fix: Raise exception if apps are on incompatible branches
2019-04-04 11:17:04 +05:30
Nabin Hait
9ee417888e Merge pull request #17092 from nabinhait/ar-ap-print
fix: Show Sales Person in AR/AP print is optional
2019-04-04 11:02:26 +05:30
Nabin Hait
2c869bd486 Merge pull request #17101 from hrwX/india_setup
fix(India): Add HSN/SAC in setup
2019-04-04 11:02:11 +05:30
Himanshu
c930cb10fa fix: remove duplicate doctype 2019-04-04 11:01:10 +05:30
Nabin Hait
91b1875ccf Merge pull request #17099 from nabinhait/return-precision-issue
fix: Validate returned qty with ref qty considering field precision
2019-04-04 10:59:26 +05:30
Nabin Hait
2092a8b1cf Merge pull request #17100 from nabinhait/gl-entry-precision
fix: Validate gl entry debit/credit as per field's precision
2019-04-04 10:59:06 +05:30
Nabin Hait
6ffdddc100 Merge pull request #17126 from rmehta/warehouse-account-description
fix(kaizen): warehouse account description
2019-04-04 10:50:52 +05:30
Nabin Hait
d2c370a215 Merge pull request #17113 from deepeshgarg007/item-register
fix: Divide by zero exception handling
2019-04-04 10:49:13 +05:30
Rushabh Mehta
1f0edabda8 fix(kaizen): warehouse account description 2019-04-04 08:58:34 +05:30
Rushabh Mehta
e7b6b46309 Merge pull request #17109 from PawanMeh/fixes_16894_v11
fix: Amazon v11 integration issues
2019-04-03 22:54:43 +05:30
asbasawaraj
d2b69445b1 Removed Location from Abbreviation Update DocTypes 2019-04-03 17:05:53 +05:30
Himanshu Warekar
5ba438af80 fix: fetch payment terms 2019-04-03 16:53:19 +05:30
rohitwaghchaure
fb48686d82 Merge pull request #17118 from rohitwaghchaure/_incorrect_prezzototale
fix: incorrect PrezzoTotale
2019-04-03 16:33:56 +05:30
Rohit Waghchaure
a2f71cdeec fix: incorrect PrezzoTotale 2019-04-03 16:10:14 +05:30
Nabin Hait
b1f3f04d71 fix: Validate gl entry debit/credit as per field's precision 2019-04-03 12:30:25 +05:30
deepeshgarg007
5ad7b655cf fix: Divide by zero exception handling 2019-04-03 09:11:03 +05:30
hello@openetech.com
ea00f8cbc3 [fix] #16894 2019-04-02 14:22:23 +05:30
rohitwaghchaure
b035bf7f39 Merge pull request #17095 from rohitwaghchaure/incorrect_calculation_of_imponibile_importo
fix: incorrect calcualtion of ImponibileImporto if tax rate is zero
2019-04-01 23:14:56 +05:30
Himanshu Warekar
624477cb21 fix(India): Add HSN/SAC in setup 2019-04-01 19:25:28 +05:30
Nabin Hait
b4263a41c6 fix: Validate gl entry debit/credit as per field's precision 2019-04-01 19:11:34 +05:30
Nabin Hait
88f036a171 fix: Validate returned qty with ref qty considering field precision 2019-04-01 18:41:31 +05:30
Nabin Hait
0049986efd Merge pull request #17088 from nabinhait/hsn-fixes
fix: Fetch HSN code only if empty
2019-04-01 18:17:26 +05:30
Rohit Waghchaure
ebc2437516 fix: calcualtion of ImponibileImporto if tax rate is zero 2019-04-01 17:50:31 +05:30
Nabin Hait
51d08786dc fix: Show Sales Person in AR/AP print is optional 2019-04-01 16:24:23 +05:30
Nabin Hait
f4af608408 fix: Fetch HSN code only if empty 2019-04-01 11:51:54 +05:30
deepeshgarg007
4614eb219b Merge branch 'hotfix' of https://github.com/frappe/erpnext into payment_entry 2019-04-01 11:48:07 +05:30
Aditya Hase
b841cb2a66 fix: Raise exception if apps are on incompatible branches 2019-04-01 11:36:57 +05:30
Nabin Hait
4873875c1c Merge pull request #17038 from netchampfaris/fix-leave-application-condition
fix: Missing "and" in filter conditions
2019-04-01 11:15:36 +05:30
Nabin Hait
093f4c529b Merge pull request #17055 from deepeshgarg007/tds
fix: TDS payable monthly report fix
2019-04-01 11:12:45 +05:30
Nabin Hait
3d6b51089c Revert "fix(Salary Slip): Consider Leave without Pay for calculation (#16926)"
This reverts commit 6343a697a2.
2019-04-01 11:09:55 +05:30
Aulia Bismar
f817663f11 Renumber Aktiva, remove excess 0 2019-04-01 10:37:28 +07:00
deepeshgarg007
d0b98d74de fix: Allow doctype only in party account types 2019-03-30 19:44:31 +05:30
Nabin Hait
08319cecf5 Merge pull request #17074 from nabinhait/woocommerce-fix
fix: Woo-commerce fix
2019-03-30 19:12:38 +05:30
Nabin Hait
f9f04ed89e fix: woocommerce settings 2019-03-30 17:39:40 +05:30
Kenneth Sequeira
4f5839eb65 fixed spelling in validation message
fixed typo in auto-reorder validation message
2019-03-30 15:37:51 +05:30
Saurabh
05c8474db3 Merge branch 'hotfix' 2019-03-30 15:00:36 +05:30
Saurabh
75b4de3e20 bumped to version 11.1.18 2019-03-30 15:30:36 +06:00
rohitwaghchaure
892f675cf7 Merge pull request #17069 from frappe/revert-16950-fix-issue-credit
feat: Revert "Fix(Delivery Note): Fix issue credit note"
2019-03-30 14:25:08 +05:30
rohitwaghchaure
223bd45e06 Merge pull request #17039 from surajshetty3416/fix-bom-item-subquery-issue
fix: Subquery in get_bom_items method
2019-03-30 14:23:25 +05:30
rohitwaghchaure
f3a1fa0bae Revert "Fix(Delivery Note): Fix issue credit note" 2019-03-30 12:33:54 +05:30
rohitwaghchaure
5fdbdd50f9 Merge pull request #16950 from hrwX/fix-issue-credit
Fix(Delivery Note): Fix issue credit note
2019-03-30 12:31:18 +05:30
Himanshu
52ae923566 fix(Update GSTIN): remove '.__' from template (#17061)
'.__'  Avoid Server Side Template Injection
2019-03-30 12:11:27 +05:30
rohitwaghchaure
9d159be826 Merge pull request #17064 from rohitwaghchaure/not_able_to_create_chart_of_account
fix: user not able to create chart of account in parent if child has no chart of account
2019-03-30 10:14:19 +05:30
rohitwaghchaure
d4365e25c4 Merge pull request #17063 from scmmishra/hotfix
fix: healthcare unit type enable toggle
2019-03-30 10:13:30 +05:30
scmmishra
6f82f96816 Merge branch 'hotfix' of https://github.com/frappe/erpnext into hotfix 2019-03-29 20:05:40 +05:30
rohitwaghchaure
8dadd4b0b2 Merge pull request #17059 from rohitwaghchaure/cherry_pick_test_case_fix
fix: cherry-pick item variant test cases fix
2019-03-29 19:32:30 +05:30
Rohit Waghchaure
fd2b1385a3 fix: user not able to create chart of account in parent if child has no chart of account 2019-03-29 19:20:47 +05:30
scmmishra
29dc744354 fix: healtcare unit type enable toggle 2019-03-29 19:00:45 +05:30
Himanshu
6343a697a2 fix(Salary Slip): Consider Leave without Pay for calculation (#16926)
while net salary calculation, it was not considering actual days worked but now it will consider it
2019-03-29 18:48:56 +05:30
rohitwaghchaure
13752774ab Merge pull request #17000 from scmmishra/hotfix-task-status
fix: Task overdue status propagates to project
2019-03-29 18:44:36 +05:30
Rushabh Mehta
c4599c21c3 fix(test): item variant 2019-03-29 18:30:00 +05:30
rohitwaghchaure
fb8f1b93d6 Merge pull request #17058 from hrwX/bank_reco_fix
fix(Bank Reconciliation): get credit and debit in float and not string
2019-03-29 18:18:15 +05:30
Himanshu Warekar
f7f85f7379 fix: get credit and debit in float and not string 2019-03-29 16:19:15 +05:30
deepeshgarg007
4092ead41e fix: fetch account only if available 2019-03-29 16:19:04 +05:30
Faris Ansari
eec89ba4cb Merge branch 'hotfix' of https://github.com/frappe/erpnext into fix-leave-application-condition 2019-03-29 16:06:38 +05:30
Nabin Hait
862f77cc13 Merge branch 'deferred_revenue' into hotfix 2019-03-29 13:26:16 +05:30
Nabin Hait
66d07c2700 fix(accounts): Indentation 2019-03-29 13:25:11 +05:30
Nabin Hait
cf7538c17f Merge pull request #17046 from nabinhait/deferred_revenue
Refactor: deferred revenue booking logic
2019-03-29 12:39:36 +05:30
rohitwaghchaure
043cfe99ad Merge pull request #17051 from rohitwaghchaure/accounts_receivable_summary_issue
fix: accounts receivable summary
2019-03-29 09:28:21 +05:30
rohitwaghchaure
c268682772 Merge pull request #17048 from rohitwaghchaure/fixed_bank_reconciliation_not_working
fix: bank reconciliation not working
2019-03-29 09:27:50 +05:30
Rohit Waghchaure
9da14747aa fix: accounts receivable summary 2019-03-29 09:26:40 +05:30
Rohit Waghchaure
573d1dd31f fix: bank reconciliation not working 2019-03-28 20:39:49 +05:30
Nabin Hait
86fb523ea7 fix(accounts): codacy fixes 2019-03-28 20:06:57 +05:30
Nabin Hait
0a90ce5cf6 Refactored deferred revenue booking logic 2019-03-28 19:43:02 +05:30
Faris Ansari
f04988a02f fix: Missing "and" in filter conditions 2019-03-28 15:42:07 +05:30
Suraj Shetty
6262c9ed6a fix: Subquery in get_bom_items method 2019-03-28 14:59:27 +05:30
Saurabh
6cc9831ce9 Merge branch 'hotfix' 2019-03-28 13:51:58 +05:30
Saurabh
f2036dd1d1 bumped to version 11.1.17 2019-03-28 14:21:58 +06:00
Saurabh
1271dea39b Merge pull request #17035 from gaurav-naik/issue-17033
fix(regional,italy): autoset tax id, cf from customer before validating
2019-03-28 12:46:24 +05:30
rohitwaghchaure
89a2577ae5 Merge pull request #17032 from surajshetty3416/fix-group-same-items-in-printview
fix(print): Fix group same items for print view
2019-03-28 12:42:22 +05:30
Gaurav
bd80fd13cb fix(regional,italy): autoset company cf, tax_id before validating 2019-03-28 12:18:03 +05:30
Nabin Hait
bf5ea691cf fixed merge conflict 2019-03-28 11:35:39 +05:30
Saurabh
ea19250884 Merge pull request #16859 from rohitwaghchaure/added_new_tags_e_invoice_xml
fix: added tags for discount amount, multiple customer po no, delivery notes
2019-03-28 11:19:44 +05:30
Gaurav
010acf75fa fix(regional,italy): autoset tax id, cf from customer before validating missing values
Fixes issue #17033
2019-03-28 10:42:29 +05:30
Suraj Shetty
a7992ecb62 style: Fix formatting 2019-03-27 20:32:42 +05:30
Suraj Shetty
abc2a64d5e fix: Commonify get gl_entry code by moving it to accounts_controller 2019-03-27 20:25:18 +05:30
Sagar Vora
d20ecb0a71 fix(accounts): dependent field should be displayed after source link field 2019-03-27 17:42:42 +05:30
Rohit Waghchaure
1b7059b867 fix: ImponibileImporto calculation 2019-03-27 15:33:47 +05:30
scmmishra
2405e14dde Merge branch 'hotfix-task-status' of github.com:scmmishra/erpnext into hotfix-task-status 2019-03-27 15:02:35 +05:30
scmmishra
36824cf7fb feat: refactored update status 2019-03-27 15:01:40 +05:30
rohitwaghchaure
4510e3a836 Merge pull request #17020 from rohitwaghchaure/offline_pos_duplicate_records_making
fix: offline pos, duplicate records creating
2019-03-26 22:49:42 +05:30
Himanshu
e43b6beff0 fix(Leave Balance Report): total allocated leaves not calculated properly (#16969)
* fix: total alloted leaves not calculated properly

* fix: Possible SQL injection

* typo fix in sql query

* prevent sql injection again ?

* Use ORM for query
2019-03-26 21:42:12 +05:30
Rohit Waghchaure
22ebaf1b11 fix: added tags for discount amount, multiple customer po no, delivery notes 2019-03-26 20:19:46 +05:30
Rohit Waghchaure
1df62097f6 fix: offline pos, duplicate records creating 2019-03-26 19:15:53 +05:30
Prateeksha Singh
6d2bb9126a Merge pull request #17019 from pratu16x7/hotfix-stock_entry_from_bom
fix(uom): Get items as per UOM defined in BOM
2019-03-26 18:00:50 +05:30
Nabin Hait
411f66a177 Merge pull request #17006 from deepeshgarg007/account-fix
fix: Ignore root company validation setting in company master
2019-03-26 17:49:21 +05:30
deepeshgarg007
3eeb1cacb0 fix: Change name to Allow Account Creation against Child Company in company master 2019-03-26 17:18:06 +05:30
Prateeksha Singh
a0927c1ba6 fix: correct use of include_item_in_manufacturing 2019-03-26 16:55:13 +05:30
Nabin Hait
8aaee57921 fix(uom): Get items as per UOM defined in BOM, fixes #15081 2019-03-26 16:53:13 +05:30
deepeshgarg007
c45c2bdabb fix: Missing semicolon 2019-03-26 15:38:38 +05:30
deepeshgarg007
7aefc15352 fix: Allow to add child account if ignore validation checked 2019-03-26 15:09:29 +05:30
Raffael Meyer
fdbb516a1b fix(projects): Auto-set employee and company in Timesheet (#16743)
* fix(projects): auto-set employee and company

* only set employee and company if document is unsaved

* use frm.set_value()
2019-03-26 12:47:36 +05:30
deepeshgarg007
1c785a99b1 fix: Added setting in company to ignore root company validation 2019-03-25 22:32:29 +05:30
Faris Ansari
843b7f6dd5 fix: Reorder Currency column to fix print (#17008)
Every Financial Report's 2nd column is Currency, which is an implicit requirement to Print them properly. In this case, Income column was not printed. This fixes that.
2019-03-25 15:50:36 +05:30
rohitwaghchaure
0a03e3d30c Merge pull request #17011 from rohitwaghchaure/fix_incorrect_paid_amt_in_accounts_receivable_summary_report
fix: incorrect paid amount in accounts receivable summary report
2019-03-25 15:41:29 +05:30
Rohit Waghchaure
4ed7d035cb fix: incorrect paid amount in accounts receivable summary report 2019-03-25 15:37:25 +05:30
rohitwaghchaure
794b6b6c0d Merge pull request #17004 from surajshetty3416/fix-bank-reconciliation-entries-hotfix
fix: Show consolidated amount of payment entries in Bank reconciliation
2019-03-25 14:11:47 +05:30
Rushabh Mehta
689490e4de Merge pull request #16986 from hrwX/italy_xml_fix
fix(Italy Customisation): Include fiscal code in invoice xml if present
2019-03-25 11:57:30 +05:30
deepeshgarg007
4f9ac0ad55 fix: Child company account currency fix 2019-03-25 11:39:25 +05:30
Shivam Mishra
ec56122876 fix: minor fix in test 2019-03-25 11:36:43 +05:30
scmmishra
1af3c41da3 fix: Typo in update_status 2019-03-25 11:34:33 +05:30
Suraj Shetty
67876d1026 fix: Show amount of entry based on diff of credit and debit 2019-03-25 11:19:07 +05:30
scmmishra
f7f32634c8 feat: Added check for no end date and refactored query 2019-03-24 20:43:15 +05:30
scmmishra
6ab6d35f92 fix: Task Overdue status propagates to project
- Used ORM instead of a SQL for set_task_as_overdue
- update_status function compares the time and marks the appropriate task as overdue
- The on_update hook makes the changes in project as well
2019-03-24 18:17:13 +05:30
rohitwaghchaure
9673d0ddae fix: description missing in the XML (#16985) 2019-03-24 12:19:58 +05:30
Himanshu Warekar
92593bb717 fix: Cost center as per company 2019-03-23 19:46:31 +05:30
Himanshu
138e030055 CodiceFiscale should be after IdFiscaleIVA 2019-03-22 23:22:52 +05:30
Saif Ur Rehman
7d1c1aa28f fix(Party Ledger Summary): Show all adjustment entries as columns
Consider only Income Account or Expense Account account type for adjustment amounts
Check if GL Entry's is_opening == "Yes"
2019-03-22 17:18:32 +05:00
Himanshu Warekar
1d04ea1212 fix: include fiscal code in invoice xml if present 2019-03-22 17:47:57 +05:30
Jamsheer
48e206d983 fix: Patient relation - patient link is not showing 2019-03-21 16:11:12 +05:30
Himanshu Warekar
2f5f17fcbb refactor: fix issue credit note 2019-03-18 21:46:26 +05:30
Himanshu
bed6f4748e Merge pull request #6 from frappe/hotfix
Hotfix
2019-03-18 20:48:26 +05:30
Himanshu
ee2b523b31 Merge pull request #5 from frappe/hotfix
Hotfix
2019-03-09 00:05:50 +05:30
Sahil Khan
88bd0674ed fix: set warehouse from defalut_warehouse_for_sales_return in sales return 2019-02-26 14:50:20 +05:30
Nabin Hait
4ff2b0114f fix: Removed limit conditionas it does not make sense in get_outstanding function 2019-02-21 17:48:21 +05:30
Nabin Hait
e7cc6649eb fix: Limit conditions while fetching payment entries 2019-02-21 17:23:23 +05:30
Charles-Henri Decultot
4d19d344b6 Merge branch 'hotfix' into plaid_reconciliation 2019-02-19 11:05:00 +00:00
Himanshu
e7bc2beea0 Remove illegal character after break 2019-02-06 15:55:49 +05:30
Himanshu
cd416a3135 Merge pull request #4 from frappe/hotfix
Hotfix
2019-02-06 15:54:33 +05:30
Nabin Hait
2a0e8e24ec Merge branch 'staging-fixes' into plaid_reconciliation 2019-01-24 14:11:00 +05:30
Charles-Henri Decultot
c75300dc43 Purchase invoice modified date 2019-01-07 15:46:25 +00:00
Charles-Henri Decultot
8d36b362d1 Merge conflict resolution 2019-01-07 15:24:39 +00:00
Charles-Henri Decultot
4c57fae726 Codacy correction 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
2d1b5b0769 Codacy corrections 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
1d7646f31f Codacy corrections 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
1a19746904 Codacy corrections 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
e7fec6e659 Codacy corrections 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
c45e271b3e Add button to unlink bank account 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
422d483baf Move actions menu to standard menu 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
c56f771c81 UX corrections + additional tests 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
89923b84b1 UX enhancements 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
c936f07a1e Correct Travis error 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
aea2fbf82d Correct test case for Travis 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
7a1ea42271 Addition of test cases 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
58438f4e5b Duplicate query to avoid SQL injection 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
f6d18e81e9 Modify SQL queries and add a test case 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
e8f3050e27 Codacy corrections 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
cbe63ec418 Codacy corrections 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
94899981d3 Dev cleanup 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
6a4dae3a9d Codacy corrections + sql queries 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
57c6b49d1a Dev cleanup 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
eae7424984 Cleanup dev 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
e394cec194 Bank reconciliation dashboard 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
818492387a WIP 2019-01-07 15:21:57 +00:00
Charles-Henri Decultot
31cb24f48d Bank reconciliation WIP 2019-01-07 15:20:06 +00:00
Charles-Henri Decultot
590d8d3d3e Bank reconciliation wip 2019-01-07 15:20:06 +00:00
Charles-Henri Decultot
6025e498f2 Bank reconciliation wip 2019-01-07 15:20:06 +00:00
Charles-Henri Decultot
09cad814cd Reconciliation dashboard wip 2019-01-07 15:20:06 +00:00
Charles-Henri Decultot
c75a2b1eed Plaid integration 2019-01-07 15:20:06 +00:00
269 changed files with 28363 additions and 16310 deletions

View File

@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '11.1.16'
__version__ = '11.1.26'
def get_default_company(user=None):
'''Get default company for user'''

View File

@@ -2,9 +2,9 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt, get_last_day
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.general_ledger import make_gl_entries
from frappe.email import sendmail_to_system_managers
def validate_service_stop_date(doc):
''' Validates service_stop_date for Purchase Invoice and Sales Invoice '''
@@ -33,47 +33,49 @@ def validate_service_stop_date(doc):
frappe.throw(_("Cannot change Service Stop Date for item in row {0}".format(item.idx)))
def convert_deferred_expense_to_expense(start_date=None, end_date=None):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
if not start_date:
start_date = add_months(today(), -1)
if not end_date:
end_date = add_days(today(), -1)
# check for the purchase invoice for which GL entries has to be done
invoices = frappe.db.sql_list('''
select distinct parent from `tabPurchase Invoice Item` where service_start_date<=%s and service_end_date>=%s
select distinct parent from `tabPurchase Invoice Item`
where service_start_date<=%s and service_end_date>=%s
and enable_deferred_expense = 1 and docstatus = 1 and ifnull(amount, 0) > 0
''', (end_date or today(), start_date or add_months(today(), -1)))
''', (end_date, start_date))
# For each invoice, book deferred expense
for invoice in invoices:
doc = frappe.get_doc("Purchase Invoice", invoice)
book_deferred_income_or_expense(doc, start_date, end_date)
book_deferred_income_or_expense(doc, end_date)
def convert_deferred_revenue_to_income(start_date=None, end_date=None):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
if not start_date:
start_date = add_months(today(), -1)
if not end_date:
end_date = add_days(today(), -1)
# check for the sales invoice for which GL entries has to be done
invoices = frappe.db.sql_list('''
select distinct parent from `tabSales Invoice Item` where service_start_date<=%s and service_end_date>=%s
select distinct parent from `tabSales Invoice Item`
where service_start_date<=%s and service_end_date>=%s
and enable_deferred_revenue = 1 and docstatus = 1 and ifnull(amount, 0) > 0
''', (end_date or today(), start_date or add_months(today(), -1)))
''', (end_date, start_date))
# For each invoice, book deferred revenue
for invoice in invoices:
doc = frappe.get_doc("Sales Invoice", invoice)
book_deferred_income_or_expense(doc, start_date, end_date)
book_deferred_income_or_expense(doc, end_date)
def get_booking_dates(doc, item, posting_date=None):
if not posting_date:
posting_date = add_days(today(), -1)
last_gl_entry = False
def get_booking_dates(doc, item, start_date=None, end_date=None):
deferred_account = "deferred_revenue_account" if doc.doctype=="Sales Invoice" else "deferred_expense_account"
last_gl_entry, skip = False, False
booking_end_date = getdate(add_days(today(), -1) if not end_date else end_date)
if booking_end_date < item.service_start_date or \
(item.service_stop_date and booking_end_date.month > item.service_stop_date.month):
return None, None, None, True
elif booking_end_date >= item.service_end_date:
last_gl_entry = True
booking_end_date = item.service_end_date
elif item.service_stop_date and item.service_stop_date <= booking_end_date:
last_gl_entry = True
booking_end_date = item.service_stop_date
booking_start_date = getdate(add_months(today(), -1) if not start_date else start_date)
booking_start_date = booking_start_date \
if booking_start_date > item.service_start_date else item.service_start_date
prev_gl_entry = frappe.db.sql('''
select name, posting_date from `tabGL Entry` where company=%s and account=%s and
@@ -81,17 +83,28 @@ def get_booking_dates(doc, item, start_date=None, end_date=None):
order by posting_date desc limit 1
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
if not prev_gl_entry and item.service_start_date < booking_start_date:
booking_start_date = item.service_start_date
elif prev_gl_entry:
booking_start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
skip = True if booking_start_date > booking_end_date else False
if prev_gl_entry:
start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
else:
start_date = item.service_start_date
return last_gl_entry, booking_start_date, booking_end_date, skip
end_date = get_last_day(start_date)
if end_date >= item.service_end_date:
end_date = item.service_end_date
last_gl_entry = True
elif item.service_stop_date and end_date >= item.service_stop_date:
end_date = item.service_stop_date
last_gl_entry = True
def calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days):
account_currency = get_account_currency(item.expense_account)
if end_date > getdate(posting_date):
end_date = posting_date
if getdate(start_date) <= getdate(end_date):
return start_date, end_date, last_gl_entry
else:
return None, None, None
def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, account_currency):
if doc.doctype == "Sales Invoice":
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
deferred_account = "deferred_revenue_account"
@@ -123,28 +136,15 @@ def calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total
return amount, base_amount
def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
# start_date: 1st of the last month or the start date
# end_date: end_date or today-1
def book_deferred_income_or_expense(doc, posting_date=None):
enable_check = "enable_deferred_revenue" \
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
gl_entries = []
for item in doc.get('items'):
if not item.get(enable_check): continue
skip = False
last_gl_entry, booking_start_date, booking_end_date, skip = \
get_booking_dates(doc, item, start_date, end_date)
if skip: continue
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
total_booking_days = date_diff(booking_end_date, booking_start_date) + 1
def _book_deferred_revenue_or_expense(item):
start_date, end_date, last_gl_entry = get_booking_dates(doc, item, posting_date=posting_date)
if not (start_date and end_date): return
account_currency = get_account_currency(item.expense_account)
amount, base_amount = calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days)
if doc.doctype == "Sales Invoice":
against, project = doc.customer, doc.project
credit_account, debit_account = item.income_account, item.deferred_revenue_account
@@ -152,36 +152,62 @@ def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
against, project = doc.supplier, item.project
credit_account, debit_account = item.deferred_expense_account, item.expense_account
# GL Entry for crediting the amount in the deferred expense
gl_entries.append(
doc.get_gl_dict({
"account": credit_account,
"against": against,
"credit": base_amount,
"credit_in_account_currency": amount,
"cost_center": item.cost_center,
"voucher_detail_no": item.name,
'posting_date': booking_end_date,
'project': project
}, account_currency)
)
# GL Entry to debit the amount from the expense
gl_entries.append(
doc.get_gl_dict({
"account": debit_account,
"against": against,
"debit": base_amount,
"debit_in_account_currency": amount,
"cost_center": item.cost_center,
"voucher_detail_no": item.name,
'posting_date': booking_end_date,
'project': project
}, account_currency)
)
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
total_booking_days = date_diff(end_date, start_date) + 1
amount, base_amount = calculate_amount(doc, item, last_gl_entry,
total_days, total_booking_days, account_currency)
make_gl_entries(doc, credit_account, debit_account, against,
amount, base_amount, end_date, project, account_currency, item.cost_center, item.name)
if getdate(end_date) < getdate(posting_date) and not last_gl_entry:
_book_deferred_revenue_or_expense(item)
for item in doc.get('items'):
if item.get(enable_check):
_book_deferred_revenue_or_expense(item)
def make_gl_entries(doc, credit_account, debit_account, against,
amount, base_amount, posting_date, project, account_currency, cost_center, voucher_detail_no):
# GL Entry for crediting the amount in the deferred expense
from erpnext.accounts.general_ledger import make_gl_entries
gl_entries = []
gl_entries.append(
doc.get_gl_dict({
"account": credit_account,
"against": against,
"credit": base_amount,
"credit_in_account_currency": amount,
"cost_center": cost_center,
"voucher_detail_no": voucher_detail_no,
'posting_date': posting_date,
'project': project
}, account_currency)
)
# GL Entry to debit the amount from the expense
gl_entries.append(
doc.get_gl_dict({
"account": debit_account,
"against": against,
"debit": base_amount,
"debit_in_account_currency": amount,
"cost_center": cost_center,
"voucher_detail_no": voucher_detail_no,
'posting_date': posting_date,
'project': project
}, account_currency)
)
if gl_entries:
try:
make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
frappe.db.commit()
except:
frappe.db.rollback()
frappe.log_error(message = frappe.get_traceback(), title = _("Error while processing deferred accounting for {0}").format(doc.name))
title = _("Error while processing deferred accounting for {0}").format(doc.name)
traceback = frappe.get_traceback()
frappe.log_error(message=traceback , title=title)
sendmail_to_system_managers(title, traceback)

View File

@@ -98,23 +98,34 @@ class Account(NestedSet):
ancestors = get_root_company(self.company)
if ancestors:
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"):
return
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
else:
descendants = get_descendants_of('Company', self.company)
if not descendants: return
acc_name_map = {}
acc_name = frappe.db.get_value('Account', self.parent_account, "account_name")
parent_acc_name_map = {}
parent_acc_name = frappe.db.get_value('Account', self.parent_account, "account_name")
for d in frappe.db.get_values('Account',
{"company": ["in", descendants], "account_name": acc_name},
{"company": ["in", descendants], "account_name": parent_acc_name},
["company", "name"], as_dict=True):
acc_name_map[d["company"]] = d["name"]
parent_acc_name_map[d["company"]] = d["name"]
if not parent_acc_name_map: return
for company in descendants:
if not parent_acc_name_map.get(company):
frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
.format(company, parent_acc_name))
doc = frappe.copy_doc(self)
doc.flags.ignore_root_company_validation = True
doc.update({"company": company, "account_currency": None,
"parent": acc_name_map[company], "parent_account": acc_name_map[company]})
doc.update({
"company": company,
"account_currency": None,
"parent_account": parent_acc_name_map[company]
})
doc.save()
frappe.msgprint(_("Account {0} is added in the child company {1}")
.format(doc.name, company))

View File

@@ -23,6 +23,10 @@ frappe.treeview_settings["Account"] = {
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;
});
}
}
});
@@ -133,9 +137,10 @@ frappe.treeview_settings["Account"] = {
{
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() &&
node.expandable && !node.hide_add;
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.treeview_settings['Account'].treeview;

View File

@@ -1,6 +1,6 @@
{
"country_code": "de",
"name": "Germany - Kontenplan SKR04",
"name": "SKR04 ohne Kontonummern",
"tree": {
"Bilanz - Aktiva": {
"Anlageverm\u00f6gen": {
@@ -1383,8 +1383,7 @@
"Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge 1": {
"Diskontertr\u00e4ge": {},
"Diskontertr\u00e4ge aus verbundenen Unternehmen": {},
"Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {},
"Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {},
"Laufende Ertr\u00e4ge aus Anteilen an Kapitalgesellschaften 100% / 50% steuerfrei": {},
"Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge 2": {},
"Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge aus verbundenen Unternehmen": {},
"Sonstige Zinsertr\u00e4ge": {},
@@ -1703,4 +1702,4 @@
"root_type": "Asset"
}
}
}
}

View File

@@ -38,24 +38,24 @@
"Kas": {
"Kas Mata Uang Lain": {
"Kas USD": {
"account_number": "1112.0010",
"account_number": "1112.001",
"account_type": "Cash"
},
"account_number": "1112.000"
},
"Kas Rupiah": {
"Kas Besar": {
"account_number": "1111.0020",
"account_number": "1111.002",
"account_type": "Cash"
},
"Kas Kecil": {
"account_number": "1111.0010",
"account_number": "1111.001",
"account_type": "Cash"
},
"account_number": "1111.000",
"account_type": "Cash"
},
"account_number": "1110.0000"
"account_number": "1110.000"
},
"Pendapatan Yang Akan di Terima": {
"Pendapatan Yang di Terima": {
@@ -98,7 +98,7 @@
},
"account_number": "1130.000"
},
"account_number": "1100.0000"
"account_number": "1100.000"
},
"Aktiva Tetap": {
"Aktiva": {
@@ -121,20 +121,20 @@
"Investasi": {
"Investasi": {
"Deposito": {
"account_number": "1231.003",
"account_number": "1231.300",
"is_group": 1
},
"Investai Saham": {
"Investasi Saham": {
"Investasi Saham": {
"account_number": "1231.0011"
"account_number": "1231.101"
},
"account_number": "1231.001"
"account_number": "1231.100"
},
"Investasi Perumahan": {
"Investasi Perumahan": {
"account_number": "1231.0021"
"account_number": "1231.201"
},
"account_number": "1231.002"
"account_number": "1231.200"
},
"account_number": "1231.000"
},
@@ -142,7 +142,7 @@
},
"account_number": "1200.000"
},
"account_number": "1000.0000",
"account_number": "1000.000",
"root_type": "Asset"
},
"Beban": {
@@ -684,4 +684,4 @@
"root_type": "Income"
}
}
}
}

View File

@@ -144,7 +144,7 @@ def _make_test_records(verbose):
# related to Account Inventory Integration
["_Test Account Stock In Hand", "Current Assets", 0, None, None],
# fixed asset depreciation
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
["_Test Accumulated Depreciations", "Current Assets", 0, None, None],
@@ -181,13 +181,17 @@ def get_inventory_account(company, warehouse=None):
return account
def create_account(**kwargs):
account = frappe.get_doc(dict(
doctype = "Account",
account_name = kwargs.get('account_name'),
account_type = kwargs.get('account_type'),
parent_account = kwargs.get('parent_account'),
company = kwargs.get('company')
))
account.save()
return account.name
account = frappe.db.get_value("Account", filters={"account_name": kwargs.get("account_name"), "company": kwargs.get("company")})
if account:
return account
else:
account = frappe.get_doc(dict(
doctype = "Account",
account_name = kwargs.get('account_name'),
account_type = kwargs.get('account_type'),
parent_account = kwargs.get('parent_account'),
company = kwargs.get('company')
))
account.save()
return account.name

View File

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

View File

@@ -0,0 +1,134 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:account_subtype",
"beta": 0,
"creation": "2018-10-25 15:46:08.054586",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "account_subtype",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Account Subtype",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-10-25 15:47:03.841390",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account Subtype",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class AccountSubtype(Document):
pass

View File

@@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Account Subtype", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Account Subtype
() => frappe.tests.make('Account Subtype', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import unittest
class TestAccountSubtype(unittest.TestCase):
pass

View File

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

View File

@@ -0,0 +1,134 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:account_type",
"beta": 0,
"creation": "2018-10-25 15:45:45.789963",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "account_type",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Account Type",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-10-25 15:46:51.042604",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account Type",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class AccountType(Document):
pass

View File

@@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Account Type", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Account Type
() => frappe.tests.make('Account Type', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import unittest
class TestAccountType(unittest.TestCase):
pass

View File

@@ -2,7 +2,29 @@
// For license information, please see license.txt
frappe.ui.form.on('Bank', {
onload: function(frm) {
add_fields_to_mapping_table(frm);
},
refresh: function(frm) {
add_fields_to_mapping_table(frm);
}
});
let add_fields_to_mapping_table = function (frm) {
let options = [];
frappe.model.with_doctype("Bank Transaction", function() {
let meta = frappe.get_meta("Bank Transaction");
meta.fields.forEach(value => {
if (!["Section Break", "Column Break"].includes(value.fieldtype)) {
options.push(value.fieldname);
}
});
});
frappe.meta.get_docfield("Bank Transaction Mapping", "bank_transaction_field",
frm.doc.name).options = options;
frm.fields_dict.bank_transaction_mapping.grid.refresh();
};

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -15,6 +16,7 @@
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -42,6 +44,134 @@
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "data_import_configuration_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Data Import Configuration",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bank_transaction_mapping",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Bank Transaction Mapping",
"length": 0,
"no_copy": 0,
"options": "Bank Transaction Mapping",
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "plaid_access_token",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Plaid Access Token",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@@ -55,7 +185,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-04-07 17:00:21.246202",
"modified": "2018-11-27 16:12:13.938776",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank",
@@ -64,7 +194,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -90,5 +219,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
"track_seen": 0,
"track_views": 0
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Bank Account', {
@@ -12,6 +12,11 @@ frappe.ui.form.on('Bank Account', {
}
};
});
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' }
@@ -24,5 +29,13 @@ frappe.ui.form.on('Bank Account', {
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", "");
});
});
}
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -13,16 +13,47 @@ class BankAccount(Document):
"""Load address and contacts in `__onload`"""
load_address_and_contact(self)
def autoname(self):
self.name = self.account_name + " - " + self.bank
def on_trash(self):
delete_contact_and_address('BankAccount', self.name)
def validate(self):
self.validate_company()
self.validate_iban()
def validate_company(self):
if self.is_company_account and not self.company:
frappe.throw(_("Company is manadatory for company account"))
def validate_iban(self):
'''
Algorithm: https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN
'''
# IBAN field is optional
if not self.iban:
return
def encode_char(c):
# Position in the alphabet (A=1, B=2, ...) plus nine
return str(9 + ord(c) - 64)
# remove whitespaces, upper case to get the right number from ord()
iban = ''.join(self.iban.split(' ')).upper()
# Move country code and checksum from the start to the end
flipped = iban[4:] + iban[:4]
# Encode characters as numbers
encoded = [encode_char(c) if ord(c) >= 65 and ord(c) <= 90 else c for c in flipped]
to_check = int(''.join(encoded))
if to_check % 97 != 1:
frappe.throw(_('IBAN is not valid'))
@frappe.whitelist()
def make_bank_account(doctype, docname):
doc = frappe.new_doc("Bank Account")

View File

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

View File

@@ -23,36 +23,36 @@ class BankReconciliation(Document):
journal_entries = frappe.db.sql("""
select
"Journal Entry" as payment_document, t1.name as payment_entry,
t1.cheque_no as cheque_number, t1.cheque_date,
select
"Journal Entry" as payment_document, t1.name as payment_entry,
t1.cheque_no as cheque_number, t1.cheque_date,
sum(t2.debit_in_account_currency) as debit, sum(t2.credit_in_account_currency) as credit,
t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency
t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency
from
`tabJournal Entry` t1, `tabJournal Entry Account` t2
where
t2.parent = t1.name and t2.account = %s and t1.docstatus=1
and t1.posting_date >= %s and t1.posting_date <= %s
and t1.posting_date >= %s and t1.posting_date <= %s
and ifnull(t1.is_opening, 'No') = 'No' {0}
group by t2.account, t1.name
order by t1.posting_date ASC, t1.name DESC
""".format(condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
payment_entries = frappe.db.sql("""
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no as cheque_number, reference_date as cheque_date,
if(paid_from=%(account)s, paid_amount, "") as credit,
if(paid_from=%(account)s, "", received_amount) as debit,
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no as cheque_number, reference_date as cheque_date,
if(paid_from=%(account)s, paid_amount, 0) as credit,
if(paid_from=%(account)s, 0, received_amount) as debit,
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
from `tabPayment Entry`
where
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
and posting_date >= %(from)s and posting_date <= %(to)s {0}
order by
order by
posting_date ASC, name DESC
""".format(condition),
""".format(condition),
{"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1)
pos_entries = []
@@ -79,8 +79,12 @@ class BankReconciliation(Document):
for d in entries:
row = self.append('payment_entries', {})
amount = d.debit if d.debit else d.credit
d.amount = fmt_money(amount, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr"))
amount = flt(d.get('debit', 0)) - flt(d.get('credit', 0))
formatted_amount = fmt_money(abs(amount), 2, d.account_currency)
d.amount = formatted_amount + " " + (_("Dr") if amount > 0 else _("Cr"))
d.pop("credit")
d.pop("debit")
d.pop("account_currency")
@@ -103,10 +107,10 @@ class BankReconciliation(Document):
d.clearance_date = None
frappe.db.set_value(d.payment_document, d.payment_entry, "clearance_date", d.clearance_date)
frappe.db.sql("""update `tab{0}` set clearance_date = %s, modified = %s
where name=%s""".format(d.payment_document),
frappe.db.sql("""update `tab{0}` set clearance_date = %s, modified = %s
where name=%s""".format(d.payment_document),
(d.clearance_date, nowdate(), d.payment_entry))
clearance_date_updated = True
if clearance_date_updated:

View File

@@ -0,0 +1,32 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Bank Transaction', {
onload(frm) {
frm.set_query('payment_document', 'payment_entries', function() {
return {
"filters": {
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
}
};
});
}
});
frappe.ui.form.on('Bank Transaction Payments', {
payment_entries_remove: function(frm, cdt, cdn) {
update_clearance_date(frm, cdt, cdn);
}
});
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})
.then(e => {
if (e == "success") {
frappe.show_alert({message:__("Document {0} successfully uncleared", [e]), indicator:'green'});
}
});
}
};

View File

@@ -0,0 +1,833 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "naming_series:",
"beta": 0,
"creation": "2018-10-22 18:19:02.784533",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "ACC-BTN-.YYYY.-",
"fetch_if_empty": 0,
"fieldname": "naming_series",
"fieldtype": "Select",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Series",
"length": 0,
"no_copy": 1,
"options": "ACC-BTN-.YYYY.-",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"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": 1,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Settled",
"fetch_if_empty": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Status",
"length": 0,
"no_copy": 0,
"options": "\nPending\nSettled\nUnreconciled\nReconciled",
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "bank_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Bank Account",
"length": 0,
"no_copy": 0,
"options": "Bank Account",
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fetch_from": "bank_account.company",
"fetch_if_empty": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "debit",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Debit",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "credit",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Credit",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_7",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "currency",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Currency",
"length": 0,
"no_copy": 0,
"options": "Currency",
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_10",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "description",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_14",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "reference_number",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Reference Number",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "transaction_id",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Transaction ID",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_entries",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Payment Entries",
"length": 0,
"no_copy": 0,
"options": "Bank Transaction Payments",
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_18",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Allocated Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amended From",
"length": 0,
"no_copy": 1,
"options": "Bank Transaction",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_17",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "unallocated_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Unallocated Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-04-26 14:32:16.437813",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "date",
"sort_order": "DESC",
"title_field": "bank_account",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}

View File

@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from erpnext.controllers.status_updater import StatusUpdater
from frappe.utils import flt
from six.moves import reduce
from frappe import _
class BankTransaction(StatusUpdater):
def after_insert(self):
self.unallocated_amount = abs(flt(self.credit) - flt(self.debit))
def on_submit(self):
self.clear_linked_payment_entries()
self.set_status()
def on_update_after_submit(self):
self.update_allocations()
self.clear_linked_payment_entries()
self.set_status(update=True)
def update_allocations(self):
if self.payment_entries:
allocated_amount = reduce(lambda x, y: flt(x) + flt(y), [x.allocated_amount for x in self.payment_entries])
else:
allocated_amount = 0
if allocated_amount:
frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount))
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)) - flt(allocated_amount))
else:
frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0)
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)))
self.reload()
def clear_linked_payment_entries(self):
for payment_entry in self.payment_entries:
allocated_amount = get_total_allocated_amount(payment_entry)
paid_amount = get_paid_amount(payment_entry)
if paid_amount and allocated_amount:
if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).".format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount))))
elif flt(allocated_amount[0]["allocated_amount"]) == flt(paid_amount):
if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
self.clear_simple_entry(payment_entry)
elif payment_entry.payment_document == "Sales Invoice":
self.clear_sales_invoice(payment_entry)
def clear_simple_entry(self, payment_entry):
frappe.db.set_value(payment_entry.payment_document, payment_entry.payment_entry, "clearance_date", self.date)
def clear_sales_invoice(self, payment_entry):
frappe.db.set_value("Sales Invoice Payment", dict(parenttype=payment_entry.payment_document,
parent=payment_entry.payment_entry), "clearance_date", self.date)
def get_total_allocated_amount(payment_entry):
return frappe.db.sql("""
SELECT
SUM(btp.allocated_amount) as allocated_amount,
bt.name
FROM
`tabBank Transaction Payments` as btp
LEFT JOIN
`tabBank Transaction` bt ON bt.name=btp.parent
WHERE
btp.payment_document = %s
AND
btp.payment_entry = %s
AND
bt.docstatus = 1""", (payment_entry.payment_document, payment_entry.payment_entry), as_dict=True)
def get_paid_amount(payment_entry):
if payment_entry.payment_document in ["Payment Entry", "Sales Invoice", "Purchase Invoice"]:
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "paid_amount")
elif payment_entry.payment_document == "Journal Entry":
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "total_credit")
elif payment_entry.payment_document == "Expense Claim":
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "total_amount_reimbursed")
else:
frappe.throw("Please reconcile {0}: {1} manually".format(payment_entry.payment_document, payment_entry.payment_entry))
@frappe.whitelist()
def unclear_reference_payment(doctype, docname):
if frappe.db.exists(doctype, docname):
doc = frappe.get_doc(doctype, docname)
if doctype == "Sales Invoice":
frappe.db.set_value("Sales Invoice Payment", dict(parenttype=doc.payment_document,
parent=doc.payment_entry), "clearance_date", None)
else:
frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
return doc.payment_entry

View File

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

View File

@@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
import json
from frappe.utils import getdate
from frappe.utils.dateutils import parse_date
from six import iteritems
@frappe.whitelist()
def upload_bank_statement():
if getattr(frappe, "uploaded_file", None):
with open(frappe.uploaded_file, "rb") as upfile:
fcontent = upfile.read()
else:
from frappe.utils.file_manager import get_uploaded_content
fname, fcontent = get_uploaded_content()
if frappe.safe_encode(fname).lower().endswith("csv".encode('utf-8')):
from frappe.utils.csvutils import read_csv_content
rows = read_csv_content(fcontent, False)
elif frappe.safe_encode(fname).lower().endswith("xlsx".encode('utf-8')):
from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file
rows = read_xlsx_file_from_attached_file(fcontent=fcontent)
columns = rows[0]
rows.pop(0)
data = rows
return {"columns": columns, "data": data}
@frappe.whitelist()
def create_bank_entries(columns, data, bank_account):
header_map = get_header_mapping(columns, bank_account)
success = 0
errors = 0
for d in json.loads(data):
if all(item is None for item in d) is True:
continue
fields = {}
for key, value in iteritems(header_map):
fields.update({key: d[int(value)-1]})
try:
bank_transaction = frappe.get_doc({
"doctype": "Bank Transaction"
})
bank_transaction.update(fields)
bank_transaction.date = getdate(parse_date(bank_transaction.date))
bank_transaction.bank_account = bank_account
bank_transaction.insert()
bank_transaction.submit()
success += 1
except Exception:
frappe.log_error(frappe.get_traceback())
errors += 1
return {"success": success, "errors": errors}
def get_header_mapping(columns, bank_account):
mapping = get_bank_mapping(bank_account)
header_map = {}
for column in json.loads(columns):
if column["content"] in mapping:
header_map.update({mapping[column["content"]]: column["colIndex"]})
return header_map
def get_bank_mapping(bank_account):
bank_name = frappe.db.get_value("Bank Account", bank_account, "bank")
bank = frappe.get_doc("Bank", bank_name)
mapping = {row.file_field:row.bank_transaction_field for row in bank.bank_transaction_mapping}
return mapping

View File

@@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Bank Transaction", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Bank Transaction
() => frappe.tests.make('Bank Transaction', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@@ -0,0 +1,286 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import reconcile, get_linked_payments
test_dependencies = ["Item", "Cost Center"]
class TestBankTransaction(unittest.TestCase):
def setUp(self):
add_transactions()
add_payments()
def tearDown(self):
for bt in frappe.get_all("Bank Transaction"):
doc = frappe.get_doc("Bank Transaction", bt.name)
doc.cancel()
doc.delete()
# Delete directly in DB to avoid validation errors for countries not allowing deletion
frappe.db.sql("""delete from `tabPayment Entry Reference`""")
frappe.db.sql("""delete from `tabPayment Entry`""")
frappe.flags.test_bank_transactions_created = False
frappe.flags.test_payments_created = False
# 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):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic"))
linked_payments = get_linked_payments(bank_transaction.name)
self.assertTrue(linked_payments[0].party == "Conrad Electronic")
# This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment
def test_reconcile(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
reconcile(bank_transaction.name, "Payment Entry", payment.name)
unallocated_amount = frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount")
self.assertTrue(unallocated_amount == 0)
clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date")
self.assertTrue(clearance_date is not None)
# Check if ERPNext can correctly fetch a linked payment based on the party
def test_linked_payments_based_on_party(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G"))
linked_payments = get_linked_payments(bank_transaction.name)
self.assertTrue(len(linked_payments)==1)
# Check if ERPNext can correctly filter a linked payments based on the debit/credit amount
def test_debit_credit_output(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
linked_payments = get_linked_payments(bank_transaction.name)
self.assertTrue(linked_payments[0].payment_type == "Pay")
# Check error if already reconciled
def test_already_reconciled(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
reconcile(bank_transaction.name, "Payment Entry", payment.name)
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
# Raise an error if creditor transaction vs creditor payment
def test_invalid_creditor_reconcilation(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
payment = frappe.get_doc("Payment Entry", dict(party="Conrad Electronic", paid_amount=690))
self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
# Raise an error if debitor transaction vs debitor payment
def test_invalid_debitor_reconcilation(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
payment = frappe.get_doc("Payment Entry", dict(party="Fayva", paid_amount=109080))
self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
# Raise an error if debitor transaction vs debitor payment
def test_clear_sales_invoice(self):
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
payment = frappe.get_doc("Sales Invoice", dict(customer="Fayva", status=["=", "Paid"]))
reconcile(bank_transaction.name, "Sales Invoice", payment.name)
self.assertEqual(frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount"), 0)
self.assertTrue(frappe.db.get_value("Sales Invoice Payment", dict(parent=payment.name), "clearance_date") is not None)
def add_transactions():
if frappe.flags.test_bank_transactions_created:
return
frappe.set_user("Administrator")
try:
frappe.get_doc({
"doctype": "Bank",
"bank_name":"Citi Bank",
}).insert()
except frappe.DuplicateEntryError:
pass
try:
frappe.get_doc({
"doctype": "Bank Account",
"account_name":"Checking Account",
"bank": "Citi Bank",
"account": "_Test Bank - _TC"
}).insert()
except frappe.DuplicateEntryError:
pass
doc = frappe.get_doc({
"doctype": "Bank Transaction",
"description":"1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G",
"date": "2018-10-23",
"debit": 1200,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
doc.submit()
doc = frappe.get_doc({
"doctype": "Bank Transaction",
"description":"1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G",
"date": "2018-10-23",
"debit": 1700,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
doc.submit()
doc = frappe.get_doc({
"doctype": "Bank Transaction",
"description":"Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic",
"date": "2018-10-26",
"debit": 690,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
doc.submit()
doc = frappe.get_doc({
"doctype": "Bank Transaction",
"description":"Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07",
"date": "2018-10-27",
"debit": 3900,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
doc.submit()
doc = frappe.get_doc({
"doctype": "Bank Transaction",
"description":"I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio",
"date": "2018-10-27",
"credit": 109080,
"currency": "INR",
"bank_account": "Checking Account - Citi Bank"
}).insert()
doc.submit()
frappe.flags.test_bank_transactions_created = True
def add_payments():
if frappe.flags.test_payments_created:
return
frappe.set_user("Administrator")
try:
frappe.get_doc({
"doctype": "Supplier",
"supplier_group":"All Supplier Groups",
"supplier_type": "Company",
"supplier_name": "Conrad Electronic"
}).insert()
except frappe.DuplicateEntryError:
pass
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.reference_no = "Conrad Oct 18"
pe.reference_date = "2018-10-24"
pe.insert()
pe.submit()
try:
frappe.get_doc({
"doctype": "Supplier",
"supplier_group":"All Supplier Groups",
"supplier_type": "Company",
"supplier_name": "Mr G"
}).insert()
except frappe.DuplicateEntryError:
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.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.reference_no = "Herr G Nov 18"
pe.reference_date = "2018-11-01"
pe.insert()
pe.submit()
try:
frappe.get_doc({
"doctype": "Supplier",
"supplier_group":"All Supplier Groups",
"supplier_type": "Company",
"supplier_name": "Poore Simon's"
}).insert()
except frappe.DuplicateEntryError:
pass
try:
frappe.get_doc({
"doctype": "Customer",
"customer_group":"All Customer Groups",
"customer_type": "Company",
"customer_name": "Poore Simon's"
}).insert()
except frappe.DuplicateEntryError:
pass
pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "Poore Simon's Oct 18"
pe.reference_date = "2018-10-28"
pe.insert()
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.reference_no = "Poore Simon's Oct 18"
pe.reference_date = "2018-10-28"
pe.insert()
pe.submit()
try:
frappe.get_doc({
"doctype": "Customer",
"customer_group":"All Customer Groups",
"customer_type": "Company",
"customer_name": "Fayva"
}).insert()
except frappe.DuplicateEntryError:
pass
si = create_sales_invoice(customer="Fayva", qty=1, rate=109080)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
pe.reference_no = "Fayva Oct 18"
pe.reference_date = "2018-10-29"
pe.insert()
pe.submit()
company = frappe.db.get_single_value('Global Defaults', 'default_company')
frappe.get_doc({
"doctype": "Mode of Payment",
"name": "Cash"
}).append("accounts", {
"company": company,
"default_account": "_Test Bank - _TC"
}).save()
si = create_sales_invoice(customer="Fayva", qty=1, rate=109080, do_not_submit=1)
si.is_pos = 1
si.append("payments", {
"mode_of_payment": "Cash",
"account": "_Test Bank - _TC",
"amount": 109080
})
si.save()
si.submit()
frappe.flags.test_payments_created = True

View File

@@ -0,0 +1,107 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-10-24 15:24:56.713277",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bank_transaction_field",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Field in Bank Transaction",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "file_field",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Column in Bank File",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-10-24 15:24:56.713277",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction Mapping",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class BankTransactionMapping(Document):
pass

View File

@@ -0,0 +1,141 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-11-28 08:55:40.815355",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "payment_document",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Payment Document",
"length": 0,
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "payment_entry",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Payment Entry",
"length": 0,
"no_copy": 0,
"options": "payment_document",
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Allocated Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-12-06 10:57:02.635141",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction Payments",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class BankTransactionPayments(Document):
pass

View File

@@ -6,6 +6,7 @@ import frappe, erpnext
from frappe import _
from frappe.utils import flt, fmt_money, getdate, formatdate
from frappe.model.document import Document
from frappe.model.meta import get_field_precision
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.utils import get_fiscal_year
@@ -56,7 +57,7 @@ class GLEntry(Document):
.format(self.voucher_type, self.voucher_no, self.account))
# Zero value transaction is not allowed
if not (flt(self.debit) or flt(self.credit)):
if not (flt(self.debit, self.precision("debit")) or flt(self.credit, self.precision("credit"))):
frappe.throw(_("{0} {1}: Either debit or credit amount is required for {2}")
.format(self.voucher_type, self.voucher_no, self.account))
@@ -216,17 +217,23 @@ def validate_frozen_account(account, adv_adj=None):
def update_against_account(voucher_type, voucher_no):
entries = frappe.db.get_all("GL Entry",
filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
fields=["name", "party", "against", "debit", "credit", "account"])
fields=["name", "party", "against", "debit", "credit", "account", "company"])
if not entries:
return
company_currency = erpnext.get_company_currency(entries[0].company)
precision = get_field_precision(frappe.get_meta("GL Entry")
.get_field("debit"), company_currency)
accounts_debited, accounts_credited = [], []
for d in entries:
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
if flt(d.debit, precision) > 0: accounts_debited.append(d.party or d.account)
if flt(d.credit, precision) > 0: accounts_credited.append(d.party or d.account)
for d in entries:
if flt(d.debit > 0):
if flt(d.debit, precision) > 0:
new_against = ", ".join(list(set(accounts_credited)))
if flt(d.credit > 0):
if flt(d.credit, precision) > 0:
new_against = ", ".join(list(set(accounts_debited)))
if d.against != new_against:

View File

@@ -52,11 +52,6 @@ class JournalEntry(AccountsController):
self.update_loan()
self.update_inter_company_jv()
def before_print(self):
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Journal Entry",
"voucher_no": self.name} ,
fields=["account", "party_type", "party", "debit", "credit", "remarks"]
)
def get_title(self):
return self.pay_to_recd_from or self.accounts[0].account

View File

@@ -232,6 +232,13 @@ frappe.ui.form.on('Payment Entry', {
},
party_type: function(frm) {
let party_types = Object.keys(frappe.boot.party_account_types);
if(frm.doc.party_type && !party_types.includes(frm.doc.party_type)){
frm.set_value("party_type", "");
frappe.throw(__("Party can only be one of "+ party_types.join(", ")));
}
if(frm.doc.party) {
$.each(["party", "party_balance", "paid_from", "paid_to",
"paid_from_account_currency", "paid_from_account_balance",

File diff suppressed because it is too large Load Diff

View File

@@ -70,11 +70,6 @@ class PaymentEntry(AccountsController):
self.update_advance_paid()
self.update_expense_claim()
def before_print(self):
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Payment Entry",
"voucher_no": self.name} ,
fields=["account", "party_type", "party", "debit", "credit", "remarks"]
)
def on_cancel(self):
self.setup_party_account_field()
@@ -165,7 +160,7 @@ class PaymentEntry(AccountsController):
d.reference_name, self.party_account_currency)
for field, value in iteritems(ref_details):
if not d.get(field) or force:
if field == 'exchange_rate' or not d.get(field) or force:
d.set(field, value)
def validate_payment_type(self):
@@ -541,9 +536,13 @@ class PaymentEntry(AccountsController):
@frappe.whitelist()
def get_outstanding_reference_documents(args):
if isinstance(args, string_types):
args = json.loads(args)
if args.get('party_type') == 'Member':
return
# confirm that Supplier is not blocked
if args.get('party_type') == 'Supplier':
supplier_status = get_supplier_block_status(args['party'])
@@ -754,7 +753,7 @@ def get_outstanding_on_journal_entry(name):
@frappe.whitelist()
def get_reference_details(reference_doctype, reference_name, party_account_currency):
total_amount = outstanding_amount = exchange_rate = None
total_amount = outstanding_amount = exchange_rate = bill_no = None
ref_doc = frappe.get_doc(reference_doctype, reference_name)
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)
@@ -788,6 +787,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
outstanding_amount = ref_doc.get("outstanding_amount")
bill_no = ref_doc.get("bill_no")
elif reference_doctype == "Expense Claim":
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \
- flt(ref_doc.get("total_amount+reimbursed")) - flt(ref_doc.get("total_advance_amount"))
@@ -804,7 +804,8 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
"due_date": ref_doc.get("due_date"),
"total_amount": total_amount,
"outstanding_amount": outstanding_amount,
"exchange_rate": exchange_rate
"exchange_rate": exchange_rate,
"bill_no": bill_no
})

View File

@@ -13,20 +13,20 @@ class PaymentReconciliation(Document):
def get_unreconciled_entries(self):
self.get_nonreconciled_payment_entries()
self.get_invoice_entries()
def get_nonreconciled_payment_entries(self):
self.check_mandatory_to_fetch()
payment_entries = self.get_payment_entries()
journal_entries = self.get_jv_entries()
self.add_payment_entries(payment_entries + journal_entries)
def get_payment_entries(self):
order_doctype = "Sales Order" if self.party_type=="Customer" else "Purchase Order"
payment_entries = get_advance_payment_entries(self.party_type, self.party,
payment_entries = get_advance_payment_entries(self.party_type, self.party,
self.receivable_payable_account, order_doctype, against_all_orders=True, limit=self.limit)
return payment_entries
def get_jv_entries(self):
@@ -36,12 +36,12 @@ class PaymentReconciliation(Document):
bank_account_condition = "t2.against_account like %(bank_cash_account)s" \
if self.bank_cash_account else "1=1"
limit_cond = "limit %s" % (self.limit or 1000)
limit_cond = "limit %s" % self.limit if self.limit else ""
journal_entries = frappe.db.sql("""
select
"Journal Entry" as reference_type, t1.name as reference_name,
t1.posting_date, t1.remark as remarks, t2.name as reference_row,
"Journal Entry" as reference_type, t1.name as reference_name,
t1.posting_date, t1.remark as remarks, t2.name as reference_row,
{dr_or_cr} as amount, t2.is_advance
from
`tabJournal Entry` t1, `tabJournal Entry Account` t2
@@ -49,8 +49,8 @@ class PaymentReconciliation(Document):
t1.name = t2.parent and t1.docstatus = 1 and t2.docstatus = 1
and t2.party_type = %(party_type)s and t2.party = %(party)s
and t2.account = %(account)s and {dr_or_cr} > 0
and (t2.reference_type is null or t2.reference_type = '' or
(t2.reference_type in ('Sales Order', 'Purchase Order')
and (t2.reference_type is null or t2.reference_type = '' or
(t2.reference_type in ('Sales Order', 'Purchase Order')
and t2.reference_name is not null and t2.reference_name != ''))
and (CASE
WHEN t1.voucher_type in ('Debit Note', 'Credit Note')
@@ -83,7 +83,10 @@ class PaymentReconciliation(Document):
condition = self.check_condition()
non_reconciled_invoices = get_outstanding_invoices(self.party_type, self.party,
self.receivable_payable_account, condition=condition, limit=self.limit)
self.receivable_payable_account, condition=condition)
if self.limit:
non_reconciled_invoices = non_reconciled_invoices[:self.limit]
self.add_invoice_entries(non_reconciled_invoices)
@@ -109,7 +112,7 @@ class PaymentReconciliation(Document):
self.validate_invoice()
dr_or_cr = ("credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit_in_account_currency")
lst = []
for e in self.get('payments'):
if e.invoice_number and e.allocated_amount:
@@ -127,11 +130,11 @@ class PaymentReconciliation(Document):
'unadjusted_amount' : flt(e.amount),
'allocated_amount' : flt(e.allocated_amount)
}))
if lst:
from erpnext.accounts.utils import reconcile_against_document
reconcile_against_document(lst)
msgprint(_("Successfully Reconciled"))
self.get_unreconciled_entries()

View File

@@ -285,6 +285,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
is_paid: function() {
hide_fields(this.frm.doc);
if(cint(this.frm.doc.is_paid)) {
this.frm.set_value("allocate_advances_automatically", 0);
if(!this.frm.doc.company) {
this.frm.set_value("is_paid", 0)
frappe.msgprint(__("Please specify Company to proceed"));
@@ -468,7 +469,7 @@ cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(
cur_frm.cscript.cost_center = function(doc, cdt, cdn){
var d = locals[cdt][cdn];
if(d.idx == 1 && d.cost_center){
if(d.cost_center){
var cl = doc.items || [];
for(var i = 0; i < cl.length; i++){
if(!cl[i].cost_center) cl[i].cost_center = d.cost_center;
@@ -522,8 +523,13 @@ frappe.ui.form.on("Purchase Invoice", {
},
onload: function(frm) {
if(frm.doc.__onload && !frm.doc.__onload.supplier_tds) {
me.frm.set_df_property("apply_tds", "read_only", 1);
if(frm.doc.__onload) {
if(frm.doc.supplier) {
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
}
if(!frm.doc.__onload.supplier_tds) {
frm.set_df_property("apply_tds", "read_only", 1);
}
}
erpnext.queries.setup_queries(frm, "Warehouse", function() {

File diff suppressed because it is too large Load Diff

View File

@@ -55,11 +55,6 @@ class PurchaseInvoice(BuyingController):
if not self.on_hold:
self.release_date = ''
def before_print(self):
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Purchase Invoice",
"voucher_no": self.name} ,
fields=["account", "party_type", "party", "debit", "credit"]
)
def invoice_is_blocked(self):
return self.on_hold and (not self.release_date or self.release_date > getdate(nowdate()))
@@ -794,9 +789,8 @@ class PurchaseInvoice(BuyingController):
for d in self.items:
if d.project and d.project not in project_list:
project = frappe.get_doc("Project", d.project)
project.flags.dont_sync_tasks = True
project.update_purchase_costing()
project.save()
project.db_update()
project_list.append(d.project)
def validate_supplier_invoice(self):

View File

@@ -344,6 +344,7 @@ class TestPurchaseInvoice(unittest.TestCase):
pi = frappe.copy_doc(test_records[0])
pi.disable_rounded_total = 1
pi.allocate_advances_automatically = 0
pi.append("advances", {
"reference_type": "Journal Entry",
"reference_name": jv.name,
@@ -383,6 +384,7 @@ class TestPurchaseInvoice(unittest.TestCase):
pi = frappe.copy_doc(test_records[0])
pi.disable_rounded_total = 1
pi.allocate_advances_automatically = 0
pi.append("advances", {
"reference_type": "Journal Entry",
"reference_name": jv.name,
@@ -551,7 +553,7 @@ class TestPurchaseInvoice(unittest.TestCase):
sum(credit) as credit, debit_in_account_currency, credit_in_account_currency
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
group by account, voucher_no order by account asc;""", pi.name, as_dict=1)
stock_in_hand_account = get_inventory_account(pi.company, pi.get("items")[0].warehouse)
self.assertTrue(gl_entries)
@@ -634,7 +636,7 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(frappe.db.get_value("Serial No", pi.get("items")[0].rejected_serial_no,
"warehouse"), pi.get("items")[0].rejected_warehouse)
def test_outstanding_amount_after_advance_jv_cancelation(self):
from erpnext.accounts.doctype.journal_entry.test_journal_entry \
import test_records as jv_test_records
@@ -656,14 +658,14 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.insert()
pi.submit()
pi.load_from_db()
#check outstanding after advance allocation
self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total - pi.total_advance))
#added to avoid Document has been modified exception
jv = frappe.get_doc("Journal Entry", jv.name)
jv.cancel()
pi.load_from_db()
#check outstanding after advance cancellation
self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total + pi.total_advance))
@@ -722,7 +724,7 @@ class TestPurchaseInvoice(unittest.TestCase):
shipping_rule = create_shipping_rule(shipping_rule_type = "Buying", shipping_rule_name = "Shipping Rule - Purchase Invoice Test")
pi = frappe.copy_doc(test_records[0])
pi.shipping_rule = shipping_rule.name
pi.insert()
@@ -740,14 +742,14 @@ class TestPurchaseInvoice(unittest.TestCase):
"tax_amount": shipping_amount,
"description": shipping_rule.name,
"add_deduct_tax": "Add"
}
}
pi.append("taxes", shipping_charge)
pi.save()
self.assertEqual(pi.net_total, 1250)
self.assertEqual(pi.total_taxes_and_charges, 462.3)
self.assertEqual(pi.grand_total, 1712.3)
self.assertEqual(pi.grand_total, 1712.3)
def test_make_pi_without_terms(self):
pi = make_purchase_invoice(do_not_save=1)

View File

@@ -0,0 +1,38 @@
frappe.ui.form.on("Sales Invoice", {
setup: function(frm) {
frm.set_query('transporter', function() {
return {
filters: {
'is_transporter': 1
}
};
});
frm.set_query('driver', function(doc) {
return {
filters: {
'transporter': doc.transporter
}
};
});
},
refresh: function(frm) {
if(frm.doc.docstatus == 1 && !frm.is_dirty()
&& !frm.doc.is_return && !frm.doc.ewaybill) {
frm.add_custom_button('Generate e-Way Bill JSON', () => {
var w = window.open(
frappe.urllib.get_full_url(
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
+ "dt=" + encodeURIComponent(frm.doc.doctype)
+ "&dn=" + encodeURIComponent(frm.doc.name)
)
);
if (!w) {
frappe.msgprint(__("Please enable pop-ups")); return;
}
}, __("Make"));
}
}
});

View File

@@ -0,0 +1,33 @@
var globalOnload = frappe.listview_settings['Sales Invoice'].onload;
frappe.listview_settings['Sales Invoice'].onload = function (doclist) {
// Provision in case onload event is added to sales_invoice.js in future
if (globalOnload) {
globalOnload(doclist);
}
const action = () => {
const selected_docs = doclist.get_checked_items();
const docnames = doclist.get_checked_items(true);
for (let doc of selected_docs) {
if (doc.docstatus !== 1) {
frappe.throw(__("e-Way Bill JSON can only be generated from a submitted document"));
}
}
var w = window.open(
frappe.urllib.get_full_url(
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
+ "dt=" + encodeURIComponent(doclist.doctype)
+ "&dn=" + encodeURIComponent(docnames)
)
);
if (!w) {
frappe.msgprint(__("Please enable pop-ups")); return;
}
};
doclist.page.add_actions_menu_item(__('Generate e-Way Bill JSON'), action, false);
};

View File

@@ -356,6 +356,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
set_pos_data: function() {
if(this.frm.doc.is_pos) {
this.frm.set_value("allocate_advances_automatically", 0);
if(!this.frm.doc.company) {
this.frm.set_value("is_pos", 0);
frappe.msgprint(__("Please specify Company to proceed"));

File diff suppressed because it is too large Load Diff

View File

@@ -205,11 +205,6 @@ class SalesInvoice(SellingController):
def before_cancel(self):
self.update_time_sheet(None)
def before_print(self):
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Sales Invoice",
"voucher_no": self.name} ,
fields=["account", "party_type", "party", "debit", "credit"]
)
def on_cancel(self):
self.check_close_sales_order("sales_order")
@@ -1027,9 +1022,8 @@ class SalesInvoice(SellingController):
def update_project(self):
if self.project:
project = frappe.get_doc("Project", self.project)
project.flags.dont_sync_tasks = True
project.update_billed_amount()
project.save()
project.db_update()
def verify_payment_amount_is_positive(self):

View File

@@ -14,9 +14,12 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
from frappe.model.naming import make_autoname
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
from erpnext.stock.doctype.item.test_item import create_item
from six import iteritems
from erpnext.regional.india.utils import get_ewb_data
class TestSalesInvoice(unittest.TestCase):
def make(self):
w = frappe.copy_doc(test_records[0])
@@ -762,7 +765,7 @@ class TestSalesInvoice(unittest.TestCase):
set_perpetual_inventory(0)
frappe.db.sql("delete from `tabPOS Profile`")
def test_pos_si_without_payment(self):
set_perpetual_inventory()
make_pos_profile()
@@ -854,6 +857,7 @@ class TestSalesInvoice(unittest.TestCase):
jv.submit()
si = frappe.copy_doc(test_records[0])
si.allocate_advances_automatically = 0
si.append("advances", {
"doctype": "Sales Invoice Advance",
"reference_type": "Journal Entry",
@@ -1360,7 +1364,7 @@ class TestSalesInvoice(unittest.TestCase):
"included_in_print_rate": 1
})
si.save()
si.submit()
self.assertEqual(si.net_total, 19453.13)
self.assertEqual(si.grand_total, 24900)
self.assertEqual(si.total_taxes_and_charges, 5446.88)
@@ -1382,6 +1386,50 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_rounding_adjustment_2(self):
si = create_sales_invoice(rate=400, do_not_save=True)
for rate in [400, 600, 100]:
si.append("items", {
"item_code": "_Test Item",
"gst_hsn_code": "999800",
"warehouse": "_Test Warehouse - _TC",
"qty": 1,
"rate": rate,
"income_account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC"
})
for tax_account in ["_Test Account VAT - _TC", "_Test Account Service Tax - _TC"]:
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": tax_account,
"description": tax_account,
"rate": 9,
"cost_center": "_Test Cost Center - _TC",
"included_in_print_rate": 1
})
si.save()
si.submit()
self.assertEqual(si.net_total, 1271.19)
self.assertEqual(si.grand_total, 1500)
self.assertEqual(si.total_taxes_and_charges, 228.82)
self.assertEqual(si.rounding_adjustment, -0.01)
expected_values = dict((d[0], d) for d in [
[si.debit_to, 1500, 0.0],
["_Test Account Service Tax - _TC", 0.0, 114.41],
["_Test Account VAT - _TC", 0.0, 114.41],
["Sales - _TC", 0.0, 1271.18]
])
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.name, as_dict=1)
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.account)
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_sales_invoice_with_shipping_rule(self):
from erpnext.accounts.doctype.shipping_rule.test_shipping_rule \
import create_shipping_rule
@@ -1514,6 +1562,160 @@ class TestSalesInvoice(unittest.TestCase):
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
def test_deferred_revenue(self):
deferred_account = create_account(account_name="Deferred Revenue",
parent_account="Current Liabilities - _TC", company="_Test Company")
item = create_item("_Test Item for Deferred Accounting")
item.enable_deferred_revenue = 1
item.deferred_revenue_account = deferred_account
item.no_of_months = 12
item.save()
si = create_sales_invoice(item=item.name, posting_date="2019-01-10", do_not_submit=True)
si.items[0].enable_deferred_revenue = 1
si.items[0].service_start_date = "2019-01-10"
si.items[0].service_end_date = "2019-03-15"
si.items[0].deferred_revenue_account = deferred_account
si.save()
si.submit()
from erpnext.accounts.deferred_revenue import convert_deferred_revenue_to_income
convert_deferred_revenue_to_income(start_date="2019-01-01", end_date="2019-01-31")
expected_gle = [
[deferred_account, 33.85, 0.0, "2019-01-31"],
["Sales - _TC", 0.0, 33.85, "2019-01-31"]
]
self.check_gl_entries(si.name, expected_gle, "2019-01-10")
convert_deferred_revenue_to_income(start_date="2019-01-01", end_date="2019-03-31")
expected_gle = [
[deferred_account, 43.08, 0.0, "2019-02-28"],
["Sales - _TC", 0.0, 43.08, "2019-02-28"],
[deferred_account, 23.07, 0.0, "2019-03-15"],
["Sales - _TC", 0.0, 23.07, "2019-03-15"]
]
self.check_gl_entries(si.name, expected_gle, "2019-01-31")
def check_gl_entries(self, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s and posting_date > %s
order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_gle[i][0], gle.account)
self.assertEqual(expected_gle[i][1], gle.debit)
self.assertEqual(expected_gle[i][2], gle.credit)
self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
def test_eway_bill_json(self):
if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_title": "_Test Address for Eway bill",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000",
"gstin": "27AAECE4835E1ZR",
"gst_state": "Maharashtra",
"gst_state_number": "27",
"pincode": "401108"
}).insert()
address.append("links", {
"link_doctype": "Company",
"link_name": "_Test Company"
})
address.save()
if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Shipping'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_title": "_Test Customer-Address for Eway bill",
"address_type": "Shipping",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000",
"gst_state": "Maharashtra",
"gst_state_number": "27",
"pincode": "410038"
}).insert()
address.append("links", {
"link_doctype": "Customer",
"link_name": "_Test Customer"
})
address.save()
gst_settings = frappe.get_doc("GST Settings")
gst_account = frappe.get_all(
"GST Account",
fields=["cgst_account", "sgst_account", "igst_account"],
filters = {"company": "_Test Company"})
if not gst_account:
gst_settings.append("gst_accounts", {
"company": "_Test Company",
"cgst_account": "CGST - _TC",
"sgst_account": "SGST - _TC",
"igst_account": "IGST - _TC",
})
gst_settings.save()
si = create_sales_invoice(do_not_save =1, rate = '60000')
si.distance = 2000
si.company_address = "_Test Address for Eway bill-Billing"
si.customer_address = "_Test Customer-Address for Eway bill-Shipping"
si.vehicle_no = "KA12KA1234"
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "CGST - _TC",
"cost_center": "Main - _TC",
"description": "CGST @ 9.0",
"rate": 9
})
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "SGST - _TC",
"cost_center": "Main - _TC",
"description": "SGST @ 9.0",
"rate": 9
})
si.submit()
data = get_ewb_data("Sales Invoice", si.name)
self.assertEqual(data['version'], '1.0.1118')
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company')
self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer')
self.assertEqual(data['billLists'][0]['vehicleType'], 'R')
self.assertEqual(data['billLists'][0]['totalValue'], 60000)
self.assertEqual(data['billLists'][0]['cgstValue'], 5400)
self.assertEqual(data['billLists'][0]['sgstValue'], 5400)
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
@@ -1611,4 +1813,4 @@ def get_outstanding_amount(against_voucher_type, against_voucher, account, party
if against_voucher_type == 'Purchase Invoice':
bal = bal * -1
return bal
return bal

View File

@@ -295,7 +295,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2019-03-06 15:58:37.839241",
"modified": "2019-03-19 14:54:56.524556",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Payment",

View File

@@ -135,9 +135,9 @@ def round_off_debit_credit(gl_map):
.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff))
elif abs(debit_credit_diff) >= (1.0 / (10**precision)):
make_round_off_gle(gl_map, debit_credit_diff)
make_round_off_gle(gl_map, debit_credit_diff, precision)
def make_round_off_gle(gl_map, debit_credit_diff):
def make_round_off_gle(gl_map, debit_credit_diff, precision):
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(gl_map[0].company)
round_off_account_exists = False
round_off_gle = frappe._dict()
@@ -150,6 +150,10 @@ def make_round_off_gle(gl_map, debit_credit_diff):
debit_credit_diff += flt(d.credit_in_account_currency)
round_off_account_exists = True
if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)):
gl_map.remove(round_off_gle)
return
if not round_off_gle:
for k in ["voucher_type", "voucher_no", "company",
"posting_date", "remarks", "is_opening"]:

View File

@@ -0,0 +1,578 @@
frappe.provide("erpnext.accounts");
frappe.pages['bank-reconciliation'].on_page_load = function(wrapper) {
new erpnext.accounts.bankReconciliation(wrapper);
}
erpnext.accounts.bankReconciliation = class BankReconciliation {
constructor(wrapper) {
this.page = frappe.ui.make_app_page({
parent: wrapper,
title: __("Bank Reconciliation"),
single_column: true
});
this.parent = wrapper;
this.page = this.parent.page;
this.check_plaid_status();
this.make();
}
make() {
const me = this;
me.$main_section = $(`<div class="reconciliation page-main-content"></div>`).appendTo(me.page.main);
const empty_state = __("Upload a bank statement, link or reconcile a bank account")
me.$main_section.append(`<div class="flex justify-center align-center text-muted"
style="height: 50vh; display: flex;"><h5 class="text-muted">${empty_state}</h5></div>`)
me.page.add_field({
fieldtype: 'Link',
label: __('Company'),
fieldname: 'company',
options: "Company",
onchange: function() {
if (this.value) {
me.company = this.value;
} else {
me.company = null;
me.bank_account = null;
}
}
})
me.page.add_field({
fieldtype: 'Link',
label: __('Bank Account'),
fieldname: 'bank_account',
options: "Bank Account",
get_query: function() {
if(!me.company) {
frappe.throw(__("Please select company first"));
return
}
return {
filters: {
"company": me.company
}
}
},
onchange: function() {
if (this.value) {
me.bank_account = this.value;
me.add_actions();
} else {
me.bank_account = null;
me.page.hide_actions_menu();
}
}
})
}
check_plaid_status() {
const me = this;
frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => {
if (r && r.enabled == "1") {
me.plaid_status = "active"
} else {
me.plaid_status = "inactive"
}
})
}
add_actions() {
const me = this;
me.page.show_menu()
me.page.add_menu_item(__("Upload a statement"), function() {
me.clear_page_content();
new erpnext.accounts.bankTransactionUpload(me);
}, true)
if (me.plaid_status==="active") {
me.page.add_menu_item(__("Synchronize this account"), function() {
me.clear_page_content();
new erpnext.accounts.bankTransactionSync(me);
}, true)
}
me.page.add_menu_item(__("Reconcile this account"), function() {
me.clear_page_content();
me.make_reconciliation_tool();
}, true)
}
clear_page_content() {
const me = this;
$(me.page.body).find('.frappe-list').remove();
me.$main_section.empty();
}
make_reconciliation_tool() {
const me = this;
frappe.model.with_doctype("Bank Transaction", () => {
erpnext.accounts.ReconciliationList = new erpnext.accounts.ReconciliationTool({
parent: me.parent,
doctype: "Bank Transaction"
});
})
}
}
erpnext.accounts.bankTransactionUpload = class bankTransactionUpload {
constructor(parent) {
this.parent = parent;
this.data = [];
const assets = [
"/assets/frappe/css/frappe-datatable.css",
"/assets/frappe/js/lib/clusterize.min.js",
"/assets/frappe/js/lib/Sortable.min.js",
"/assets/frappe/js/lib/frappe-datatable.js"
];
frappe.require(assets, () => {
this.make();
});
}
make() {
const me = this;
frappe.upload.make({
args: {
method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
allow_multiple: 0
},
no_socketio: true,
sample_url: "e.g. http://example.com/somefile.csv",
callback: function(attachment, r) {
if (!r.exc && r.message) {
me.data = r.message;
me.setup_transactions_dom();
me.create_datatable();
me.add_primary_action();
}
}
})
}
setup_transactions_dom() {
const me = this;
me.parent.$main_section.append(`<div class="transactions-table"></div>`)
}
create_datatable() {
try {
this.datatable = new DataTable('.transactions-table', {
columns: this.data.columns,
data: this.data.data
})
}
catch(err) {
let msg = __(`Your file could not be processed by ERPNext.
<br>It should be a standard CSV or XLSX file.
<br>The headers should be in the first row.`)
frappe.throw(msg)
}
}
add_primary_action() {
const me = this;
me.parent.page.set_primary_action(__("Submit"), function() {
me.add_bank_entries()
}, null, __("Creating bank entries..."))
}
add_bank_entries() {
const me = this;
frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.create_bank_entries',
{columns: this.datatable.datamanager.columns, data: this.datatable.datamanager.data, bank_account: me.parent.bank_account}
).then((result) => {
let result_title = result.errors == 0 ? __("{0} bank transaction(s) created", [result.success]) : __("{0} bank transaction(s) created and {1} errors", [result.success, result.errors])
let result_msg = `
<div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;">
<h5 class="text-muted">${result_title}</h5>
</div>`
me.parent.page.clear_primary_action();
me.parent.$main_section.empty();
me.parent.$main_section.append(result_msg);
if (result.errors == 0) {
frappe.show_alert({message:__("All bank transactions have been created"), indicator:'green'});
} else {
frappe.show_alert({message:__("Please check the error log for details about the import errors"), indicator:'red'});
}
})
}
}
erpnext.accounts.bankTransactionSync = class bankTransactionSync {
constructor(parent) {
this.parent = parent;
this.data = [];
this.init_config()
}
init_config() {
const me = this;
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.plaid_configuration')
.then(result => {
me.plaid_env = result.plaid_env;
me.plaid_public_key = result.plaid_public_key;
me.client_name = result.client_name;
me.sync_transactions()
})
}
sync_transactions() {
const me = this;
frappe.db.get_value("Bank Account", me.parent.bank_account, "bank", (v) => {
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions', {
bank: v['bank'],
bank_account: me.parent.bank_account,
freeze: true
})
.then((result) => {
let result_title = (result.length > 0) ? __("{0} bank transaction(s) created", [result.length]) : __("This bank account is already synchronized")
let result_msg = `
<div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;">
<h5 class="text-muted">${result_title}</h5>
</div>`
this.parent.$main_section.append(result_msg)
frappe.show_alert({message:__("Bank account '{0}' has been synchronized", [me.parent.bank_account]), indicator:'green'});
})
})
}
}
erpnext.accounts.ReconciliationTool = class ReconciliationTool extends frappe.views.BaseList {
constructor(opts) {
super(opts);
this.show();
}
setup_defaults() {
super.setup_defaults();
this.page_title = __("Bank Reconciliation");
this.doctype = 'Bank Transaction';
this.fields = ['date', 'description', 'debit', 'credit', 'currency']
}
setup_view() {
this.render_header();
}
setup_side_bar() {
//
}
make_standard_filters() {
//
}
freeze() {
this.$result.find('.list-count').html(`<span>${__('Refreshing')}...</span>`);
}
get_args() {
const args = super.get_args();
return Object.assign({}, args, {
...args.filters.push(["Bank Transaction", "docstatus", "=", 1],
["Bank Transaction", "unallocated_amount", ">", 0])
});
}
update_data(r) {
let data = r.message || [];
if (this.start === 0) {
this.data = data;
} else {
this.data = this.data.concat(data);
}
}
render() {
const me = this;
this.$result.find('.list-row-container').remove();
$('[data-fieldname="name"]').remove();
me.data.map((value) => {
const row = $('<div class="list-row-container">').data("data", value).appendTo(me.$result).get(0);
new erpnext.accounts.ReconciliationRow(row, value);
})
}
render_header() {
const me = this;
if ($(this.wrapper).find('.transaction-header').length === 0) {
me.$result.append(frappe.render_template("bank_transaction_header"));
}
}
}
erpnext.accounts.ReconciliationRow = class ReconciliationRow {
constructor(row, data) {
this.data = data;
this.row = row;
this.make();
this.bind_events();
}
make() {
$(this.row).append(frappe.render_template("bank_transaction_row", this.data))
}
bind_events() {
const me = this;
$(me.row).on('click', '.clickable-section', function() {
me.bank_entry = $(this).attr("data-name");
me.show_dialog($(this).attr("data-name"));
})
$(me.row).on('click', '.new-reconciliation', function() {
me.bank_entry = $(this).attr("data-name");
me.show_dialog($(this).attr("data-name"));
})
$(me.row).on('click', '.new-payment', function() {
me.bank_entry = $(this).attr("data-name");
me.new_payment();
})
$(me.row).on('click', '.new-invoice', function() {
me.bank_entry = $(this).attr("data-name");
me.new_invoice();
})
$(me.row).on('click', '.new-expense', function() {
me.bank_entry = $(this).attr("data-name");
me.new_expense();
})
}
new_payment() {
const me = this;
const paid_amount = me.data.credit > 0 ? me.data.credit : me.data.debit;
const payment_type = me.data.credit > 0 ? "Receive": "Pay";
const party_type = me.data.credit > 0 ? "Customer": "Supplier";
frappe.new_doc("Payment Entry", {"payment_type": payment_type, "paid_amount": paid_amount,
"party_type": party_type, "paid_from": me.data.bank_account})
}
new_invoice() {
const me = this;
const invoice_type = me.data.credit > 0 ? "Sales Invoice" : "Purchase Invoice";
frappe.new_doc(invoice_type)
}
new_expense() {
frappe.new_doc("Expense Claim")
}
show_dialog(data) {
const me = this;
frappe.db.get_value("Bank Account", me.data.bank_account, "account", (r) => {
me.gl_account = r.account;
})
frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments',
{bank_transaction: data, freeze:true, freeze_message:__("Finding linked payments")}
).then((result) => {
me.make_dialog(result)
})
}
make_dialog(data) {
const me = this;
me.selected_payment = null;
const fields = [
{
fieldtype: 'Section Break',
fieldname: 'section_break_1',
label: __('Automatic Reconciliation')
},
{
fieldtype: 'HTML',
fieldname: 'payment_proposals'
},
{
fieldtype: 'Section Break',
fieldname: 'section_break_2',
label: __('Search for a payment')
},
{
fieldtype: 'Link',
fieldname: 'payment_doctype',
options: 'DocType',
label: 'Payment DocType',
get_query: () => {
return {
filters : {
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
}
}
},
},
{
fieldtype: 'Column Break',
fieldname: 'column_break_1',
},
{
fieldtype: 'Dynamic Link',
fieldname: 'payment_entry',
options: 'payment_doctype',
label: 'Payment Document',
get_query: () => {
let dt = this.dialog.fields_dict.payment_doctype.value;
if (dt === "Payment Entry") {
return {
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.payment_entry_query",
filters : {
"bank_account": this.data.bank_account,
"company": this.data.company
}
}
} else if (dt === "Journal Entry") {
return {
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.journal_entry_query",
filters : {
"bank_account": this.data.bank_account,
"company": this.data.company
}
}
} else if (dt === "Sales Invoice") {
return {
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.sales_invoices_query"
}
} else if (dt === "Purchase Invoice") {
return {
filters : [
["Purchase Invoice", "ifnull(clearance_date, '')", "=", ""],
["Purchase Invoice", "docstatus", "=", 1],
["Purchase Invoice", "company", "=", this.data.company]
]
}
} else if (dt === "Expense Claim") {
return {
filters : [
["Expense Claim", "ifnull(clearance_date, '')", "=", ""],
["Expense Claim", "docstatus", "=", 1],
["Expense Claim", "company", "=", this.data.company]
]
}
}
},
onchange: function() {
if (me.selected_payment !== this.value) {
me.selected_payment = this.value;
me.display_payment_details(this);
}
}
},
{
fieldtype: 'Section Break',
fieldname: 'section_break_3'
},
{
fieldtype: 'HTML',
fieldname: 'payment_details'
},
];
me.dialog = new frappe.ui.Dialog({
title: __("Choose a corresponding payment"),
fields: fields,
size: "large"
});
const proposals_wrapper = me.dialog.fields_dict.payment_proposals.$wrapper;
if (data && data.length > 0) {
proposals_wrapper.append(frappe.render_template("linked_payment_header"));
data.map(value => {
proposals_wrapper.append(frappe.render_template("linked_payment_row", value))
})
} else {
const empty_data_msg = __("ERPNext could not find any matching payment entry")
proposals_wrapper.append(`<div class="text-center"><h5 class="text-muted">${empty_data_msg}</h5></div>`)
}
$(me.dialog.body).on('click', '.reconciliation-btn', (e) => {
const payment_entry = $(e.target).attr('data-name');
const payment_doctype = $(e.target).attr('data-doctype');
frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.reconcile',
{bank_transaction: me.bank_entry, payment_doctype: payment_doctype, payment_name: payment_entry})
.then((result) => {
setTimeout(function(){
erpnext.accounts.ReconciliationList.refresh();
}, 2000);
me.dialog.hide();
})
})
me.dialog.show();
}
display_payment_details(event) {
const me = this;
if (event.value) {
let dt = me.dialog.fields_dict.payment_doctype.value;
me.dialog.fields_dict['payment_details'].$wrapper.empty();
frappe.db.get_doc(dt, event.value)
.then(doc => {
let displayed_docs = []
if (dt === "Payment Entry") {
payment.currency = doc.payment_type == "Receive" ? doc.paid_to_account_currency : doc.paid_from_account_currency;
payment.doctype = dt
displayed_docs.push(payment);
} else if (dt === "Journal Entry") {
doc.accounts.forEach(payment => {
if (payment.account === me.gl_account) {
payment.doctype = dt;
payment.posting_date = doc.posting_date;
payment.party = doc.pay_to_recd_from;
payment.reference_no = doc.cheque_no;
payment.reference_date = doc.cheque_date;
payment.currency = payment.account_currency;
payment.paid_amount = payment.credit > 0 ? payment.credit : payment.debit;
payment.name = doc.name;
displayed_docs.push(payment);
}
})
} else if (dt === "Sales Invoice") {
doc.payments.forEach(payment => {
if (payment.clearance_date === null || payment.clearance_date === "") {
payment.doctype = dt;
payment.posting_date = doc.posting_date;
payment.party = doc.customer;
payment.reference_no = doc.remarks;
payment.currency = doc.currency;
payment.paid_amount = payment.amount;
payment.name = doc.name;
displayed_docs.push(payment);
}
})
}
const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
details_wrapper.append(frappe.render_template("linked_payment_header"));
displayed_docs.forEach(values => {
details_wrapper.append(frappe.render_template("linked_payment_row", values));
})
})
}
}
}

View File

@@ -0,0 +1,29 @@
{
"content": null,
"creation": "2018-11-24 12:03:14.646669",
"docstatus": 0,
"doctype": "Page",
"idx": 0,
"modified": "2018-11-24 12:03:14.646669",
"modified_by": "Administrator",
"module": "Accounts",
"name": "bank-reconciliation",
"owner": "Administrator",
"page_name": "bank-reconciliation",
"roles": [
{
"role": "System Manager"
},
{
"role": "Accounts Manager"
},
{
"role": "Accounts User"
}
],
"script": null,
"standard": "Yes",
"style": null,
"system_page": 0,
"title": "Bank Reconciliation"
}

View File

@@ -0,0 +1,358 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
import difflib
from frappe.utils import flt
from six import iteritems
from erpnext import get_company_currency
@frappe.whitelist()
def reconcile(bank_transaction, payment_doctype, payment_name):
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
payment_entry = frappe.get_doc(payment_doctype, payment_name)
account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
gl_entry = frappe.get_doc("GL Entry", dict(account=account, voucher_type=payment_doctype, voucher_no=payment_name))
if transaction.unallocated_amount == 0:
frappe.throw(_("This bank transaction is already fully reconciled"))
if transaction.credit > 0 and gl_entry.credit > 0:
frappe.throw(_("The selected payment entry should be linked with a debtor bank transaction"))
if transaction.debit > 0 and gl_entry.debit > 0:
frappe.throw(_("The selected payment entry should be linked with a creditor bank transaction"))
add_payment_to_transaction(transaction, payment_entry, gl_entry)
return 'reconciled'
def add_payment_to_transaction(transaction, payment_entry, gl_entry):
gl_amount, transaction_amount = (gl_entry.credit, transaction.debit) if gl_entry.credit > 0 else (gl_entry.debit, transaction.credit)
allocated_amount = gl_amount if gl_amount <= transaction_amount else transaction_amount
transaction.append("payment_entries", {
"payment_document": payment_entry.doctype,
"payment_entry": payment_entry.name,
"allocated_amount": allocated_amount
})
transaction.save()
@frappe.whitelist()
def get_linked_payments(bank_transaction):
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
bank_account = frappe.db.get_values("Bank Account", transaction.bank_account, ["account", "company"], as_dict=True)
# Get all payment entries with a matching amount
amount_matching = check_matching_amount(bank_account[0].account, bank_account[0].company, transaction)
# Get some data from payment entries linked to a corresponding bank transaction
description_matching = get_matching_descriptions_data(bank_account[0].company, transaction)
if amount_matching:
return check_amount_vs_description(amount_matching, description_matching)
elif description_matching:
return sorted(description_matching, key = lambda x: x["posting_date"], reverse=True)
else:
return []
def check_matching_amount(bank_account, company, transaction):
payments = []
amount = transaction.credit if transaction.credit > 0 else transaction.debit
payment_type = "Receive" if transaction.credit > 0 else "Pay"
account_from_to = "paid_to" if transaction.credit > 0 else "paid_from"
currency_field = "paid_to_account_currency as currency" if transaction.credit > 0 else "paid_from_account_currency as currency"
payment_entries = frappe.get_all("Payment Entry", fields=["'Payment Entry' as doctype", "name", "paid_amount", "payment_type", "reference_no", "reference_date",
"party", "party_type", "posting_date", "{0}".format(currency_field)], filters=[["paid_amount", "like", "{0}%".format(amount)],
["docstatus", "=", "1"], ["payment_type", "=", payment_type], ["ifnull(clearance_date, '')", "=", ""], ["{0}".format(account_from_to), "=", "{0}".format(bank_account)]])
if transaction.credit > 0:
journal_entries = frappe.db.sql("""
SELECT
'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no,
je.pay_to_recd_from as party, je.cheque_date as reference_date, jea.debit_in_account_currency as paid_amount
FROM
`tabJournal Entry Account` as jea
JOIN
`tabJournal Entry` as je
ON
jea.parent = je.name
WHERE
(je.clearance_date is null or je.clearance_date='0000-00-00')
AND
jea.account = %s
AND
jea.debit_in_account_currency like %s
AND
je.docstatus = 1
""", (bank_account, amount), as_dict=True)
else:
journal_entries = frappe.db.sql("""
SELECT
'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no,
je.pay_to_recd_from as party, je.cheque_date as reference_date, jea.credit_in_account_currency as paid_amount
FROM
`tabJournal Entry Account` as jea
JOIN
`tabJournal Entry` as je
ON
jea.parent = je.name
WHERE
(je.clearance_date is null or je.clearance_date='0000-00-00')
AND
jea.account = %s
AND
jea.credit_in_account_currency like %s
AND
je.docstatus = 1
""", (bank_account, amount), as_dict=True)
if transaction.credit > 0:
sales_invoices = frappe.db.sql("""
SELECT
'Sales Invoice' as doctype, si.name, si.customer as party,
si.posting_date, sip.amount as paid_amount
FROM
`tabSales Invoice Payment` as sip
JOIN
`tabSales Invoice` as si
ON
sip.parent = si.name
WHERE
(sip.clearance_date is null or sip.clearance_date='0000-00-00')
AND
sip.account = %s
AND
sip.amount like %s
AND
si.docstatus = 1
""", (bank_account, amount), as_dict=True)
else:
sales_invoices = []
if transaction.debit > 0:
purchase_invoices = frappe.get_all("Purchase Invoice",
fields = ["'Purchase Invoice' as doctype", "name", "paid_amount", "supplier as party", "posting_date", "currency"],
filters=[
["paid_amount", "like", "{0}%".format(amount)],
["docstatus", "=", "1"],
["is_paid", "=", "1"],
["ifnull(clearance_date, '')", "=", ""],
["cash_bank_account", "=", "{0}".format(bank_account)]
]
)
mode_of_payments = [x["parent"] for x in frappe.db.get_list("Mode of Payment Account",
filters={"default_account": bank_account}, fields=["parent"])]
company_currency = get_company_currency(company)
expense_claims = frappe.get_all("Expense Claim",
fields=["'Expense Claim' as doctype", "name", "total_sanctioned_amount as paid_amount",
"employee as party", "posting_date", "'{0}' as currency".format(company_currency)],
filters=[
["total_sanctioned_amount", "like", "{0}%".format(amount)],
["docstatus", "=", "1"],
["is_paid", "=", "1"],
["ifnull(clearance_date, '')", "=", ""],
["mode_of_payment", "in", "{0}".format(tuple(mode_of_payments))]
]
)
else:
purchase_invoices = expense_claims = []
for data in [payment_entries, journal_entries, sales_invoices, purchase_invoices, expense_claims]:
if data:
payments.extend(data)
return payments
def get_matching_descriptions_data(company, transaction):
if not transaction.description :
return []
bank_transactions = frappe.db.sql("""
SELECT
bt.name, bt.description, bt.date, btp.payment_document, btp.payment_entry
FROM
`tabBank Transaction` as bt
LEFT JOIN
`tabBank Transaction Payments` as btp
ON
bt.name = btp.parent
WHERE
bt.allocated_amount > 0
AND
bt.docstatus = 1
""", as_dict=True)
selection = []
for bank_transaction in bank_transactions:
if bank_transaction.description:
seq=difflib.SequenceMatcher(lambda x: x == " ", transaction.description, bank_transaction.description)
if seq.ratio() > 0.6:
bank_transaction["ratio"] = seq.ratio()
selection.append(bank_transaction)
document_types = set([x["payment_document"] for x in selection])
links = {}
for document_type in document_types:
links[document_type] = [x["payment_entry"] for x in selection if x["payment_document"]==document_type]
data = []
company_currency = get_company_currency(company)
for key, value in iteritems(links):
if key == "Payment Entry":
data.extend(frappe.get_all("Payment Entry", filters=[["name", "in", value]], fields=["'Payment Entry' as doctype", "posting_date", "party", "reference_no", "reference_date", "paid_amount", "paid_to_account_currency as currency"]))
if key == "Journal Entry":
journal_entries = frappe.get_all("Journal Entry", filters=[["name", "in", value]], fields=["name", "'Journal Entry' as doctype", "posting_date", "pay_to_recd_from as party", "cheque_no as reference_no", "cheque_date as reference_date", "total_credit as paid_amount"])
for journal_entry in journal_entries:
journal_entry_accounts = frappe.get_all("Journal Entry Account", filters={"parenttype": journal_entry["doctype"], "parent": journal_entry["name"]}, fields=["account_currency"])
journal_entry["currency"] = journal_entry_accounts[0]["account_currency"] if journal_entry_accounts else company_currency
data.extend(journal_entries)
if key == "Sales Invoice":
data.extend(frappe.get_all("Sales Invoice", filters=[["name", "in", value]], fields=["'Sales Invoice' as doctype", "posting_date", "customer_name as party", "paid_amount", "currency"]))
if key == "Purchase Invoice":
data.extend(frappe.get_all("Purchase Invoice", filters=[["name", "in", value]], fields=["'Purchase Invoice' as doctype", "posting_date", "supplier_name as party", "paid_amount", "currency"]))
if key == "Expense Claim":
expense_claims = frappe.get_all("Expense Claim", filters=[["name", "in", value]], fields=["'Expense Claim' as doctype", "posting_date", "employee_name as party", "total_amount_reimbursed as paid_amount"])
data.extend([dict(x,**{"currency": company_currency}) for x in expense_claims])
return data
def check_amount_vs_description(amount_matching, description_matching):
result = []
if description_matching:
for am_match in amount_matching:
for des_match in description_matching:
if am_match["party"] == des_match["party"]:
if am_match not in result:
result.append(am_match)
continue
if "reference_no" in am_match and "reference_no" in des_match:
if difflib.SequenceMatcher(lambda x: x == " ", am_match["reference_no"], des_match["reference_no"]).ratio() > 70:
if am_match not in result:
result.append(am_match)
if result:
return sorted(result, key = lambda x: x["posting_date"], reverse=True)
else:
return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
else:
return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
def get_matching_transactions_payments(description_matching):
payments = [x["payment_entry"] for x in description_matching]
payment_by_ratio = {x["payment_entry"]: x["ratio"] for x in description_matching}
if payments:
reference_payment_list = frappe.get_all("Payment Entry", fields=["name", "paid_amount", "payment_type", "reference_no", "reference_date",
"party", "party_type", "posting_date", "paid_to_account_currency"], filters=[["name", "in", payments]])
return sorted(reference_payment_list, key=lambda x: payment_by_ratio[x["name"]])
else:
return []
def payment_entry_query(doctype, txt, searchfield, start, page_len, filters):
account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
if not account:
return
return frappe.db.sql("""
SELECT
name, party, paid_amount, received_amount, reference_no
FROM
`tabPayment Entry`
WHERE
(clearance_date is null or clearance_date='0000-00-00')
AND (paid_from = %(account)s or paid_to = %(account)s)
AND (name like %(txt)s or party like %(txt)s)
AND docstatus = 1
ORDER BY
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), name
LIMIT
%(start)s, %(page_len)s""",
{
'txt': "%%%s%%" % txt,
'_txt': txt.replace("%", ""),
'start': start,
'page_len': page_len,
'account': account
}
)
def journal_entry_query(doctype, txt, searchfield, start, page_len, filters):
account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
return frappe.db.sql("""
SELECT
jea.parent, je.pay_to_recd_from,
if(jea.debit_in_account_currency > 0, jea.debit_in_account_currency, jea.credit_in_account_currency)
FROM
`tabJournal Entry Account` as jea
LEFT JOIN
`tabJournal Entry` as je
ON
jea.parent = je.name
WHERE
(je.clearance_date is null or je.clearance_date='0000-00-00')
AND
jea.account = %(account)s
AND
(jea.parent like %(txt)s or je.pay_to_recd_from like %(txt)s)
AND
je.docstatus = 1
ORDER BY
if(locate(%(_txt)s, jea.parent), locate(%(_txt)s, jea.parent), 99999),
jea.parent
LIMIT
%(start)s, %(page_len)s""",
{
'txt': "%%%s%%" % txt,
'_txt': txt.replace("%", ""),
'start': start,
'page_len': page_len,
'account': account
}
)
def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""
SELECT
sip.parent, si.customer, sip.amount, sip.mode_of_payment
FROM
`tabSales Invoice Payment` as sip
LEFT JOIN
`tabSales Invoice` as si
ON
sip.parent = si.name
WHERE
(sip.clearance_date is null or sip.clearance_date='0000-00-00')
AND
(sip.parent like %(txt)s or si.customer like %(txt)s)
ORDER BY
if(locate(%(_txt)s, sip.parent), locate(%(_txt)s, sip.parent), 99999),
sip.parent
LIMIT
%(start)s, %(page_len)s""",
{
'txt': "%%%s%%" % txt,
'_txt': txt.replace("%", ""),
'start': start,
'page_len': page_len
}
)

View File

@@ -0,0 +1,21 @@
<div class="transaction-header">
<div class="level list-row list-row-head text-muted small">
<div class="col-sm-2 ellipsis hidden-xs">
{{ __("Date") }}
</div>
<div class="col-xs-11 col-sm-4 ellipsis list-subject">
{{ __("Description") }}
</div>
<div class="col-sm-2 ellipsis hidden-xs">
{{ __("Debit") }}
</div>
<div class="col-sm-2 ellipsis hidden-xs">
{{ __("Credit") }}
</div>
<div class="col-sm-1 ellipsis hidden-xs">
{{ __("Currency") }}
</div>
<div class="col-sm-1 ellipsis">
</div>
</div>
</div>

View File

@@ -0,0 +1,36 @@
<div class="list-row transaction-item">
<div>
<div class="clickable-section" data-name={{ name }}>
<div class="col-sm-2 ellipsis hidden-xs">
{%= frappe.datetime.str_to_user(date) %}
</div>
<div class="col-xs-8 col-sm-4 ellipsis list-subject">
{{ description }}
</div>
<div class="col-sm-2 ellipsis hidden-xs">
{%= format_currency(debit, currency) %}
</div>
<div class="col-sm-2 ellipsis hidden-xs">
{%= format_currency(credit, currency) %}
</div>
<div class="col-sm-1 ellipsis hidden-xs">
{{ currency }}
</div>
</div>
<div class="col-xs-3 col-sm-1">
<div class="btn-group">
<a class="dropdown-toggle btn btn-default btn-xs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span>Actions </span>
<span class="caret"></span>
</a>
<ul class="dropdown-menu reports-dropdown" style="max-height: 300px; overflow-y: auto; right: 0px; left: auto;">
<li><a class="new-reconciliation" data-name={{ name }}>{{ __("Reconcile") }}</a></li>
<li class="divider"></li>
<li><a class="new-payment" data-name={{ name }}>{{ __("New Payment") }}</a></li>
<li><a class="new-invoice" data-name={{ name }}>{{ __("New Invoice") }}</a></li>
<li><a class="new-expense" data-name={{ name }}>{{ __("New Expense") }}</a></li>
</ul>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,21 @@
<div class="transaction-header">
<div class="level list-row list-row-head text-muted small">
<div class="col-xs-3 col-sm-2 ellipsis">
{{ __("Payment Name") }}
</div>
<div class="col-xs-3 col-sm-2 ellipsis">
{{ __("Reference Date") }}
</div>
<div class="col-sm-2 ellipsis hidden-xs">
{{ __("Amount") }}
</div>
<div class="col-sm-2 ellipsis hidden-xs">
{{ __("Party") }}
</div>
<div class="col-xs-3 col-sm-2 ellipsis">
{{ __("Reference Number") }}
</div>
<div class="col-xs-2 col-sm-2">
</div>
</div>
</div>

View File

@@ -0,0 +1,36 @@
<div class="list-row">
<div>
<div class="col-xs-3 col-sm-2 ellipsis">
{{ name }}
</div>
<div class="col-xs-3 col-sm-2 ellipsis">
{% if (typeof reference_date !== "undefined") %}
{%= frappe.datetime.str_to_user(reference_date) %}
{% else %}
{% if (typeof posting_date !== "undefined") %}
{%= frappe.datetime.str_to_user(posting_date) %}
{% endif %}
{% endif %}
</div>
<div class="col-sm-2 ellipsis hidden-xs">
{{ format_currency(paid_amount, currency) }}
</div>
<div class="col-sm-2 ellipsis hidden-xs">
{% if (typeof party !== "undefined") %}
{{ party }}
{% endif %}
</div>
<div class="col-xs-3 col-sm-2 ellipsis">
{% if (typeof reference_no !== "undefined") %}
{{ reference_no }}
{% else %}
{{ "" }}
{% endif %}
</div>
<div class="col-xs-2 col-sm-2">
<div class="text-right margin-bottom">
<button class="btn btn-primary btn-xs reconciliation-btn" data-doctype="{{ doctype }}" data-name="{{ name }}">{{ __("Reconcile") }}</button>
</div>
</div>
</div>
</div>

View File

@@ -333,6 +333,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
var me = this;
this.frm = {}
this.load_data(true);
this.frm.doc.offline_pos_name = '';
this.setup();
this.set_default_customer()
},
@@ -345,7 +346,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
if (load_doc) {
this.frm.doc = JSON.parse(localStorage.getItem('doc'));
this.frm.doc.offline_pos_name = null;
}
$.each(this.meta, function (i, data) {
@@ -641,7 +641,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
me.list_customers_btn.toggleClass("view_customer");
me.pos_bill.show();
me.list_customers_btn.show();
me.frm.doc.offline_pos_name = $(this).parents().attr('invoice-name')
me.frm.doc.offline_pos_name = $(this).parents().attr('invoice-name');
me.edit_record();
})
@@ -984,7 +984,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}
if(!this.customer_doc.fields_dict.customer_pos_id.value) {
this.customer_doc.set_value("customer_pos_id", $.now())
this.customer_doc.set_value("customer_pos_id", frappe.datetime.now_datetime())
}
},
@@ -1686,10 +1686,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
create_invoice: function () {
var me = this;
var existing_pos_list = [];
var invoice_data = {};
this.si_docs = this.get_doc_from_localstorage();
if (this.frm.doc.offline_pos_name) {
if(this.si_docs) {
this.si_docs.forEach((row) => {
existing_pos_list.push(Object.keys(row));
});
}
if (this.frm.doc.offline_pos_name
&& in_list(existing_pos_list, this.frm.doc.offline_pos_name)) {
this.update_invoice()
//to retrieve and set the default payment
invoice_data[this.frm.doc.offline_pos_name] = this.frm.doc;
@@ -1698,8 +1706,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.frm.doc.paid_amount = this.frm.doc.net_total
this.frm.doc.outstanding_amount = 0
} else {
this.frm.doc.offline_pos_name = $.now();
} else if(!this.frm.doc.offline_pos_name) {
this.frm.doc.offline_pos_name = frappe.datetime.now_datetime();
this.frm.doc.posting_date = frappe.datetime.get_today();
this.frm.doc.posting_time = frappe.datetime.now_time();
this.frm.doc.pos_total_qty = this.frm.doc.qty_total;

View File

@@ -573,13 +573,17 @@ def get_party_shipping_address(doctype, name):
else:
return ''
def get_partywise_advanced_payment_amount(party_type="Customer"):
def get_partywise_advanced_payment_amount(party_type, posting_date = None):
cond = "1=1"
if posting_date:
cond = "posting_date <= '{0}'".format(posting_date)
data = frappe.db.sql(""" SELECT party, sum({0}) as amount
FROM `tabGL Entry`
WHERE
party_type = %s and against_voucher is null
GROUP BY party"""
.format(("credit") if party_type == "Customer" else "debit") , party_type)
and {1} GROUP BY party"""
.format(("credit") if party_type == "Customer" else "debit", cond) , party_type)
if data:
return frappe._dict(data)

View File

@@ -6,17 +6,18 @@
</style>
<div class="page-break">
<div>
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
and doc.set("select_print_heading", _("Payment Entry")) -%}{%- endif -%}
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
<div class="row margin-bottom">
<div class="col-sm-6">
<div class="col-xs-6">
<table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
</table>
</div>
<div>
<div class="col-xs-6">
<table>
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
</table>
@@ -30,53 +31,46 @@
<th>Party</th>
<th>Amount</th>
</tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
</tr>
{% for entries in gl %}
{% if entries.credit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
<td class="left top-bottom">{{ entries.debit }}</td>
</tr>
<tr>
<td class="top-bottom"colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
</tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
</tr>
{% set total_credit = 0 -%}
{% for entries in doc.gl_entries %}
{% for entries in gl %}
{% if entries.debit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
<td class="left top-bottom">{{ entries.credit }}</td>
{% set total_credit = total_credit + entries.credit -%}
</tr>
<tr>
<td class="top-bottom" colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
<td class="left" >{{total_credit}}</td>
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td class="top-bottom" colspan="4"> </td>
</tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
</tr>
{% set total_debit = 0 -%}
{% for entries in doc.gl_entries %}
{% if entries.credit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
{% set total_debit = total_debit + entries.debit -%}
<td class="left top-bottom">{{ entries.debit }}</td>
</tr>
<tr>
<td class="top-bottom"colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
</tr>
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
<td class="left" >{{total_debit}}</td>
</tr>
{% endif %}
{% endfor %}
</table>
<div>
</div>

View File

@@ -1,19 +1,23 @@
{
"creation": "2014-08-28 11:11:39.796473",
"custom_format": 0,
"disabled": 0,
"doc_type": "Journal Entry",
"docstatus": 0,
"doctype": "Print Format",
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
"idx": 2,
"modified": "2015-07-22 17:42:01.560817",
"modified_by": "Administrator",
"name": "Credit Note",
"owner": "Administrator",
"parent": "Journal Entry",
"parentfield": "__print_formats",
"parenttype": "DocType",
"print_format_type": "Server",
"align_labels_right": 0,
"creation": "2014-08-28 11:11:39.796473",
"custom_format": 0,
"disabled": 0,
"doc_type": "Journal Entry",
"docstatus": 0,
"doctype": "Print Format",
"format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\t\\t\\t\\t<h2>Journal Entry<br><small>{{ doc.name }}</small>\\t\\t\\t\\t</h2></div>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"voucher_type\", \"print_hide\": 0, \"label\": \"Entry Type\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"posting_date\", \"print_hide\": 0, \"label\": \"Posting Date\"}, {\"fieldname\": \"finance_book\", \"print_hide\": 0, \"label\": \"Finance Book\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"accounts\", \"print_hide\": 0, \"label\": \"Accounting Entries\", \"visible_columns\": [{\"fieldname\": \"account\", \"print_width\": \"250px\", \"print_hide\": 0}, {\"fieldname\": \"bank_account_no\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"party_type\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"party\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"debit_in_account_currency\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"credit_in_account_currency\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"reference_type\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"reference_name\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"reference_due_date\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"project\", \"print_width\": \"\", \"print_hide\": 0}]}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"cheque_no\", \"print_hide\": 0, \"label\": \"Reference Number\"}, {\"fieldname\": \"cheque_date\", \"print_hide\": 0, \"label\": \"Reference Date\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"get_balance\", \"print_hide\": 0, \"label\": \"Make Difference Entry\"}, {\"fieldname\": \"total_amount\", \"print_hide\": 0, \"label\": \"Total Amount\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Reference\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"clearance_date\", \"print_hide\": 0, \"label\": \"Clearance Date\"}, {\"fieldname\": \"remark\", \"print_hide\": 0, \"label\": \"Remark\"}, {\"fieldname\": \"inter_company_journal_entry_reference\", \"print_hide\": 0, \"label\": \"Inter Company Journal Entry Reference\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"due_date\", \"print_hide\": 0, \"label\": \"Due Date\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Printing Settings\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"pay_to_recd_from\", \"print_hide\": 0, \"label\": \"Pay To / Recd From\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"letter_head\", \"print_hide\": 0, \"label\": \"Letter Head\"}, {\"fieldtype\": \"Section Break\", \"label\": \"More Information\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"mode_of_payment\", \"print_hide\": 0, \"label\": \"Mode of Payment\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"stock_entry\", \"print_hide\": 0, \"label\": \"Stock Entry\"}]",
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
"idx": 2,
"line_breaks": 0,
"modified": "2019-04-18 12:10:14.732269",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Credit Note",
"owner": "Administrator",
"parentfield": "__print_formats",
"print_format_builder": 0,
"print_format_type": "Server",
"show_section_headings": 0,
"standard": "Yes"
}

View File

@@ -3,26 +3,25 @@
.table-bordered td.top-bottom {border-top: none !important;border-bottom: none !important;}
.table-bordered td.right{border-right: none !important;}
.table-bordered td.left{border-left: none !important;}
</style>
<div class="page-break">
<div>
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
and doc.set("select_print_heading", _("Journal Entry")) -%}{%- endif -%}
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
<div class="row margin-bottom">
<div class="col-sm-6">
<div class="row">
<div class="col-xs-6">
<table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
</table>
</div>
<div>
<div class="col-xs-6">
<table>
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
</table>
</div>
</div>
<div class="margin-top">
<div>
<table class="table table-bordered table-condensed">
<tr>
<th>Account</th>
@@ -30,47 +29,43 @@
<th>Party</th>
<th>Amount</th>
</tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
</tr>
{% for entries in gl %}
{% if entries.credit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
<td class="left top-bottom">{{ entries.debit }}</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
</tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
</tr>
{% set total_credit = 0 -%}
{% for entries in doc.gl_entries %}
{% for entries in gl %}
{% if entries.debit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
<td class="left top-bottom">{{ entries.credit }}</td>
{% set total_credit = total_credit + entries.credit -%}
</tr>
<tr>
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
<td class="left" >{{total_credit}}</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td class="top-bottom" colspan="4"> </td>
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
</tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
<td class="top-bottom" colspan="5"><b>Narration: </b>{{ gl[0].remarks }}</td>
</tr>
{% set total_debit = 0 -%}
{% for entries in doc.gl_entries %}
{% if entries.credit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
{% set total_debit = total_debit + entries.debit -%}
<td class="left top-bottom">{{ entries.debit }}</td>
</tr>
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
<td class="left" >{{total_debit}}</td>
</tr>
{% endif %}
{% endfor %}
</table>
<div>
</div>

View File

@@ -1,10 +1,11 @@
{%- from "templates/print_formats/standard_macros.html" import add_header -%}
<div class="page-break">
<div>
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
and doc.set("select_print_heading", _("Purchase Invoice")) -%}{%- endif -%}
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
<div class="row margin-bottom">
<div class="col-sm-6">
<div class="col-xs-6">
<table>
<tr><td><strong>Supplier Name: </strong></td><td>{{ doc.supplier }}</td></tr>
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
@@ -13,7 +14,7 @@
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
</table>
</div>
<div>
<div class="col-xs-6">
<table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
@@ -49,21 +50,27 @@
</table>
</div>
<div class="row margin-bottom">
<div class="col-sm-6">
<div class="col-xs-6">
<table>
<tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr>
<tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr>
<tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr>
</table>
</div>
<div>
<div class="col-xs-6">
<table>
<tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr>
{% for tax in doc.taxes %}
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
{% if tax.tax_amount_after_discount_amount!= 0 %}
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
{% endif %}
{% endfor %}
{% if doc.taxes_and_charges_added!= 0 %}
<tr><td><strong> Taxes and Charges Added: </strong></td><td>{{ doc.taxes_and_charges_added }}</td></tr>
{% endif %}
{% if doc.taxes_and_charges_deducted!= 0 %}
<tr><td><strong> Taxes and Charges Deducted: </strong></td><td>{{ doc.taxes_and_charges_deducted }}</td></tr>
{% endif %}
<tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr>
<tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr>
</table>
@@ -76,17 +83,17 @@
<th>Account</th>
<th>Party Type</th>
<th>Party</th>
<th>Credit Amount</th>
<th>Debit Amount</th>
<th>Credit Amount</th>
</tr>
{% for entries in doc.gl_entries %}
{% for entries in gl %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ entries.account }}</td>
<td>{{ entries.party_type }}</td>
<td>{{ entries.party }}</td>
<td>{{ entries.credit }}</td>
<td>{{ entries.debit }}</td>
<td>{{ entries.credit }}</td>
</tr>
{% endfor %}
<tr>

View File

@@ -1,10 +1,11 @@
{%- from "templates/print_formats/standard_macros.html" import add_header -%}
<div class="page-break">
<div>
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
and doc.set("select_print_heading", _("Sales Invoice")) -%}{%- endif -%}
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
<div class="row margin-bottom">
<div class="col-sm-6">
<div class="col-xs-6">
<table>
<tr><td><strong>Customer Name: </strong></td><td>{{ doc.customer }}</td></tr>
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
@@ -13,7 +14,7 @@
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
</table>
</div>
<div>
<div class="col-xs-6">
<table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
@@ -45,18 +46,20 @@
</table>
</div>
<div class="row margin-bottom">
<div class="col-sm-6">
<div class="col-xs-6">
<table>
<tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr>
<tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr>
<tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr>
</table>
</div>
<div>
<div class="col-xs-6">
<table>
<tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr>
{% for tax in doc.taxes %}
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
{% if tax.tax_amount_after_discount_amount!= 0 %}
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
{% endif %}
{% endfor %}
<tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr>
<tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr>
@@ -70,17 +73,17 @@
<th>Account</th>
<th>Party Type</th>
<th>Party</th>
<th>Credit Amount</th>
<th>Debit Amount</th>
<th>Credit Amount</th>
</tr>
{% for entries in doc.gl_entries %}
{% for entries in gl %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ entries.account }}</td>
<td>{{ entries.party_type }}</td>
<td>{{ entries.party }}</td>
<td>{{ entries.credit }}</td>
<td>{{ entries.debit }}</td>
<td>{{ entries.credit }}</td>
</tr>
{% endfor %}
<tr>

View File

@@ -107,26 +107,28 @@
<thead>
<tr>
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
<th style="width: 7%">{%= __("Date") %}</th>
<th style="width: 7%">{%= __("Age (Days)") %}</th>
<th style="width: 13%">{%= __("Reference") %}</th>
{% if(report.report_name === "Accounts Receivable") { %}
<th style="width: 10%">{%= __("Sales Person") %}</th>
<th style="width: 10%">{%= __("Date") %}</th>
<th style="width: 4%">{%= __("Age (Days)") %}</th>
{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
<th style="width: 16%">{%= __("Reference") %}</th>
<th style="width: 10%">{%= __("Sales Person") %}</th>
{% } else { %}
<th style="width: 26%">{%= __("Reference") %}</th>
{% } %}
{% if(!filters.show_pdc_in_print) { %}
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
{% } %}
<th style="width: 10%; text-align: right">{%= __("Invoiced Amount") %}</th>
{% if(!filters.show_pdc_in_print) { %}
<th style="width: 10%; text-align: right">{%= __("Paid Amount") %}</th>
<th style="width: 10%; text-align: right">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
{% } %}
<th style="width: 15%; text-align: right">{%= __("Outstanding Amount") %}</th>
<th style="width: 10%; text-align: right">{%= __("Outstanding Amount") %}</th>
{% if(filters.show_pdc_in_print) { %}
{% if(report.report_name === "Accounts Receivable") { %}
<th style="width: 10%">{%= __("Customer LPO No.") %}</th>
{% } %}
<th style="width: 10%">{%= __("PDC/LC Date") %}</th>
<th style="width: 10%">{%= __("PDC/LC Ref") %}</th>
<th style="width: 10%">{%= __("PDC/LC Amount") %}</th>
<th style="width: 10%">{%= __("Remaining Balance") %}</th>
@@ -155,7 +157,7 @@
{%= data[i]["voucher_no"] %}
</td>
{% if(report.report_name === "Accounts Receivable") { %}
{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
<td>{%= data[i]["sales_person"] %}</td>
{% } %}
@@ -195,7 +197,6 @@
<td style="text-align: right">
{%= data[i]["po_no"] %}</td>
{% } %}
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][("pdc/lc_date")]) %}</td>
<td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td>
<td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td>
@@ -205,7 +206,7 @@
{% if(!filters.show_pdc_in_print) { %}
<td></td>
{% } %}
{% if(report.report_name === "Accounts Receivable") { %}
{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
<td></td>
{% } %}
<td></td>
@@ -226,7 +227,6 @@
<td style="text-align: right">
{%= data[i][__("Customer LPO")] %}</td>
{% } %}
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][__("PDC/LC Date")]) %}</td>
<td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td>
<td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td>

View File

@@ -102,14 +102,19 @@ frappe.query_reports["Accounts Receivable"] = {
"fieldtype": "Link",
"options": "Sales Person"
},
{
"fieldname":"based_on_payment_terms",
"label": __("Based On Payment Terms"),
"fieldtype": "Check",
},
{
"fieldname":"show_pdc_in_print",
"label": __("Show PDC in Print"),
"fieldtype": "Check",
},
{
"fieldname":"based_on_payment_terms",
"label": __("Based On Payment Terms"),
"fieldname":"show_sales_person_in_print",
"label": __("Show Sales Person in Print"),
"fieldtype": "Check",
},
{

View File

@@ -194,10 +194,9 @@ class ReceivablePayableReport(object):
self.payment_term_map = self.get_payment_term_detail(voucher_nos)
for gle in gl_entries_data:
if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers):
if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers, return_entries):
outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount(
gle,self.filters.report_date, self.dr_or_cr, return_entries)
temp_outstanding_amt = outstanding_amount
temp_credit_note_amt = credit_note_amount
@@ -377,7 +376,7 @@ class ReceivablePayableReport(object):
# returns a generator
return self.get_gl_entries(party_type, report_date)
def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers):
def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers, return_entries):
return (
# advance
(not gle.against_voucher) or
@@ -388,30 +387,37 @@ class ReceivablePayableReport(object):
# sales invoice/purchase invoice
(gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0) or
# standalone credit notes
(gle.against_voucher==gle.voucher_no and gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no)) or
# entries adjusted with future vouchers
((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
)
def get_return_entries(self, party_type):
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})]
return_entries = frappe._dict(frappe.get_all(doctype,
filters={"is_return": 1, "docstatus": 1}, fields=["name", "return_against"], as_list=1))
return return_entries
def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries):
payment_amount, credit_note_amount = 0.0, 0.0
reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
if getdate(e.posting_date) <= report_date and e.name!=gle.name:
if getdate(e.posting_date) <= report_date \
and (e.name!=gle.name or (e.voucher_no in return_entries and not return_entries.get(e.voucher_no))):
amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision)
if e.voucher_no not in return_entries:
payment_amount += amount
else:
credit_note_amount += amount
outstanding_amount = (flt((flt(gle.get(dr_or_cr), self.currency_precision)
- flt(gle.get(reverse_dr_or_cr), self.currency_precision)
- payment_amount - credit_note_amount), self.currency_precision))
voucher_amount = flt(gle.get(dr_or_cr), self.currency_precision) - flt(gle.get(reverse_dr_or_cr), self.currency_precision)
if gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no):
voucher_amount = 0
outstanding_amount = flt((voucher_amount - payment_amount - credit_note_amount), self.currency_precision)
credit_note_amount = flt(credit_note_amount, self.currency_precision)
return outstanding_amount, credit_note_amount, payment_amount
@@ -481,13 +487,8 @@ class ReceivablePayableReport(object):
conditions.append("company=%s")
values.append(self.filters.company)
company_finance_book = erpnext.get_default_finance_book(self.filters.company)
if not self.filters.finance_book or (self.filters.finance_book == company_finance_book):
if self.filters.finance_book:
conditions.append("ifnull(finance_book,'') in (%s, '')")
values.append(company_finance_book)
elif self.filters.finance_book:
conditions.append("ifnull(finance_book,'') = %s")
values.append(self.filters.finance_book)
if self.filters.get(party_type_field):

View File

@@ -136,7 +136,8 @@ class AccountsReceivableSummary(ReceivablePayableReport):
partywise_total = self.get_partywise_total(party_naming_by, args)
partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type")) or {}
partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type"),
self.filters.get("report_date")) or {}
for party, party_dict in iteritems(partywise_total):
row = [party]
@@ -144,7 +145,10 @@ class AccountsReceivableSummary(ReceivablePayableReport):
row += [self.get_party_name(args.get("party_type"), party)]
row += [partywise_advance_amount.get(party, 0)]
paid_amt = flt(party_dict.paid_amt - partywise_advance_amount.get(party, 0))
paid_amt = 0
if party_dict.paid_amt > 0:
paid_amt = flt(party_dict.paid_amt - partywise_advance_amount.get(party, 0))
row += [
party_dict.invoiced_amt, paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,

View File

@@ -31,11 +31,8 @@ def get_data(filters):
filters_data.append(["against_voucher", "in", assets])
company_finance_book = erpnext.get_default_finance_book(filters.get("company"))
if (not filters.get('finance_book') or (filters.get('finance_book') == company_finance_book)):
if filters.get("finance_book"):
filters_data.append(["finance_book", "in", ['', filters.get('finance_book')]])
elif filters.get("finance_book"):
filters_data.append(["finance_book", "=", filters.get('finance_book')])
gl_entries = frappe.get_all('GL Entry',
filters= filters_data,

View File

@@ -101,7 +101,7 @@ def get_income_expense_data(companies, fiscal_year, filters):
net_profit_loss = get_net_profit_loss(income, expense, companies, filters.company, company_currency, True)
return income, expense, net_profit_loss
def get_cash_flow_data(fiscal_year, companies, filters):
cash_flow_accounts = get_cash_flow_accounts()
@@ -123,7 +123,7 @@ def get_cash_flow_data(fiscal_year, companies, filters):
# add first net income in operations section
if net_profit_loss:
net_profit_loss.update({
"indent": 1,
"indent": 1,
"parent_account": cash_flow_accounts[0]['section_header']
})
data.append(net_profit_loss)
@@ -327,7 +327,7 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g
accounts_by_name, ignore_closing_entries=False):
"""Returns a dict like { "account": [gl entries], ... }"""
company_lft, company_rgt = frappe.get_cached_value('Company',
company_lft, company_rgt = frappe.get_cached_value('Company',
filters.get('company'), ["lft", "rgt"])
additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters)
@@ -354,7 +354,8 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g
"to_date": to_date,
"lft": root_lft,
"rgt": root_rgt,
"company": d.name
"company": d.name,
"finance_book": filters.get("finance_book")
},
as_dict=True)
@@ -384,14 +385,8 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
if from_date:
additional_conditions.append("gl.posting_date >= %(from_date)s")
company_finance_book = erpnext.get_default_finance_book(filters.get("company"))
if not filters.get('finance_book') or (filters.get('finance_book') == company_finance_book):
additional_conditions.append("ifnull(finance_book, '') in ('%s', '')" %
frappe.db.escape(company_finance_book))
elif filters.get("finance_book"):
additional_conditions.append("ifnull(finance_book, '') = '%s' " %
frappe.db.escape(filters.get("finance_book")))
if filters.get("finance_book"):
additional_conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
import erpnext
from frappe import _
from frappe import _, scrub
from frappe.utils import getdate, nowdate
from six import iteritems, itervalues
@@ -14,6 +14,9 @@ class PartyLedgerSummaryReport(object):
self.filters.from_date = getdate(self.filters.from_date or nowdate())
self.filters.to_date = getdate(self.filters.to_date or nowdate())
if not self.filters.get("company"):
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
def run(self, args):
if self.filters.from_date > self.filters.to_date:
frappe.throw(_("From Date must be before To Date"))
@@ -21,10 +24,9 @@ class PartyLedgerSummaryReport(object):
self.filters.party_type = args.get("party_type")
self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
discount_account_field = "discount_allowed_account" if self.filters.party_type == "Customer" \
else "discount_received_account"
self.round_off_account, self.write_off_account, self.discount_account = frappe.get_cached_value('Company',
self.filters.company, ["round_off_account", "write_off_account", discount_account_field])
self.get_gl_entries()
self.get_return_invoices()
self.get_party_adjustment_amounts()
columns = self.get_columns()
data = self.get_data()
@@ -48,7 +50,6 @@ class PartyLedgerSummaryReport(object):
})
credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note"
discount_allowed_or_received = "Discount Allowed" if self.filters.party_type == "Customer" else "Discount Received"
columns += [
{
@@ -79,27 +80,19 @@ class PartyLedgerSummaryReport(object):
"options": "currency",
"width": 120
},
{
"label": _(discount_allowed_or_received),
"fieldname": "discount_amount",
]
for account in self.party_adjustment_accounts:
columns.append({
"label": account,
"fieldname": "adj_" + scrub(account),
"fieldtype": "Currency",
"options": "currency",
"width": 120
},
{
"label": _("Write Off Amount"),
"fieldname": "write_off_amount",
"fieldtype": "Currency",
"options": "currency",
"width": 120
},
{
"label": _("Other Adjustments"),
"fieldname": "adjustment_amount",
"fieldtype": "Currency",
"options": "currency",
"width": 120
},
"width": 120,
"is_adjustment": 1
})
columns += [
{
"label": _("Closing Balance"),
"fieldname": "closing_balance",
@@ -119,17 +112,10 @@ class PartyLedgerSummaryReport(object):
return columns
def get_data(self):
if not self.filters.get("company"):
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency")
invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit"
self.get_gl_entries()
self.get_return_invoices()
self.get_party_adjustment_amounts()
self.party_data = frappe._dict({})
for gle in self.gl_entries:
self.party_data.setdefault(gle.party, frappe._dict({
@@ -146,7 +132,7 @@ class PartyLedgerSummaryReport(object):
amount = gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr)
self.party_data[gle.party].closing_balance += amount
if gle.posting_date < self.filters.from_date:
if gle.posting_date < self.filters.from_date or gle.is_opening == "Yes":
self.party_data[gle.party].opening_balance += amount
else:
if amount > 0:
@@ -161,9 +147,10 @@ class PartyLedgerSummaryReport(object):
if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount:
total_party_adjustment = sum([amount for amount in itervalues(self.party_adjustment_details.get(party, {}))])
row.paid_amount -= total_party_adjustment
row.discount_amount = self.party_adjustment_details.get(party, {}).get(self.discount_account, 0)
row.write_off_amount = self.party_adjustment_details.get(party, {}).get(self.write_off_account, 0)
row.adjustment_amount = total_party_adjustment - row.discount_amount - row.write_off_amount
adjustments = self.party_adjustment_details.get(party, {})
for account in self.party_adjustment_accounts:
row["adj_" + scrub(account)] = adjustments.get(account, 0)
out.append(row)
@@ -182,7 +169,7 @@ class PartyLedgerSummaryReport(object):
self.gl_entries = frappe.db.sql("""
select
gle.posting_date, gle.party, gle.voucher_type, gle.voucher_no, gle.against_voucher_type,
gle.against_voucher, gle.debit, gle.credit {join_field}
gle.against_voucher, gle.debit, gle.credit, gle.is_opening {join_field}
from `tabGL Entry` gle
{join}
where
@@ -197,12 +184,8 @@ class PartyLedgerSummaryReport(object):
if self.filters.company:
conditions.append("gle.company=%(company)s")
self.filters.company_finance_book = erpnext.get_default_finance_book(self.filters.company)
if not self.filters.finance_book or (self.filters.finance_book == self.filters.company_finance_book):
conditions.append("ifnull(finance_book,'') in (%(company_finance_book)s, '')")
elif self.filters.finance_book:
conditions.append("ifnull(finance_book,'') = %(finance_book)s")
if self.filters.finance_book:
conditions.append("ifnull(finance_book,'') in (%(finance_book)s, '')")
if self.filters.get("party"):
conditions.append("party=%(party)s")
@@ -254,9 +237,10 @@ class PartyLedgerSummaryReport(object):
def get_party_adjustment_amounts(self):
conditions = self.prepare_conditions()
income_or_expense = "Expense" if self.filters.party_type == "Customer" else "Income"
income_or_expense = "Expense Account" if self.filters.party_type == "Customer" else "Income Account"
invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit"
round_off_account = frappe.get_cached_value('Company', self.filters.company, "round_off_account")
gl_entries = frappe.db.sql("""
select
@@ -267,7 +251,7 @@ class PartyLedgerSummaryReport(object):
docstatus < 2
and (voucher_type, voucher_no) in (
select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc
where acc.name = gle.account and acc.root_type = '{income_or_expense}'
where acc.name = gle.account and acc.account_type = '{income_or_expense}'
and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2
) and (voucher_type, voucher_no) in (
select voucher_type, voucher_no from `tabGL Entry` gle
@@ -277,6 +261,7 @@ class PartyLedgerSummaryReport(object):
""".format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True)
self.party_adjustment_details = {}
self.party_adjustment_accounts = set()
adjustment_voucher_entries = {}
for gle in gl_entries:
adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), [])
@@ -288,12 +273,12 @@ class PartyLedgerSummaryReport(object):
has_irrelevant_entry = False
for gle in voucher_gl_entries:
if gle.account == self.round_off_account:
if gle.account == round_off_account:
continue
elif gle.party:
parties.setdefault(gle.party, 0)
parties[gle.party] += gle.get(reverse_dr_or_cr) - gle.get(invoice_dr_or_cr)
elif frappe.get_cached_value("Account", gle.account, "root_type") == income_or_expense:
elif frappe.get_cached_value("Account", gle.account, "account_type") == income_or_expense:
accounts.setdefault(gle.account, 0)
accounts[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr)
else:
@@ -303,11 +288,13 @@ class PartyLedgerSummaryReport(object):
if len(parties) == 1:
party = parties.keys()[0]
for account, amount in iteritems(accounts):
self.party_adjustment_accounts.add(account)
self.party_adjustment_details.setdefault(party, {})
self.party_adjustment_details[party].setdefault(account, 0)
self.party_adjustment_details[party][account] += amount
elif len(accounts) == 1 and not has_irrelevant_entry:
account = accounts.keys()[0]
self.party_adjustment_accounts.add(account)
for party, amount in iteritems(parties):
self.party_adjustment_details.setdefault(party, {})
self.party_adjustment_details[party].setdefault(account, 0)

View File

@@ -359,7 +359,8 @@ def set_gl_entries_by_account(
"from_date": from_date,
"to_date": to_date,
"cost_center": filters.cost_center,
"project": filters.project
"project": filters.project,
"finance_book": filters.get("finance_book")
},
as_dict=True)
@@ -392,14 +393,8 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
additional_conditions.append("cost_center in %(cost_center)s")
company_finance_book = erpnext.get_default_finance_book(filters.get("company"))
if not filters.get('finance_book') or (filters.get('finance_book') == company_finance_book):
additional_conditions.append("ifnull(finance_book, '') in ('%s', '')" %
frappe.db.escape(company_finance_book))
elif filters.get("finance_book"):
additional_conditions.append("ifnull(finance_book, '') = '%s' " %
frappe.db.escape(filters.get("finance_book")))
if filters.get("finance_book"):
additional_conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""

View File

@@ -186,12 +186,8 @@ def get_conditions(filters):
if filters.get("project"):
conditions.append("project in %(project)s")
company_finance_book = erpnext.get_default_finance_book(filters.get("company"))
if not filters.get("finance_book") or (filters.get("finance_book") == company_finance_book):
filters['finance_book'] = company_finance_book
if filters.get("finance_book"):
conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
elif filters.get("finance_book"):
conditions.append("ifnull(finance_book, '') = %(finance_book)s")
from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("GL Entry")

View File

@@ -23,6 +23,12 @@ frappe.query_reports["Gross Profit"] = {
"fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_end_date")
},
{
"fieldname":"sales_invoice",
"label": __("Sales Invoice"),
"fieldtype": "Link",
"options": "Sales Invoice"
},
{
"fieldname":"group_by",
"label": __("Group By"),

View File

@@ -302,6 +302,12 @@ class GrossProfitGenerator(object):
sales_person_cols = ""
sales_team_table = ""
if self.filters.get("sales_invoice"):
conditions += " and `tabSales Invoice`.name = %(sales_invoice)s"
if self.filters.get("item_code"):
conditions += " and `tabSales Invoice Item`.item_code = %(item_code)s"
self.si_list = frappe.db.sql("""
select
`tabSales Invoice Item`.parenttype, `tabSales Invoice Item`.parent,

View File

@@ -0,0 +1,34 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Inactive Sales Items"] = {
"filters": [
{
fieldname: "item",
label: __("Item"),
fieldtype: "Link",
options: "Item"
},
{
fieldname: "item_group",
label: __("Item Group"),
fieldtype: "Link",
options: "Item Group"
},
{
fieldname: "based_on",
label: __("Based On"),
fieldtype: "Select",
options: "Sales Order\nSales Invoice",
default: "Sales Order"
},
{
fieldname: "days",
label: __("Days Since Last order"),
fieldtype: "Select",
options: [30, 60, 90],
default: 30
},
]
}

View File

@@ -0,0 +1,30 @@
{
"add_total_row": 0,
"creation": "2019-05-01 12:59:52.018850",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2019-05-01 13:00:26.545278",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Inactive Sales Items",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Sales Invoice",
"report_name": "Inactive Sales Items",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts User"
},
{
"role": "Accounts Manager"
},
{
"role": "Auditor"
}
]
}

View File

@@ -0,0 +1,144 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.utils import getdate, add_days, today, cint
from frappe import _
def execute(filters=None):
columns = get_columns()
data = get_data(filters)
return columns, data
def get_columns():
columns = [
{
"fieldname": "territory",
"fieldtype": "Link",
"label": _("Territory"),
"options": "Territory",
"width": 100
},
{
"fieldname": "item_group",
"fieldtype": "Link",
"label": _("Item Group"),
"options": "Item Group",
"width": 150
},
{
"fieldname": "item_name",
"fieldtype": "Link",
"options": "Item",
"label": "Item",
"width": 150
},
{
"fieldname": "item_name",
"fieldtype": "Data",
"label": _("Item Name"),
"width": 150
},
{
"fieldname": "customer",
"fieldtype": "Link",
"label": _("Customer"),
"options": "Customer",
"width": 100
},
{
"fieldname": "last_order_date",
"fieldtype": "Date",
"label": _("Last Order Date"),
"width": 100
},
{
"fieldname": "qty",
"fieldtype": "Float",
"label": _("Quantity"),
"width": 100
},
{
"fieldname": "days_since_last_order",
"fieldtype": "Int",
"label": _("Days Since Last Order"),
"width": 100
},
]
return columns
def get_data(filters):
data = []
items = get_items(filters)
sales_invoice_data = get_sales_details(filters)
for item in items:
row = {
"item_group": item.item_group,
"item": item.name,
"item_name": item.item_name
}
if sales_invoice_data.get(item.name):
item_obj = sales_invoice_data[item.name]
if item_obj.days_since_last_order > cint(filters['days']):
row.update({
"territory": item_obj.territory,
"customer": item_obj.customer,
"last_order_date": item_obj.last_order_date,
"qty": item_obj.qty,
"days_since_last_order": item_obj.days_since_last_order
})
data.append(row)
return data
def get_sales_details(filters):
data = []
item_details_map = {}
date_field = "s.transaction_date" if filters["based_on"] == "Sales Order" else "s.posting_date"
sales_data = frappe.db.sql("""
select s.territory, s.customer, si.item_group, si.item_name, si.qty, {date_field} as last_order_date,
DATEDIFF(CURDATE(), {date_field}) as days_since_last_order
from `tab{doctype}` s, `tab{doctype} Item` si
where s.name = si.parent and s.docstatus = 1
group by si.name order by days_since_last_order """ #nosec
.format(date_field = date_field, doctype = filters['based_on']), as_dict=1)
for d in sales_data:
item_details_map.setdefault(d.item_name, d)
return item_details_map
def get_items(filters):
filters_dict = {
"disabled": 0,
"is_stock_item": 1
}
if filters.get("item_group"):
filters_dict.update({
"item_group": filters["item_group"]
})
if filters.get("item"):
filters_dict.update({
"name": filters["item"]
})
items = frappe.get_all("Item", fields=["name", "item_group", "item_name"], filters=filters_dict, order_by="name")
return items

View File

@@ -54,8 +54,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom
]
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount] \
if d.stock_uom != d.uom and d.stock_qty != 0 else [d.base_net_rate, d.base_net_amount]
if d.stock_uom != d.uom and d.stock_qty:
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount]
else:
row += [d.base_net_rate, d.base_net_amount]
total_tax = 0
for tax in tax_columns:
@@ -108,13 +110,13 @@ def get_conditions(filters):
conditions += """ and exists(select name from `tabSales Invoice Payment`
where parent=`tabSales Invoice`.name
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
if filters.get("warehouse"):
conditions += """ and exists(select name from `tabSales Invoice Item`
where parent=`tabSales Invoice`.name
and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s)"""
if filters.get("brand"):
conditions += """ and exists(select name from `tabSales Invoice Item`
where parent=`tabSales Invoice`.name
@@ -131,10 +133,10 @@ def get_conditions(filters):
def get_items(filters, additional_query_columns):
conditions = get_conditions(filters)
match_conditions = frappe.build_match_conditions("Sales Invoice")
if match_conditions:
match_conditions = " and {0} ".format(match_conditions)
if additional_query_columns:
additional_query_columns = ', ' + ', '.join(additional_query_columns)

View File

@@ -133,6 +133,13 @@ def get_columns(filters):
"options": filters.get("based_on"),
"width": 300
},
{
"fieldname": "currency",
"label": _("Currency"),
"fieldtype": "Link",
"options": "Currency",
"hidden": 1
},
{
"fieldname": "income",
"label": _("Income"),
@@ -153,13 +160,6 @@ def get_columns(filters):
"fieldtype": "Currency",
"options": "currency",
"width": 120
},
{
"fieldname": "currency",
"label": _("Currency"),
"fieldtype": "Link",
"options": "Currency",
"hidden": 1
}
]
@@ -191,4 +191,4 @@ def set_gl_entries_by_account(company, from_date, to_date, based_on, gl_entries_
for entry in gl_entries:
gl_entries_by_account.setdefault(entry.based_on, []).append(entry)
return gl_entries_by_account
return gl_entries_by_account

View File

@@ -157,7 +157,7 @@ def get_conditions(filters):
conditions += """ and exists(select name from `tabSales Invoice Item`
where parent=`tabSales Invoice`.name
and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s)"""
if filters.get("item_group"):
conditions += """ and exists(select name from `tabSales Invoice Item`
where parent=`tabSales Invoice`.name
@@ -171,7 +171,7 @@ def get_invoices(filters, additional_query_columns):
conditions = get_conditions(filters)
return frappe.db.sql("""
select name, posting_date, debit_to, project, customer,
select name, posting_date, debit_to, project, customer,
customer_name, owner, remarks, territory, tax_id, customer_group,
base_net_total, base_grand_total, base_rounded_total, outstanding_amount {0}
from `tabSales Invoice`

View File

@@ -1,23 +1,27 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2017-12-27 16:15:52.615453",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2017-12-27 16:46:54.422356",
"modified": "2019-04-19 10:50:36.061588",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Share Ledger",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Share Transfer",
"report_name": "Share Ledger",
"report_type": "Script Report",
"roles": [
{
"role": "Administrator"
},
{
"role": "System Manager"
}
]
}

View File

@@ -55,12 +55,15 @@ def get_result(filters):
supplier = supplier_map[d]
tds_doc = tds_docs[supplier.tax_withholding_category]
account = [i.account for i in tds_doc.accounts if i.company == filters.company][0]
account_list = [i.account for i in tds_doc.accounts if i.company == filters.company]
if account_list:
account = account_list[0]
for k in gle_map[d]:
if k.party == supplier_map[d] and k.credit > 0:
total_amount_credited += k.credit
elif k.account == account and k.credit > 0:
elif account_list and k.account == account and k.credit > 0:
tds_deducted = k.credit
total_amount_credited += k.credit

View File

@@ -112,13 +112,15 @@ def convert_to_presentation_currency(gl_entries, currency_info):
if entry.get('debit'):
entry['debit'] = converted_value
else:
if entry.get('credit'):
entry['credit'] = converted_value
elif account_currency == presentation_currency:
if entry.get('debit'):
entry['debit'] = debit_in_account_currency
else:
if entry.get('credit'):
entry['credit'] = credit_in_account_currency
converted_gl_list.append(entry)
@@ -133,3 +135,22 @@ def get_appropriate_company(filters):
company = get_default_company()
return company
@frappe.whitelist()
def get_invoiced_item_gross_margin(sales_invoice=None, item_code=None, company=None):
from erpnext.accounts.report.gross_profit.gross_profit import GrossProfitGenerator
sales_invoice = sales_invoice or frappe.form_dict.get('sales_invoice')
item_code = item_code or frappe.form_dict.get('item_code')
company = company or frappe.get_cached_value("Sales Invoice", sales_invoice, 'company')
filters = {
'sales_invoice': sales_invoice,
'item_code': item_code,
'company': company,
'group_by': 'Invoice'
}
gross_profit_data = GrossProfitGenerator(filters)
return gross_profit_data.grouped_data

View File

@@ -615,7 +615,7 @@ def get_held_invoices(party_type, party):
return held_invoices
def get_outstanding_invoices(party_type, party, account, condition=None, limit=None):
def get_outstanding_invoices(party_type, party, account, condition=None):
outstanding_invoices = []
precision = frappe.get_precision("Sales Invoice", "outstanding_amount") or 2
@@ -628,7 +628,6 @@ def get_outstanding_invoices(party_type, party, account, condition=None, limit=N
invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice'
held_invoices = get_held_invoices(party_type, party)
limit_cond = "limit %s" % limit if limit else ""
invoice_list = frappe.db.sql("""
select
@@ -643,11 +642,10 @@ def get_outstanding_invoices(party_type, party, account, condition=None, limit=N
and (against_voucher = '' or against_voucher is null))
or (voucher_type not in ('Journal Entry', 'Payment Entry')))
group by voucher_type, voucher_no
order by posting_date, name {limit_cond}""".format(
order by posting_date, name""".format(
dr_or_cr=dr_or_cr,
invoice = invoice,
condition=condition or "",
limit_cond = limit_cond
condition=condition or ""
), {
"party_type": party_type,
"party": party,

View File

@@ -31,7 +31,7 @@ frappe.ui.form.on('Asset', {
}
};
});
frm.set_query("cost_center", function() {
return {
"filters": {
@@ -206,12 +206,10 @@ frappe.ui.form.on('Asset', {
erpnext.asset.set_accululated_depreciation(frm);
},
depreciation_method: function(frm) {
frm.events.make_schedules_editable(frm);
},
make_schedules_editable: function(frm) {
var is_editable = frm.doc.depreciation_method==="Manual" ? true : false;
var is_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0
? true : false;
frm.toggle_enable("schedules", is_editable);
frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable);
@@ -296,6 +294,50 @@ frappe.ui.form.on('Asset', {
})
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
},
gross_purchase_amount: function(frm) {
frm.doc.finance_books.forEach(d => {
frm.events.set_depreciation_rate(frm, d);
})
},
set_depreciation_rate: function(frm, row) {
if (row.total_number_of_depreciations && row.frequency_of_depreciation) {
frappe.call({
method: "get_depreciation_rate",
doc: frm.doc,
args: row,
callback: function(r) {
if (r.message) {
frappe.model.set_value(row.doctype, row.name, "rate_of_depreciation", r.message);
}
}
});
}
}
});
frappe.ui.form.on('Asset Finance Book', {
depreciation_method: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
frm.events.make_schedules_editable(frm);
},
expected_value_after_useful_life: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
frequency_of_depreciation: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
total_number_of_depreciations: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe, erpnext
import frappe, erpnext, math, json
from frappe import _
from six import string_types
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
from frappe.model.document import Document
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
@@ -20,6 +21,7 @@ class Asset(AccountsController):
self.validate_item()
self.set_missing_values()
if self.calculate_depreciation:
self.set_depreciation_rate()
self.make_depreciation_schedule()
self.set_accumulated_depreciation()
else:
@@ -89,17 +91,22 @@ class Asset(AccountsController):
if self.is_existing_asset:
return
date = nowdate()
docname = self.purchase_receipt or self.purchase_invoice
if docname:
doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
date = frappe.db.get_value(doctype, docname, 'posting_date')
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(date):
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
frappe.throw(_("Available-for-use Date should be after purchase date"))
def set_depreciation_rate(self):
for d in self.get("finance_books"):
d.rate_of_depreciation = self.get_depreciation_rate(d, on_validate=True)
def make_depreciation_schedule(self):
if self.depreciation_method != 'Manual':
depreciation_method = [d.depreciation_method for d in self.finance_books]
if 'Manual' not in depreciation_method:
self.schedules = []
if not self.get("schedules") and self.available_for_use_date:
@@ -118,7 +125,7 @@ class Asset(AccountsController):
no_of_depreciations * cint(d.frequency_of_depreciation))
total_days = date_diff(end_date, self.available_for_use_date)
rate_per_day = value_after_depreciation / total_days
rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
cint(self.number_of_depreciations_booked)
@@ -254,14 +261,16 @@ class Asset(AccountsController):
return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
percentage_value = 100.0 if row.depreciation_method == 'Written Down Value' else 200.0
if row.depreciation_method in ["Straight Line", "Manual"]:
amt = (flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life) -
flt(self.opening_accumulated_depreciation))
factor = percentage_value / cint(total_number_of_depreciations)
depreciation_amount = flt(depreciable_value * factor / 100, 0)
value_after_depreciation = flt(depreciable_value) - depreciation_amount
if value_after_depreciation < flt(row.expected_value_after_useful_life):
depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
depreciation_amount = amt * row.rate_of_depreciation
else:
depreciation_amount = flt(depreciable_value) * (flt(row.rate_of_depreciation) / 100)
value_after_depreciation = flt(depreciable_value) - depreciation_amount
if value_after_depreciation < flt(row.expected_value_after_useful_life):
depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
return depreciation_amount
@@ -282,8 +291,8 @@ class Asset(AccountsController):
def validate_expected_value_after_useful_life(self):
for row in self.get('finance_books'):
accumulated_depreciation_after_full_schedule = \
max([d.accumulated_depreciation_amount for d in self.get("schedules") if d.finance_book_id == row.idx])
accumulated_depreciation_after_full_schedule = max([d.accumulated_depreciation_amount
for d in self.get("schedules") if cint(d.finance_book_id) == row.idx])
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
flt(accumulated_depreciation_after_full_schedule),
@@ -394,6 +403,35 @@ class Asset(AccountsController):
make_gl_entries(gl_entries)
self.db_set('booked_fixed_asset', 1)
def get_depreciation_rate(self, args, on_validate=False):
if isinstance(args, string_types):
args = json.loads(args)
number_of_depreciations_booked = 0
if self.is_existing_asset:
number_of_depreciations_booked = self.number_of_depreciations_booked
float_precision = cint(frappe.db.get_default("float_precision")) or 2
tot_no_of_depreciation = flt(args.get("total_number_of_depreciations")) - flt(number_of_depreciations_booked)
if args.get("depreciation_method") in ["Straight Line", "Manual"]:
return 1.0 / tot_no_of_depreciation
if args.get("depreciation_method") == 'Double Declining Balance':
return 200.0 / args.get("total_number_of_depreciations")
if args.get("depreciation_method") == "Written Down Value":
if args.get("rate_of_depreciation") and on_validate:
return args.get("rate_of_depreciation")
no_of_years = flt(args.get("total_number_of_depreciations") * flt(args.get("frequency_of_depreciation"))) / 12
value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
# square root of flt(salvage_value) / flt(asset_cost)
depreciation_rate = math.pow(value, 1.0/flt(no_of_years, 2))
return 100 * (1 - flt(depreciation_rate, float_precision))
def update_maintenance_status():
assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1})
@@ -480,7 +518,6 @@ def create_asset_adjustment(asset, asset_category, company):
@frappe.whitelist()
def transfer_asset(args):
import json
args = json.loads(args)
if args.get('serial_no'):
@@ -557,4 +594,4 @@ def make_journal_entry(asset_name):
return je
def is_cwip_accounting_disabled():
return cint(frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting"))
return cint(frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting"))

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