Compare commits

...

140 Commits

Author SHA1 Message Date
Saurabh
f38d6d9c44 Merge branch 'hotfix' 2018-07-09 15:53:50 +05:30
Saurabh
07bb1811af bumped to version 10.1.42 2018-07-09 16:23:50 +06:00
rohitwaghchaure
f07462860b Merge pull request #14846 from shreyashah115/fix-digest
Filter out pending orders based on company
2018-07-09 14:48:13 +05:30
rohitwaghchaure
720b06495c [Fix] Not able to save project (#14848) 2018-07-09 13:57:16 +05:30
Shreya
83ad646af4 Filter out pending orders based on company 2018-07-09 12:14:03 +05:30
rohitwaghchaure
8179bcbabd [Fix] Code cleanup (#14843) 2018-07-09 09:29:40 +05:30
rohitwaghchaure
6be8bea934 Provision to view return entries in Sales Person-wise Transaction Summary (#14830) 2018-07-08 19:25:13 +05:30
Saurabh
0b9129e519 Merge branch 'hotfix' 2018-07-06 13:02:58 +05:30
Saurabh
778e06d0ee bumped to version 10.1.41 2018-07-06 13:32:57 +06:00
rohitwaghchaure
3f5e80ebe3 Allow bulk edit for the sales invoice item (#14826) 2018-07-06 12:39:04 +05:30
rohitwaghchaure
ea943c6fe4 [Fix] Due date validate issue in the POS (#14825) 2018-07-06 12:28:58 +05:30
rohitwaghchaure
82a9fde921 Added compact print option for the material request (#14799) 2018-07-06 10:40:51 +05:30
Saurabh
b35721029b Merge pull request #14820 from saurabh6790/fix_task_status
[fix] Add Overdue status in Project Task
2018-07-06 05:54:47 +05:30
Saurabh
f403031449 [fix] Add Overdue status in Project Task 2018-07-05 19:38:59 +05:30
rohitwaghchaure
25f36489b3 Merge pull request #14805 from rohitwaghchaure/pos_ignore_pricing_issue_online
[Fix] POS Profile ignore pricing rule not working for online pos
2018-07-04 16:26:48 +05:30
Rohit Waghchaure
5005e467a0 [Fix] POS Profile ignore pricing rule not working for online pos 2018-07-04 12:37:38 +05:30
Zarrar
68a148e293 half_day enable/disable check (#14795) 2018-07-03 17:00:38 +05:30
rohitwaghchaure
205eae322b [Fix] BOM replace timeout issue (#14782) 2018-07-03 15:06:38 +05:30
Ameya Shenoy
935f4a474b Prevent creation of more than 500 item variants (#14790) 2018-07-03 10:48:59 +05:30
Shreya Shah
aa62a62bb0 Add VAT related fields after printing settings fields (#14773) 2018-07-03 10:28:20 +05:30
Nabin Hait
104f62090d Add filters for cost center in Budget Variance report 2018-06-29 12:25:03 +05:30
Manas Solanki
3ff7f79cc7 Merge pull request #14740 from manassolanki/fix-20
[minor] fix for the args in the frm.call
2018-06-28 20:47:25 +05:30
Manas Solanki
89e7f8b387 [minor] fix for the args in the frm.call 2018-06-28 20:44:53 +05:30
Shreya Shah
2fbc8509f5 Fix error message (#14716) 2018-06-28 14:14:28 +05:30
rohitwaghchaure
67d87e29e3 [Fix] Wrong rate calculation in Itemwise sales register report for multi uom (#14690) 2018-06-27 11:22:03 +05:30
Deepak kumar
55cf6c5f7e Membership (#14688)
* Correct the label and field name

* Update membership.json
2018-06-27 09:17:33 +05:30
rohitwaghchaure
f3cf15fa0d [Fix] While saving project getting timeout error (#14672) 2018-06-26 17:06:00 +05:30
Prateeksha Singh
d53d2ed791 Merge pull request #14679 from pratu16x7/hotfix
[fix] yet another python attribute fetch
2018-06-26 12:20:26 +05:30
Prateeksha Singh
34aeefc0a1 [fix] yet another python attribute fetch 2018-06-26 12:18:29 +05:30
Shreya Shah
d8031d1a53 Clear child table before appending (#14648) 2018-06-25 10:34:55 +05:30
Ameya Shenoy
1098755d26 Merge branch 'hotfix' 2018-06-22 05:10:27 +00:00
Ameya Shenoy
774f676a25 bumped to version 10.1.40 2018-06-22 05:10:27 +00:00
Ameya Shenoy
1629393618 Merge pull request #14628 from Zlash65/fix-pe
Expense Claim - Payment Entry related fix
2018-06-21 18:49:50 +05:30
Zlash65
4cf46edabc expense_claim related fix in payment entry
outstanding amount calculation fix, manual entry of expense trigger calculation of allocation added
2018-06-21 15:18:13 +05:30
Saurabh
e6498996fa Merge branch 'hotfix' 2018-06-20 15:21:40 +05:30
Saurabh
98b7bb5679 bumped to version 10.1.39 2018-06-20 15:51:40 +06:00
Zarrar
99017b173d naming for asset maintenance task should be task name (#14607) 2018-06-20 14:53:13 +05:30
Zarrar
42f2d1a7a8 fix incase no customer fetched (#14596) 2018-06-20 10:50:11 +05:30
Nabin Hait
a125a6199c Allowed paid amount against debit/credit note 2018-06-19 12:07:02 +05:30
Zarrar
ba1cdc6c57 fix opening invoice related authorization control - item=None (#14567) 2018-06-19 10:45:47 +05:30
Nabin Hait
875c941f3d fixes in setting itemised tax breakup 2018-06-18 17:41:27 +05:30
Nabin Hait
8eeb5694ba Fixed qty in item-wise sales history report 2018-06-18 17:41:27 +05:30
Nabin Hait
0bef91c241 minor fix in item type validation 2018-06-18 17:41:27 +05:30
Nabin Hait
ae02209b6a Removed autoname of child table 2018-06-18 17:41:27 +05:30
Zarrar
e0adb6bbd6 cost_center overridden by company's default fix in SI (#14560) 2018-06-18 15:49:12 +05:30
Manas Solanki
efa191c72e [minor fix] change the unicode/str to the datetime obejct (#14534) 2018-06-15 18:04:12 +05:30
Ameya Shenoy
40fe3a2cdf Merge branch 'hotfix' 2018-06-15 09:29:56 +00:00
Ameya Shenoy
ed77429496 bumped to version 10.1.38 2018-06-15 09:29:56 +00:00
Manas Solanki
c7afbea708 Update bom.py (#14524) 2018-06-14 17:30:26 +05:30
Shreya Shah
dd8fba6783 Do not check for batch on cancellation (#14506) 2018-06-14 11:49:45 +05:30
Saurabh
8e74df09a4 [fix] On deletion of salary slip decrease the series count (#14508) 2018-06-14 11:47:21 +05:30
Shreya Shah
3d73a6f7f2 Fetch details from Journal Entry in Accounts Payable report (#14495)
* Fetch bill_no, bill_date from Journal Entry

* Fix as per suggestion

* Fetch details only if bill_no exists
2018-06-13 16:33:06 +05:30
FinByz Tech Pvt. Ltd
46c8ccc6a8 Fix conflict for taxable value having same item in GSTR-1 Report (#14492)
* Update gstr_1.py

Merge conflict for taxable value having same item

* Update gstr_1.py

* Minor Fix

* Update gstr_1.py
2018-06-13 15:34:17 +05:30
Prateeksha Singh
5d0674a23a Merge pull request #14452 from pratu16x7/hotfix
[hotfix][enhance][tax-breakup] store itemized tax by item_name when possible
2018-06-12 17:42:01 +05:30
Prateeksha Singh
a831868d02 Merge pull request #14460 from chdecultot/hotfix_customer
Customer timeline data hotfix
2018-06-11 16:31:17 +05:30
Charles-Henri Decultot
943dc09f29 Customer timeline data hotfix 2018-06-11 09:42:05 +00:00
Prateeksha Singh
ea7533fa75 [tax-breakup] store itemized tax by item_name when can 2018-06-11 13:31:33 +05:30
Shreya Shah
b9399d8781 Cancel attendance if leave application is cancelled (#14372)
* Cancel attendance if leave application is cancelled

* Fix as per review
2018-06-08 11:24:08 +05:30
Zarrar
8cd0f67b25 query fix if name contains apostrophe (#14370) 2018-06-07 16:48:31 +05:30
Zarrar
32a118d68c fix precision in stock entry (#14366) 2018-06-06 15:06:52 +05:30
Ameya Shenoy
a02d5d1104 Merge branch 'hotfix' 2018-06-06 05:41:37 +00:00
Ameya Shenoy
36cd433999 bumped to version 10.1.37 2018-06-06 05:41:37 +00:00
Shreya Shah
6ff3a094e2 Fix currency exchange tests (#14356) 2018-06-05 14:16:10 +05:30
rohitwaghchaure
50d8c4a10f [Fix] Not able to save purchase invoice, due to invalid condition (#14355) 2018-06-05 13:08:10 +05:30
Zarrar
7c088ff623 dont validate items if item_code not found (#14344)
item_code field is not set when created using invoice creation tool
2018-06-05 10:32:09 +05:30
rohitwaghchaure
7cf01e7c75 Replaced fixer api with exchangeratesapi (#14347) 2018-06-05 10:30:20 +05:30
Zarrar
fc03a0463c [Fix] Validate items for saleable, purchaseable or subcontractable in transactions (#14316)
* validate items to see if they are saleable

* check if items are subcontractable or saleable

* improvise name,error message and code
Validate type function validates item if they are of proper type for that transaction and throws descriptive error.
2018-06-04 12:52:52 +05:30
rohitwaghchaure
5ecc26bf15 [Fix] get_shipping_address() takes at least 1 argument (0 given) (#14328) 2018-06-04 11:00:24 +05:30
rohitwaghchaure
c1cf495a93 [Fix] Special character issue (#14322) 2018-06-03 16:00:31 +05:30
rohitwaghchaure
ce642d73cb [Fix] Special character issue while upadting customer group in customer (#14312) 2018-06-01 15:11:21 +05:30
rohitwaghchaure
2fa057e4ad [Fix] Expense claim showing status as Unpaid even if Total Advance Amount and Total Sanctioned Amount is same (#14311) 2018-06-01 15:10:55 +05:30
Zarrar
7e0e85912b item_name not fetched in packing slip (#14310) 2018-06-01 15:10:33 +05:30
Saurabh
defecd3785 Merge branch 'hotfix' 2018-05-31 17:24:53 +05:30
Saurabh
fccf7f2a68 bumped to version 10.1.36 2018-05-31 17:54:53 +06:00
Ameya Shenoy
cce7189b4f Added issue and PR Templates (#14300) 2018-05-31 08:42:52 +05:30
rohitwaghchaure
31a96d2a3f [Fix] System not fetching default warehoue defined in pos profile for packing materials of product bundle item (#14287) 2018-05-30 18:13:47 +05:30
Zarrar
39c0add5a2 query fix sales-person-target-variance-item-group-wise (#14271) 2018-05-30 11:56:58 +05:30
Zarrar
58200182b4 update timeline data form Activity Log (#14276)
Documents updated are stored in Activity Log rather than Communication
2018-05-30 11:56:23 +05:30
Ameya Shenoy
c2c73ae96a [minor] removed vim swap file (#14277) 2018-05-30 11:55:38 +05:30
Shreya Shah
ae95a8aa15 Update status in Purchase Receipt (#14257)
* Update status on submission if per_billed = 100

* Add patch to update existing records
2018-05-28 18:24:28 +05:30
Zarrar
b9f54ca946 [Enhance] Group same items during printing Delivery Note, Invoices, etc (#14250)
* add doctypes allowed to group items, average the rate

* add check field to group items during print

* call common before_print in delivery note

* fix precision issue while calculating average
2018-05-28 17:41:09 +05:30
rohitwaghchaure
a8c6ec27c0 Merge pull request #14252 from rohitwaghchaure/leaderboard_translation_issue
[Fix] Translation issue in leaderboard
2018-05-28 15:51:00 +05:30
Saurabh
3c1b153cdb Merge pull request #14111 from netchampfaris/stock-ledger-report-hotfix
[fix] Stock Ledger report item filter
2018-05-28 15:23:21 +05:30
Rohit Waghchaure
06f91e2dc1 [Fix] Translation issue in leaderboard 2018-05-28 14:43:17 +05:30
Shreya Shah
13f39eb821 Display rate on the basis of stock UOM (#14246) 2018-05-28 11:50:28 +05:30
rohitwaghchaure
a8fb2db001 [Fix] If two po consolidated in one purchase invoice, Total Net Weight not get summed (#14230) 2018-05-26 09:23:02 +05:30
Ranjith Kurungadam
27cf190269 healthcare fix - str encode to utf-8 (#14213) 2018-05-24 17:15:22 +05:30
Ameya Shenoy
7ad556cd4c Merge branch 'hotfix' 2018-05-24 08:45:12 +00:00
Ameya Shenoy
475729cefe bumped to version 10.1.35 2018-05-24 08:45:12 +00:00
Manas Solanki
f7713ebfa7 [optimize] introduce two filter in the report in order to handle large item master data (#14193) 2018-05-23 19:43:04 +05:30
Ameya Shenoy
92640cc899 Merge branch 'hotfix' 2018-05-22 09:06:38 +00:00
Ameya Shenoy
826f020862 bumped to version 10.1.34 2018-05-22 09:06:38 +00:00
Zarrar
93a186aa11 fetch customer_gstin or billing_address_gstin optionally (#14075) 2018-05-22 09:16:42 +05:30
rohitwaghchaure
742d3e5549 [Fix] General ledger default_currency issue for member party type (#14172) 2018-05-22 09:10:01 +05:30
Prateeksha Singh
bcbe32ce7c Merge pull request #14169 from pratu16x7/hotfix
[hotfix][charts] update, without new build system
2018-05-21 18:31:39 +05:30
Prateeksha Singh
b434f2687e [charts] update, without new build system 2018-05-21 18:04:50 +05:30
Manas Solanki
a752eca82c Merge pull request #14163 from manassolanki/fix-20
[fix] don't update the modified of item price while updating item
2018-05-21 16:37:01 +05:30
rohitwaghchaure
37da7d7d05 Merge pull request #14162 from rohitwaghchaure/permissions_issue_leave_application
[Fix] Permission issue while saving leave application
2018-05-21 16:02:58 +05:30
Manas Solanki
b5d9b38dee don't update the modified of the item price 2018-05-21 15:40:51 +05:30
Rohit Waghchaure
11e2a9ac90 [Fix] Permission issue while saving leave application 2018-05-21 15:39:38 +05:30
rohitwaghchaure
1275ea5123 Merge pull request #14154 from rohitwaghchaure/set_default_leave_approver
Set leave approver in the leave application
2018-05-21 11:58:41 +05:30
Rohit Waghchaure
812224e56e Set leave approver in the leave application 2018-05-20 21:21:33 +05:30
Gaurav Naik
8f17281011 Initialized dynamic link on Warehouse (#14135)
* Initialized dynamic link for Warehouse

* Codacy Fixes
2018-05-20 10:39:14 +05:30
Prateeksha Singh
8233cb11ed Merge pull request #14124 from pratu16x7/hotfix
[item-query] change order of description terms, name first
2018-05-17 17:32:54 +05:30
Prateeksha Singh
984a7a7e61 [item-query] change order of description terms, name first 2018-05-17 17:29:36 +05:30
rohitwaghchaure
b5cc946771 Merge pull request #14122 from shreyashah115/fixes
Fix in marking attendance from Leave Application
2018-05-17 17:16:57 +05:30
Shreya
65dd1f6b4c Mark attendance only if to_date <= nowdate in Leave Application 2018-05-17 17:13:56 +05:30
Prateeksha Singh
7c9a6eba3f Merge pull request #14116 from rohitwaghchaure/project_heatmap_issue
[Fix] Heatmap issue in the project
2018-05-17 15:42:58 +05:30
Rohit Waghchaure
f2ccde0454 [Fix] Heatmap issue in the project 2018-05-17 15:40:32 +05:30
Faris Ansari
9e4889d756 [fix] Stock Ledger report item filter
- breaks when Item Code contains % symbol
2018-05-17 12:18:28 +05:30
Manas Solanki
b81ece9ddf Merge pull request #14076 from chdecultot/pricing_rule
Missing parentheses in price list rate determination
2018-05-16 14:55:32 +05:30
Charles-Henri Decultot
2f822476dd Removal of debugging print 2018-05-16 08:40:16 +00:00
Charles-Henri Decultot
dcfe19d868 Missing parentheses in price list rate determination 2018-05-16 08:34:41 +00:00
Shreya Shah
4f40b2dca5 [Fix] Sales Person Reports (#13987)
* Fix Sales Person Reports
- Show quantity and amounts based on the delivered quantities if the Sales Order has been closed and all quantities weren't considered for further transactions.

* Fix codacy

* Modify as per the review comment
2018-05-16 11:22:59 +05:30
Manas Solanki
1b48fde986 Make the communication from the issue webform (#14015) 2018-05-16 10:47:02 +05:30
Rushabh Mehta
33db332eca Revert "apply sorting for make multiple variant attributes (#14060)" (#14065)
This reverts commit 257e18b640.
2018-05-16 10:43:58 +05:30
lasalesi
257e18b640 apply sorting for make multiple variant attributes (#14060) 2018-05-16 10:42:42 +05:30
Saurabh
292f46fec0 Merge branch 'hotfix' 2018-05-15 14:59:36 +05:30
Saurabh
78a0be666f bumped to version 10.1.33 2018-05-15 15:29:36 +06:00
Saurabh
ce4f520908 Merge pull request #14042 from saurabh6790/patch_fix_15_05
[fix] if UOM and Warehouse link is invalid then set blank values
2018-05-15 14:58:12 +05:30
Saurabh
29160441bb [fix] if UOM and Warehouse link is invalid then set blank values 2018-05-15 14:56:18 +05:30
Saurabh
1b18bba04a Merge branch 'hotfix' 2018-05-15 12:58:15 +05:30
Saurabh
f8c26bb778 bumped to version 10.1.32 2018-05-15 13:28:15 +06:00
Saurabh
ccd0617e19 Merge pull request #14017 from netchampfaris/apply-price-list-hotfix
[fix] apply price list
2018-05-15 11:25:08 +05:30
Saurabh
bf10d0f98b Merge pull request #14031 from shreyashah115/leave-balance
[Bug] Clear leave balance in Leave Application
2018-05-15 11:11:49 +05:30
Shreya
dbb67fb4fd Clear leave balance on changing leave type 2018-05-14 23:02:09 +05:30
Faris Ansari
404f39d373 [fix] apply price list
in_apply_price_list flag remains true if server exception occurs
2018-05-14 15:46:45 +05:30
Shreya Shah
bbee9b6cc4 [Enhancement] Monthly Attendance Report (#13970)
* Update Attendance on Approval of Leave

* Separate out leaves on the basis of its type

* Remove commented code

* Make attendance records if not found

* Fix Codacy

* Replace bad code in attendance.py
2018-05-14 14:30:58 +05:30
Faris Ansari
69b0535e10 [fix] Incorrect currency conversion in Itemised Tax Breakup (#14006) 2018-05-14 14:19:31 +05:30
rohitwaghchaure
7f63c1ad7c Merge pull request #14014 from rohitwaghchaure/hotfix_production_order_name_issue
[Fix] 'ProductionOrder' object has no attribute 'set_work_order_operations'
2018-05-14 14:04:09 +05:30
Rohit Waghchaure
ebe1ebead2 [Fix] 'ProductionOrder' object has no attribute 'set_work_order_operations' 2018-05-14 13:21:45 +05:30
Faris Ansari
f2b3307136 Remove escaped customer string (#13986)
- no need to escape strings that are passed to the values parameter of the sql method
- this query was failing for inputs like "D'Arby" which have quotes
2018-05-11 21:07:27 +05:30
Nabin Hait
9d215c2d9b Set operations on production order while making from Material Request 2018-05-09 18:32:54 +05:30
Vishal Dhayagude
3cf0d51e65 [fix] Compounding error in task weight (#13958)
* [fix] Compounding error in task weight

* [minor] minor changes

* [fix] Requested Changes added
2018-05-09 10:42:39 +05:30
Nabin Hait
9fc5ddc26e Merge branch 'hotfix' 2018-05-08 16:31:38 +05:30
Nabin Hait
0ff31f0ebf bumped to version 10.1.31 2018-05-08 17:01:38 +06:00
Saurabh
40349f4b00 [fix] add stock entry link on Material Request Dashboard (#13950) 2018-05-08 15:23:51 +05:30
Saurabh
b36517158b [fix] cheque print template coordinates (#13959) 2018-05-08 15:23:29 +05:30
Manas Solanki
3b9720f0be Merge pull request #13952 from manassolanki/minor-report-fix
[minor] fix for the student report card
2018-05-08 12:43:43 +05:30
Manas Solanki
cf26b2ca1c [minor] fix for the student report card 2018-05-08 12:39:02 +05:30
98 changed files with 1143 additions and 291 deletions

68
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,68 @@
---
name: Bug report
about: Create a report to help us improve
---
Issue: Bug report
Our project, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
**Do the checklist before filing an issue:**
- [ ] Have a usage question? Ask your question on [Discuss Forum](https://discuss.erpnext.com). We use [Discuss Forum](https://discuss.erpnext.com) for usage question and GitHub for bugs.
- [ ] Can you replicate the issue?
- [ ] Is this something you can debug and fix? Send a pull request! Bug fixes and documentation fixes are welcome
**Describe the bug** :chart_with_downwards_trend:
A clear and concise description of what the bug is.
**To Reproduce** :page_with_curl:
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior** :chart_with_upwards_trend:
A clear and concise description of what you expected to happen.
**Screenshots** :crystal_ball:
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):** :cyclone:
- OS:
- [ ] Linux
- [ ] macOS
- [ ] Windows
- [ ] Others? Please mention:
- Browser:
- [ ] Safari
- [ ] Chrome
- [ ] Firefox
- [ ] Other? Please mention:
**Smartphone (please complete the following information):** :iphone: :computer:
- Device:
- [ ] iPhone
- [ ] Android
- Browser:
- [ ] Safari
- [ ] Chrome
- [ ] Firefox
- [ ] Other? Please mention:
**Version Information**
- Which branch are you on?
- [ ] `master` :star2:
- [ ] `develop` :fire:
- Frappe Version:
- ERPNext Version:
**Additional context** :page_facing_up:
Add any other context about the problem here.
**Possible Solution** :bookmark_tabs:
Any idea what might be causing the issue. Or if you have a proposed solution to the problem,
**Please don't be intimidated by the long list of options you've fill. Try to fill out as much as you can. Remember, the more the information the easier it is for us to replicate and fix the issue** :grin:

View File

@@ -0,0 +1,21 @@
---
name: Feature request
about: Suggest an idea for this project
---
Issue: Feature Request
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

28
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,28 @@
Pull-Request
- [ ] Have you followed the guidelines in our Contributing document?
- [ ] Have you checked to ensure there aren't other open [Pull Requests](../pulls) for the same update/change?
- [ ] Have you lint your code locally prior to submission?
- [ ] Have you successfully run tests with your changes locally?
- [ ] Does your commit message have an explanation for your changes and why you'd like us to include them?
- [ ] Docs have been added / updated
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Did you modify the existing test cases? If yes, why?
---
What type of a PR is this?
- [ ] Changes to Existing Features
- [ ] New Feature Submissions
- [ ] Bug Fix
- [ ] Breaking Change
---
- Motivation and Context (What existing problem does the pull request solve):
- Related Issue:
- Screenshots (if applicable, remember, a picture tells a thousand words):
**Please don't be intimidated by the long list of options you've fill. Try to fill out as much as you can. Remember, the more the information the easier it is for us to test and get your pull request merged** :grin:

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@ latest_updates.json
*.egg-info
dist/
erpnext/docs/current
*.swp

BIN
.swp

Binary file not shown.

View File

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

View File

@@ -27,10 +27,20 @@ def create_or_update_cheque_print_format(template_name):
doc = frappe.get_doc("Cheque Print Template", template_name)
cheque_print.html = """
<style>
.print-format {
padding: 0px;
}
@media screen {
.print-format {
padding: 0in;
}
}
</style>
<div style="position: relative; top:%(starting_position_from_top_edge)scm">
<div style="width:%(cheque_width)scm;height:%(cheque_height)scm;">
<span style="top:%(acc_pay_dist_from_top_edge)scm; left:%(acc_pay_dist_from_left_edge)scm;
border-bottom: solid 1px;border-top:solid 1px; position: absolute;">
border-bottom: solid 1px;border-top:solid 1px; width:2cm;text-align: center; position: absolute;">
%(message_to_show)s
</span>
<span style="top:%(date_dist_from_top_edge)scm; left:%(date_dist_from_left_edge)scm;
@@ -38,11 +48,11 @@ def create_or_update_cheque_print_format(template_name):
{{ frappe.utils.formatdate(doc.reference_date) or '' }}
</span>
<span style="top:%(acc_no_dist_from_top_edge)scm;left:%(acc_no_dist_from_left_edge)scm;
position: absolute;">
position: absolute; min-width: 6cm;">
{{ doc.account_no or '' }}
</span>
<span style="top:%(payer_name_from_top_edge)scm;left: %(payer_name_from_left_edge)scm;
position: absolute;">
position: absolute; min-width: 6cm;">
{{doc.party_name}}
</span>
<span style="top:%(amt_in_words_from_top_edge)scm; left:%(amt_in_words_from_left_edge)scm;
@@ -51,11 +61,11 @@ def create_or_update_cheque_print_format(template_name):
{{frappe.utils.money_in_words(doc.base_paid_amount or doc.base_received_amount)}}
</span>
<span style="top:%(amt_in_figures_from_top_edge)scm;left: %(amt_in_figures_from_left_edge)scm;
position: absolute;">
position: absolute; min-width: 4cm;">
{{doc.get_formatted("base_paid_amount") or doc.get_formatted("base_received_amount")}}
</span>
<span style="top:%(signatory_from_top_edge)scm;left: %(signatory_from_left_edge)scm;
position: absolute;">
position: absolute; min-width: 6cm;">
{{doc.company}}
</span>
</div>

View File

@@ -588,6 +588,10 @@ frappe.ui.form.on('Payment Entry', {
allocate_party_amount_against_ref_docs: function(frm, paid_amount) {
var total_positive_outstanding_including_order = 0;
var total_negative_outstanding = 0;
var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [],
function(d) { return flt(d.amount) }));
paid_amount -= total_deductions;
$.each(frm.doc.references || [], function(i, row) {
if(flt(row.outstanding_amount) > 0)
@@ -815,23 +819,30 @@ frappe.ui.form.on('Payment Entry Reference', {
reference_name: function(frm, cdt, cdn) {
var row = locals[cdt][cdn];
return frappe.call({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_reference_details",
args: {
reference_doctype: row.reference_doctype,
reference_name: row.reference_name,
party_account_currency: frm.doc.payment_type=="Receive" ?
frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency
},
callback: function(r, rt) {
if(r.message) {
$.each(r.message, function(field, value) {
frappe.model.set_value(cdt, cdn, field, value);
})
frm.refresh_fields();
if (row.reference_name && row.reference_doctype) {
return frappe.call({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_reference_details",
args: {
reference_doctype: row.reference_doctype,
reference_name: row.reference_name,
party_account_currency: frm.doc.payment_type=="Receive" ?
frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency
},
callback: function(r, rt) {
if(r.message) {
$.each(r.message, function(field, value) {
frappe.model.set_value(cdt, cdn, field, value);
})
let allocated_amount = frm.doc.unallocated_amount > row.outstanding_amount ?
row.outstanding_amount : frm.doc.unallocated_amount;
frappe.model.set_value(cdt, cdn, 'allocated_amount', allocated_amount);
frm.refresh_fields();
}
}
}
})
})
}
},
allocated_amount: function(frm) {

View File

@@ -337,14 +337,15 @@ class PaymentEntry(AccountsController):
total_negative_outstanding = sum([abs(flt(d.outstanding_amount))
for d in self.get("references") if flt(d.outstanding_amount) < 0])
party_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
paid_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
additional_charges = sum([flt(d.amount) for d in self.deductions])
if not total_negative_outstanding:
frappe.throw(_("Cannot {0} {1} {2} without any negative outstanding invoice")
.format(self.payment_type, ("to" if self.party_type=="Customer" else "from"),
self.party_type), InvalidPaymentEntry)
elif party_amount > total_negative_outstanding:
elif paid_amount - additional_charges > total_negative_outstanding:
frappe.throw(_("Paid Amount cannot be greater than total negative outstanding amount {0}")
.format(total_negative_outstanding), InvalidPaymentEntry)
@@ -724,8 +725,11 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
exchange_rate = ref_doc.get("conversion_rate") or \
get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
if reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim"):
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
outstanding_amount = ref_doc.get("outstanding_amount")
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"))
elif reference_doctype == "Employee Advance":
outstanding_amount = ref_doc.advance_amount - flt(ref_doc.paid_amount)
else:

View File

@@ -111,8 +111,8 @@ def apply_pricing_rule(args):
item_list = args.get("items")
args.pop("items")
set_serial_nos_based_on_fifo = frappe.db.get_single_value("Stock Settings",
set_serial_nos_based_on_fifo = frappe.db.get_single_value("Stock Settings",
"automatically_set_serial_nos_based_on_fifo")
for item in item_list:
@@ -122,7 +122,7 @@ def apply_pricing_rule(args):
if set_serial_nos_based_on_fifo and not args.get('is_return'):
out.append(get_serial_no_for_item(args_copy))
return out
def get_serial_no_for_item(args):
from erpnext.stock.get_item_details import get_serial_no
@@ -143,7 +143,7 @@ def get_pricing_rule_for_item(args):
"name": args.name,
"pricing_rule": None
})
if args.ignore_pricing_rule or not args.item_code:
if frappe.db.exists(args.doctype, args.name) and args.get("pricing_rule"):
item_details = remove_pricing_rule_for_item(args.get("pricing_rule"), item_details)
@@ -180,7 +180,7 @@ def get_pricing_rule_for_item(args):
item_details.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
if pricing_rule.price_or_discount == "Price":
item_details.update({
"price_list_rate": (pricing_rule.price/flt(args.conversion_rate)) * args.conversion_factor or 1.0 \
"price_list_rate": (pricing_rule.price/flt(args.conversion_rate)) * (args.conversion_factor or 1.0) \
if args.conversion_rate else 0.0,
"discount_percentage": 0.0
})
@@ -192,7 +192,7 @@ def get_pricing_rule_for_item(args):
return item_details
def remove_pricing_rule_for_item(pricing_rule, item_details):
pricing_rule = frappe.db.get_value('Pricing Rule', pricing_rule,
pricing_rule = frappe.db.get_value('Pricing Rule', pricing_rule,
['price_or_discount', 'margin_type'], as_dict=1)
if pricing_rule and pricing_rule.price_or_discount == 'Discount Percentage':
item_details.discount_percentage = 0.0
@@ -209,14 +209,14 @@ def remove_pricing_rule_for_item(pricing_rule, item_details):
def remove_pricing_rules(item_list):
if isinstance(item_list, basestring):
item_list = json.loads(item_list)
out = []
out = []
for item in item_list:
item = frappe._dict(item)
out.append(remove_pricing_rule_for_item(item.get("pricing_rule"), item))
return out
def get_pricing_rules(args):
def _get_tree_conditions(parenttype, allow_blank=True):
field = frappe.scrub(parenttype)

View File

@@ -1239,7 +1239,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3410,6 +3410,65 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "group_same_items",
"fieldtype": "Check",
"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": "Group same items",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_112",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "select_print_heading",
"fieldtype": "Link",
"hidden": 0,
@@ -3914,7 +3973,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-12-20 17:49:51.230092",
"modified": "2018-07-06 02:38:40.310899",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -1459,7 +1459,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3742,12 +3742,12 @@
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "language",
"fieldtype": "Data",
"fieldname": "group_same_items",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -3755,14 +3755,14 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Print Language",
"label": "Group same items",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -3831,6 +3831,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "language",
"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": "Print Language",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -4683,7 +4713,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2018-03-16 15:19:54.711885",
"modified": "2018-07-06 12:09:02.039783",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -318,6 +318,7 @@ class SalesInvoice(SellingController):
if not for_validate and not self.customer:
self.customer = pos.customer
self.ignore_pricing_rule = pos.ignore_pricing_rule
if pos.get('account_for_change_amount'):
self.account_for_change_amount = pos.get('account_for_change_amount')

View File

@@ -404,10 +404,21 @@ def get_timeline_data(doctype, name):
from frappe.desk.form.load import get_communication_data
out = {}
fields = 'date(creation), count(name)'
after = add_years(None, -1).strftime('%Y-%m-%d')
group_by='group by date(creation)'
data = get_communication_data(doctype, name,
fields = 'date(creation), count(name)',
after = add_years(None, -1).strftime('%Y-%m-%d'),
group_by='group by date(creation)', as_dict=False)
fields=fields, after=after, group_by=group_by, as_dict=False)
# fetch and append data from Activity Log
data += frappe.db.sql("""select {fields}
from `tabActivity Log`
where reference_doctype="{doctype}" and reference_name="{name}"
and status!='Success' and creation > {after}
{group_by} order by creation desc
""".format(doctype=frappe.db.escape(doctype), name=frappe.db.escape(name), fields=fields,
group_by=group_by, after=after), as_dict=False)
timeline_items = dict(data)

View File

@@ -286,7 +286,10 @@ class ReceivablePayableReport(object):
if party_type == "Supplier":
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
from `tabPurchase Invoice` where docstatus = 1
union
select name, due_date, bill_no, bill_date from `tabJournal Entry`
where docstatus = 1 and bill_no is not NULL""", as_dict=1):
voucher_details.setdefault(pi.name, pi)
return voucher_details

View File

@@ -39,6 +39,12 @@ frappe.query_reports["Budget Variance Report"] = {
options: ["Cost Center", "Project"],
default: "Cost Center",
reqd: 1
}
},
{
fieldname: "cost_center",
label: __("Cost Center"),
fieldtype: "Link",
options: "Cost Center"
},
]
}

View File

@@ -10,9 +10,13 @@ from erpnext.controllers.trends import get_period_date_ranges, get_period_month_
def execute(filters=None):
if not filters: filters = {}
validate_filters(filters)
columns = get_columns(filters)
cost_centers = get_cost_centers(filters)
if filters.get("cost_center"):
cost_centers = [filters.get("cost_center")]
else:
cost_centers = get_cost_centers(filters)
period_month_ranges = get_period_month_ranges(filters["period"], filters["fiscal_year"])
cam_map = get_cost_center_account_month_map(filters)
@@ -39,6 +43,10 @@ def execute(filters=None):
return columns, data
def validate_filters(filters):
if filters.get("budget_against")=="Project" and filters.get("cost_center"):
frappe.throw(_("Filter based on Cost Center is only applicable if Budget Against is selected as Cost Center"))
def get_columns(filters):
columns = [_(filters.get("budget_against")) + ":Link/%s:120"%(filters.get("budget_against")), _("Account") + ":Link/Account:120"]
@@ -66,12 +74,16 @@ def get_cost_centers(filters):
#Get cost center & target details
def get_cost_center_target_details(filters):
cond = ""
if filters.get("cost_center"):
cond += " and b.cost_center='%s'" % frappe.db.escape(filters.get("cost_center"))
return frappe.db.sql("""
select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount
from `tabBudget` b, `tabBudget Account` ba
where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year=%s
and b.budget_against = %s and b.company=%s
""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower()),
and b.budget_against = %s and b.company=%s {cond}
""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
(filters.fiscal_year, filters.budget_against, filters.company), as_dict=True)
#Get target distribution details of accounts of cost center

View File

@@ -71,8 +71,8 @@ def set_account_currency(filters):
if gle_currency:
account_currency = gle_currency
else:
account_currency = None if filters.party_type in ["Employee", "Student", "Shareholder"] else \
frappe.db.get_value(filters.party_type, filters.party, "default_currency")
account_currency = (None if filters.party_type in ["Employee", "Student", "Shareholder", "Member"] else
frappe.db.get_value(filters.party_type, filters.party, "default_currency"))
filters["account_currency"] = account_currency or filters.company_currency

View File

@@ -49,7 +49,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
row += [
d.credit_to, d.mode_of_payment, d.project, d.company, d.purchase_order,
purchase_receipt, expense_account, d.stock_qty, d.stock_uom, d.base_net_rate, d.base_net_amount
purchase_receipt, expense_account, d.stock_qty, d.stock_uom, d.base_net_amount / d.stock_qty, d.base_net_amount
]
total_tax = 0
@@ -120,8 +120,7 @@ def get_items(filters, additional_query_columns):
`tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`,
`tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`,
`tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`,
`tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_rate`,
`tabPurchase Invoice Item`.`base_net_amount`,
`tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_amount`,
`tabPurchase Invoice`.supplier_name, `tabPurchase Invoice`.mode_of_payment {0}
from `tabPurchase Invoice`, `tabPurchase Invoice Item`
where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and

View File

@@ -53,7 +53,7 @@ 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.stock_qty, d.base_net_amount] \
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount] \
if d.stock_uom != d.uom else [d.base_net_rate, d.base_net_amount]
total_tax = 0
@@ -133,7 +133,7 @@ def get_items(filters, additional_query_columns):
`tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate,
`tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name,
`tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom {0}
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
from `tabSales Invoice`, `tabSales Invoice Item`
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
and `tabSales Invoice`.docstatus = 1 %s %s

View File

@@ -3,7 +3,7 @@
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:maintenance_task",
"autoname": "",
"beta": 0,
"creation": "2017-10-20 07:10:55.903571",
"custom": 0,
@@ -42,7 +42,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 1
"unique": 0
},
{
"allow_bulk_edit": 0,
@@ -625,7 +625,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-11-28 12:22:34.151430",
"modified": "2018-06-18 16:12:04.330021",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance Task",

View File

@@ -7,4 +7,5 @@ import frappe
from frappe.model.document import Document
class AssetMaintenanceTask(Document):
pass
def autoname(self):
self.name = self.maintenance_task

View File

@@ -1207,7 +1207,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3355,7 +3355,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-02-17 11:00:05.037716",
"modified": "2018-07-06 11:00:05.037716",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",

View File

@@ -781,7 +781,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2177,6 +2177,65 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "group_same_items",
"fieldtype": "Check",
"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": "Group same items",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_72",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "letter_head",
"fieldtype": "Link",
"hidden": 0,
@@ -2490,7 +2549,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-11-29 14:07:56.698355",
"modified": "2018-07-06 02:45:48.616334",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation",

View File

@@ -82,7 +82,8 @@ class AccountsController(TransactionBase):
self.validate_non_invoice_documents_schedule()
def before_print(self):
if self.doctype in ['Purchase Order', 'Sales Order']:
if self.doctype in ['Purchase Order', 'Sales Order', 'Sales Invoice', 'Purchase Invoice',
'Supplier Quotation', 'Purchase Receipt', 'Delivery Note', 'Quotation']:
if self.get("group_same_items"):
self.group_similar_items()
@@ -130,6 +131,8 @@ class AccountsController(TransactionBase):
self.meta.get_label(date_field), self)
def validate_due_date(self):
if self.get('is_pos'): return
from erpnext.accounts.party import validate_due_date
if self.doctype == "Sales Invoice":
if not self.due_date:
@@ -663,6 +666,7 @@ class AccountsController(TransactionBase):
if item.item_code in group_item_qty:
item.qty = group_item_qty[item.item_code]
item.amount = group_item_amount[item.item_code]
item.rate = flt(flt(item.amount)/flt(item.qty), item.precision("rate"))
del group_item_qty[item.item_code]
else:
duplicate_list.append(item)

View File

@@ -35,6 +35,7 @@ class BuyingController(StockController):
if getattr(self, "supplier", None) and not self.supplier_name:
self.supplier_name = frappe.db.get_value("Supplier", self.supplier, "supplier_name")
self.validate_items()
self.set_qty_as_per_stock_uom()
self.validate_stock_or_nonstock_items()
self.validate_warehouse()
@@ -456,3 +457,32 @@ class BuyingController(StockController):
else:
frappe.throw(_("Please enter Reqd by Date"))
def validate_items(self):
# validate items to see if they have is_purchase_item or is_subcontracted_item enabled
if self.doctype=="Material Request": return
if hasattr(self, "is_subcontracted") and self.is_subcontracted == 'Yes':
validate_item_type(self, "is_sub_contracted_item", "subcontracted")
else:
validate_item_type(self, "is_purchase_item", "purchase")
def validate_item_type(doc, fieldname, message):
# iterate through items and check if they are valid sales or purchase items
items = [d.item_code for d in doc.items if d.item_code]
# No validation check inase of creating transaction using 'Opening Invoice Creation Tool'
if not items:
return
item_list = ", ".join(["'%s'" % frappe.db.escape(d) for d in items])
invalid_items = [d[0] for d in frappe.db.sql("""
select item_code from tabItem where name in ({0}) and {1}=0
""".format(item_list, fieldname), as_list=True)]
if invalid_items:
frappe.throw(_("Following item {items} {verb} not marked as {message} item.\
You can enable them as {message} item from its Item master".format(
items = ", ".join([d for d in invalid_items]),
verb = "are" if len(invalid_items) > 1 else "is",
message = message)))

View File

@@ -176,6 +176,14 @@ def create_variant(item, args):
@frappe.whitelist()
def enqueue_multiple_variant_creation(item, args):
# There can be innumerable attribute combinations, enqueue
if isinstance(args, basestring):
variants = json.loads(args)
total_variants = 1
for key in variants:
total_variants *= len(variants[key])
if total_variants >= 600:
frappe.msgprint("Please do not create more than 500 items at a time", raise_exception=1)
return
frappe.enqueue("erpnext.controllers.item_variant.create_multiple_variants",
item=item, args=args, now=frappe.flags.in_test);

View File

@@ -157,9 +157,10 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
# scan description only if items are less than 50000
description_cond = 'or tabItem.description LIKE %(txt)s'
return frappe.db.sql("""select tabItem.name, tabItem.item_group,
return frappe.db.sql("""select tabItem.name,
if(length(tabItem.item_name) > 40,
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
tabItem.item_group,
if(length(tabItem.description) > 40, \
concat(substr(tabItem.description, 1, 40), "..."), description) as decription
from tabItem

View File

@@ -35,6 +35,7 @@ class SellingController(StockController):
def validate(self):
super(SellingController, self).validate()
self.validate_items()
self.validate_max_discount()
self.validate_selling_price()
self.set_qty_as_per_stock_uom()
@@ -337,6 +338,11 @@ class SellingController(StockController):
po_nos = frappe.get_all('Sales Order', 'po_no', filters = {'name': ('in', sales_orders)})
self.po_no = ', '.join(list(set([d.po_no for d in po_nos if d.po_no])))
def validate_items(self):
# validate items to see if they have is_sales_item enabled
from erpnext.controllers.buying_controller import validate_item_type
validate_item_type(self, "is_sales_item", "sales")
def check_active_sales_items(obj):
for d in obj.get("items"):
if d.item_code:

View File

@@ -38,6 +38,7 @@ class calculate_taxes_and_totals(object):
self.manipulate_grand_total_for_inclusive_tax()
self.calculate_totals()
self._cleanup()
self.calculate_total_net_weight()
def validate_conversion_rate(self):
# validate conversion rate
@@ -328,6 +329,13 @@ class calculate_taxes_and_totals(object):
self.set_rounded_total()
def calculate_total_net_weight(self):
if self.doc.meta.get_field('total_net_weight'):
self.doc.total_net_weight = 0.0
for d in self.doc.items:
if d.total_weight:
self.doc.total_net_weight += d.total_weight
def set_rounded_total(self):
if self.doc.meta.get_field("rounded_total"):
if self.doc.is_rounded_total_disabled():
@@ -558,7 +566,8 @@ def get_itemised_tax_breakup_html(doc):
itemised_tax=itemised_tax,
itemised_taxable_amount=itemised_taxable_amount,
tax_accounts=tax_accounts,
company_currency=erpnext.get_company_currency(doc.company)
conversion_rate=doc.conversion_rate,
currency=doc.currency
)
)
@@ -591,16 +600,19 @@ def get_itemised_tax(taxes):
for item_code, tax_data in item_tax_map.items():
itemised_tax.setdefault(item_code, frappe._dict())
tax_rate = 0.0
tax_amount = 0.0
if isinstance(tax_data, list):
itemised_tax[item_code][tax.description] = frappe._dict(dict(
tax_rate=flt(tax_data[0]),
tax_amount=flt(tax_data[1])
))
tax_rate = flt(tax_data[0])
tax_amount = flt(tax_data[1])
else:
itemised_tax[item_code][tax.description] = frappe._dict(dict(
tax_rate=flt(tax_data),
tax_amount=0.0
))
tax_rate = flt(tax_data)
itemised_tax[item_code][tax.description] = frappe._dict(dict(
tax_rate = tax_rate,
tax_amount = tax_amount
))
return itemised_tax

View File

@@ -24,7 +24,7 @@ frappe.ui.form.on('Student Report Generation Tool', {
frm.page.clear_indicator();
frm.page.set_primary_action(__('Print Report Card'), () => {
let url = "/api/method/erpnext.education.doctype.student_report_generation_tool.student_report_generation_tool.preview_report_card";
open_url_post(url, frm.doc, true);
open_url_post(url, {"doc": frm.doc}, true);
});
},

View File

@@ -3,7 +3,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
import frappe, json
from frappe.model.document import Document
from erpnext.education.api import get_grade
from frappe.utils.pdf import get_pdf
@@ -16,8 +16,8 @@ class StudentReportGenerationTool(Document):
@frappe.whitelist()
def preview_report_card(**kwargs):
doc = frappe._dict(**kwargs)
def preview_report_card(doc):
doc = frappe._dict(json.loads(doc))
doc.students = [doc.student]
if not (doc.student_name and doc.student_batch):
program_enrollment = frappe.get_all("Program Enrollment", fields=["student_batch_name", "student_name"],
@@ -33,7 +33,7 @@ def preview_report_card(**kwargs):
course_criteria = get_courses_criteria(courses)
# get the assessment group as per the user selection
if int(doc.include_all_assessment):
if doc.include_all_assessment:
assessment_groups = get_child_assessment_groups(doc.assessment_group)
else:
assessment_groups = [doc.assessment_group]
@@ -55,7 +55,7 @@ def preview_report_card(**kwargs):
"assessment_groups": assessment_groups,
"course_criteria": course_criteria,
"letterhead": letterhead.content,
"add_letterhead": int(doc.add_letterhead) if int(doc.add_letterhead) else 0
"add_letterhead": doc.add_letterhead if doc.add_letterhead else 0
})
final_template = frappe.render_template(base_template_path, {"body": html, "title": "Report Card"})

View File

@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import getdate
from frappe.utils import getdate, cstr
import json
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
@@ -125,7 +125,7 @@ def delete_medical_record(consultation):
def set_subject_field(consultation):
subject = "No Diagnosis "
if(consultation.diagnosis):
subject = "Diagnosis: \n"+ str(consultation.diagnosis)+". "
subject = "Diagnosis: \n"+ cstr(consultation.diagnosis)+". "
if(consultation.drug_prescription):
subject +="\nDrug(s) Prescribed. "
if(consultation.test_prescription):

View File

@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
import json
from frappe.utils import getdate
from frappe.utils import getdate, cstr
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account
from frappe import _
@@ -228,9 +228,9 @@ def get_employee_by_user_id(user_id):
return employee
def insert_lab_test_to_medical_record(doc):
subject = str(doc.test_name)
subject = cstr(doc.test_name)
if(doc.test_comment):
subject += ", \n"+str(doc.test_comment)
subject += ", \n"+ cstr(doc.test_comment)
medical_record = frappe.new_doc("Patient Medical Record")
medical_record.patient = doc.patient
medical_record.subject = subject

View File

@@ -5,6 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe.utils import cstr
class VitalSigns(Document):
def on_submit(self):
@@ -33,16 +34,16 @@ def delete_vital_signs_from_medical_record(doc):
def set_subject_field(doc):
subject = " "
if(doc.temperature):
subject += "Temperature: \n"+ str(doc.temperature)+". "
subject += "Temperature: \n"+ cstr(doc.temperature)+". "
if(doc.pulse):
subject += "Pulse: \n"+ str(doc.pulse)+". "
subject += "Pulse: \n"+ cstr(doc.pulse)+". "
if(doc.respiratory_rate):
subject += "Respiratory Rate: \n"+ str(doc.respiratory_rate)+". "
subject += "Respiratory Rate: \n"+ cstr(doc.respiratory_rate)+". "
if(doc.bp):
subject += "BP: \n"+ str(doc.bp)+". "
subject += "BP: \n"+ cstr(doc.bp)+". "
if(doc.bmi):
subject += "BMI: \n"+ str(doc.bmi)+". "
subject += "BMI: \n"+ cstr(doc.bmi)+". "
if(doc.nutrition_note):
subject += "Note: \n"+ str(doc.nutrition_note)+". "
subject += "Note: \n"+ cstr(doc.nutrition_note)+". "
return subject

View File

@@ -24,6 +24,7 @@ cur_frm.cscript.refresh = function(doc,cdt,cdn){
}
cur_frm.cscript.kra_template = function(doc, dt, dn) {
doc.goals = [];
erpnext.utils.map_current_doc({
method: "erpnext.hr.doctype.appraisal.appraisal.fetch_appraisal_template",
source_name: cur_frm.doc.kra_template,

View File

@@ -20,17 +20,19 @@ class Attendance(Document):
set_employee_name(self)
def check_leave_record(self):
leave_record = frappe.db.sql("""select leave_type, half_day from `tabLeave Application`
leave_record = frappe.db.sql("""select leave_type, half_day, half_day_date from `tabLeave Application`
where employee = %s and %s between from_date and to_date and status = 'Approved'
and docstatus = 1""", (self.employee, self.attendance_date), as_dict=True)
if leave_record:
if leave_record[0].half_day:
self.status = 'Half Day'
frappe.msgprint(_("Employee {0} on Half day on {1}").format(self.employee, self.attendance_date))
else:
self.status = 'On Leave'
self.leave_type = leave_record[0].leave_type
frappe.msgprint(_("Employee {0} on Leave on {1}").format(self.employee, self.attendance_date))
for d in leave_record:
if d.half_day_date == getdate(self.attendance_date):
self.status = 'Half Day'
frappe.msgprint(_("Employee {0} on Half day on {1}").format(self.employee, self.attendance_date))
else:
self.status = 'On Leave'
self.leave_type = d.leave_type
frappe.msgprint(_("Employee {0} on Leave on {1}").format(self.employee, self.attendance_date))
if self.status == "On Leave" and not leave_record:
frappe.throw(_("No leave record found for employee {0} for {1}").format(self.employee, self.attendance_date))

View File

@@ -45,8 +45,9 @@ class ExpenseClaim(AccountsController):
}[cstr(self.docstatus or 0)]
paid_amount = flt(self.total_amount_reimbursed) + flt(self.total_advance_amount)
precision = self.precision("total_sanctioned_amount")
if (self.is_paid or (flt(self.total_sanctioned_amount) > 0
and flt(self.total_sanctioned_amount) == paid_amount)) \
and flt(self.total_sanctioned_amount, precision) == flt(paid_amount, precision))) \
and self.docstatus == 1 and self.approval_status == 'Approved':
self.status = "Paid"
elif flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and self.approval_status == 'Approved':

View File

@@ -42,6 +42,7 @@ frappe.ui.form.on("Leave Application", {
employee: function(frm) {
frm.trigger("get_leave_balance");
frm.trigger("set_leave_approver");
},
leave_type: function(frm) {
@@ -95,6 +96,9 @@ frappe.ui.form.on("Leave Application", {
if (!r.exc && r.message) {
frm.set_value('leave_balance', r.message);
}
else {
frm.set_value('leave_balance', "0");
}
}
});
}
@@ -122,4 +126,21 @@ frappe.ui.form.on("Leave Application", {
});
}
},
set_leave_approver: function(frm) {
if(frm.doc.employee) {
// server call is done to include holidays in leave days calculations
return frappe.call({
method: 'erpnext.hr.doctype.leave_application.leave_application.get_leave_approver_data',
args: {
"employee": frm.doc.employee,
},
callback: function(r) {
if (r && r.message) {
frm.set_value('leave_approver', r.message);
}
}
});
}
}
});

View File

@@ -5,12 +5,12 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \
comma_or, get_fullname
comma_or, get_fullname, nowdate
from erpnext.hr.utils import set_employee_name
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.hr.doctype.employee_leave_approver.employee_leave_approver import get_approver_list
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange
class LeaveDayBlockedError(frappe.ValidationError): pass
class OverlapError(frappe.ValidationError): pass
@@ -52,6 +52,7 @@ class LeaveApplication(Document):
frappe.throw(_("Only Leave Applications with status 'Approved' and 'Rejected' can be submitted"))
self.validate_back_dated_application()
self.update_attendance()
# notify leave applier about approval
self.notify_employee(self.status)
@@ -59,6 +60,7 @@ class LeaveApplication(Document):
def on_cancel(self):
# notify leave applier about cancellation
self.notify_employee("cancelled")
self.cancel_attendance()
def validate_dates(self):
if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)):
@@ -100,6 +102,50 @@ class LeaveApplication(Document):
frappe.throw(_("Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}")
.format(formatdate(future_allocation[0].from_date), future_allocation[0].name))
def update_attendance(self):
if self.status == "Approved":
attendance = frappe.db.sql("""select name from `tabAttendance` where employee = %s\
and (attendance_date between %s and %s) and docstatus < 2""",(self.employee, self.from_date, self.to_date), as_dict=1)
if attendance:
for d in attendance:
doc = frappe.get_doc("Attendance", d.name)
if getdate(self.half_day_date) == doc.attendance_date:
status = "Half Day"
else:
status = "On Leave"
frappe.db.sql("""update `tabAttendance` set status = %s, leave_type = %s\
where name = %s""",(status, self.leave_type, d.name))
elif getdate(self.to_date) <= getdate(nowdate()):
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
date = dt.strftime("%Y-%m-%d")
if not date == self.half_day_date:
doc = frappe.new_doc("Attendance")
doc.employee = self.employee
doc.attendance_date = date
doc.company = self.company
doc.status = "On Leave"
doc.leave_type = self.leave_type
doc.insert(ignore_permissions=True)
doc.submit()
else:
doc = frappe.new_doc("Attendance")
doc.employee = self.employee
doc.attendance_date = date
doc.company = self.company
doc.status = "Half Day"
doc.leave_type = self.leave_type
doc.insert(ignore_permissions=True)
doc.submit()
def cancel_attendance(self):
if self.docstatus == 2:
attendance = frappe.db.sql("""select name from `tabAttendance` where employee = %s\
and (attendance_date between %s and %s) and docstatus < 2 and status in ('On Leave', 'Half Day')""",(self.employee, self.from_date, self.to_date), as_dict=1)
for name in attendance:
frappe.db.set_value("Attendance", name, "docstatus", 2)
def validate_salary_processed_days(self):
if not frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
return
@@ -309,7 +355,7 @@ def get_approvers(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist()
def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None):
number_of_days = 0
if half_day == 1:
if cint(half_day) == 1:
if from_date == to_date:
number_of_days = 0.5
else:
@@ -436,30 +482,17 @@ def add_department_leaves(events, start, end, employee, company):
and company=%s""", (department, company))
match_conditions = "and employee in (\"%s\")" % '", "'.join(department_employees)
add_leaves(events, start, end, filter_conditions=match_conditions)
def add_leaves(events, start, end, filter_conditions=None):
conditions = []
if filter_conditions:
conditions.append(filter_conditions)
if not cint(frappe.db.get_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar")):
from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("Leave Application")
if match_conditions:
conditions.append(match_conditions)
add_leaves(events, start, end, match_conditions=match_conditions)
def add_leaves(events, start, end, match_conditions=None):
query = """select name, from_date, to_date, employee_name, half_day,
status, employee, docstatus
from `tabLeave Application` where
from_date <= %(end)s and to_date >= %(start)s <= to_date
and docstatus < 2
and status!="Rejected" """
if conditions:
query += ' and '.join(conditions)
if match_conditions:
query += match_conditions
for d in frappe.db.sql(query, {"start":start, "end": end}, as_dict=True):
e = {
@@ -507,3 +540,8 @@ def add_holidays(events, start, end, employee, company):
"title": _("Holiday") + ": " + cstr(holiday.description),
"name": holiday.name
})
@frappe.whitelist()
def get_leave_approver_data(employee):
return frappe.db.get_value("Employee Leave Approver",
{'parent': employee}, 'leave_approver')

View File

@@ -14,8 +14,12 @@ from erpnext.utilities.transaction_base import TransactionBase
from frappe.utils.background_jobs import enqueue
class SalarySlip(TransactionBase):
def __init__(self, *args, **kwargs):
super(SalarySlip, self).__init__(*args, **kwargs)
self.series = 'Sal Slip/{0}/.#####'.format(self.employee)
def autoname(self):
self.name = make_autoname('Sal Slip/' +self.employee + '/.#####')
self.name = make_autoname(self.series)
def validate(self):
self.status = self.get_status()
@@ -418,6 +422,10 @@ class SalarySlip(TransactionBase):
self.set_status()
self.update_status()
def on_trash(self):
from frappe.model.naming import revert_series_if_last
revert_series_if_last(self.series, self.name)
def email_salary_slip(self):
receiver = frappe.db.get_value("Employee", self.employee, "prefered_email")

View File

@@ -22,6 +22,10 @@ def execute(filters=None):
holiday_map = get_holiday(holiday_list, filters["month"])
data = []
leave_types = frappe.db.sql("""select name from `tabLeave Type`""", as_list=True)
leave_list = [d[0] for d in leave_types]
columns.extend(leave_list)
for emp in sorted(att_map):
emp_det = emp_map.get(emp)
if not emp_det:
@@ -49,10 +53,35 @@ def execute(filters=None):
elif status == "Half Day":
total_p += 0.5
total_a += 0.5
total_l += 0.5
row += [total_p, total_l, total_a]
data.append(row)
if not filters.get("employee"):
filters.update({"employee": emp})
conditions += " and employee = %(employee)s"
elif not filters.get("employee") == emp:
filters.update({"employee": emp})
leave_details = frappe.db.sql("""select leave_type, status, count(*) as count from `tabAttendance`\
where leave_type is not NULL %s group by leave_type, status""" % conditions, filters, as_dict=1)
leaves = {}
for d in leave_details:
if d.status == "Half Day":
d.count = d.count * 0.5
if d.leave_type in leaves:
leaves[d.leave_type] += d.count
else:
leaves[d.leave_type] = d.count
for d in leave_list:
if d in leaves:
row.append(leaves[d])
else:
row.append("0.0")
data.append(row)
return columns, data
def get_columns(filters):

View File

@@ -9,7 +9,7 @@ from frappe.utils import flt,cstr
from erpnext.accounts.report.financial_statements import get_period_list
def execute(filters=None):
columns, data = [], []
columns, data, chart = [], [], []
if filters.get('fiscal_year'):
company = erpnext.get_default_company()
period_list = get_period_list(filters.get('fiscal_year'), filters.get('fiscal_year'),"Monthly", company)

View File

@@ -158,7 +158,7 @@ class BOM(WebsiteGenerator):
if not self.buying_price_list:
frappe.throw(_("Please select Price List"))
rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list,
"item_code": arg["item_code"]}, "price_list_rate")
"item_code": arg["item_code"]}, "price_list_rate") or 0.0
price_list_currency = frappe.db.get_value("Price List",
self.buying_price_list, "currency")
@@ -652,4 +652,4 @@ def get_boms_in_bottom_up_order(bom_no=None):
bom_list.append(child_bom)
count += 1
return bom_list
return bom_list

View File

@@ -22,6 +22,21 @@ frappe.ui.form.on('BOM Update Tool', {
frm.disable_save();
},
replace: function(frm) {
if (frm.doc.current_bom && frm.doc.new_bom) {
frappe.call({
method: "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.enqueue_replace_bom",
freeze: true,
args: {
args: {
"current_bom": frm.doc.current_bom,
"new_bom": frm.doc.new_bom
}
}
});
}
},
update_latest_price_in_all_boms: function() {
frappe.call({
method: "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.enqueue_update_cost",

View File

@@ -123,7 +123,7 @@
"label": "Replace",
"length": 0,
"no_copy": 0,
"options": "replace_bom",
"options": "",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -208,7 +208,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-31 18:08:05.919276",
"modified": "2018-07-02 16:17:09.014102",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Update Tool",

View File

@@ -3,9 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
import frappe, json
from frappe.utils import cstr, flt
from frappe import _
from six import string_types
from erpnext.manufacturing.doctype.bom.bom import get_boms_in_bottom_up_order
from frappe.model.document import Document
@@ -17,12 +18,14 @@ class BOMUpdateTool(Document):
updated_bom = []
for bom in bom_list:
bom_obj = frappe.get_doc("BOM", bom)
bom_obj.get_doc_before_save()
updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom)
bom_obj.calculate_cost()
bom_obj.update_parent_cost()
bom_obj.db_update()
frappe.msgprint(_("BOM replaced"))
if (getattr(bom_obj.meta, 'track_changes', False)
and bom_obj._doc_before_save and not bom_obj.flags.ignore_version):
bom_obj.save_version()
def validate_bom(self):
if cstr(self.current_bom) == cstr(self.new_bom):
@@ -54,6 +57,14 @@ class BOMUpdateTool(Document):
return bom_list
@frappe.whitelist()
def enqueue_replace_bom(args):
if isinstance(args, string_types):
args = json.loads(args)
frappe.enqueue("erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.replace_bom", args=args)
frappe.msgprint(_("Queued for replacing the BOM. It may take a few minutes."))
@frappe.whitelist()
def enqueue_update_cost():
frappe.enqueue("erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_cost")
@@ -63,6 +74,14 @@ def update_latest_price_in_all_boms():
if frappe.db.get_single_value("Manufacturing Settings", "update_bom_costs_automatically"):
update_cost()
def replace_bom(args):
args = frappe._dict(args)
doc = frappe.get_doc("BOM Update Tool")
doc.current_bom = args.current_bom
doc.new_bom = args.new_bom
doc.replace_bom()
def update_cost():
bom_list = get_boms_in_bottom_up_order()
for bom in bom_list:

View File

@@ -64,8 +64,7 @@ erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({
var chart_data = this.get_chart_data ? this.get_chart_data() : null;
this.chart = new Chart({
parent: ".chart",
this.chart = new frappeChart.Chart(".chart", {
data: chart_data,
type: 'line'
});

View File

@@ -15,6 +15,7 @@
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -42,10 +43,12 @@
"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,
@@ -73,10 +76,12 @@
"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,
@@ -102,10 +107,12 @@
"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,
@@ -133,15 +140,17 @@
"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": "membership_validaty_section",
"fieldname": "membership_validity_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -150,7 +159,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "membership validaty section",
"label": "Validity",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -163,10 +172,12 @@
"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,
@@ -193,10 +204,12 @@
"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,
@@ -223,10 +236,12 @@
"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,
@@ -252,10 +267,12 @@
"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,
@@ -282,10 +299,12 @@
"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,
@@ -312,10 +331,12 @@
"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,
@@ -342,10 +363,12 @@
"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,
@@ -373,10 +396,12 @@
"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,
@@ -403,6 +428,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@@ -416,7 +442,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-05 07:02:56.859408",
"modified": "2018-06-26 19:23:17.911121",
"modified_by": "Administrator",
"module": "Non Profit",
"name": "Membership",
@@ -425,7 +451,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -445,7 +470,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -472,5 +496,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}
"track_seen": 0,
"track_views": 0
}

View File

@@ -502,3 +502,4 @@ erpnext.patches.v10_0.fix_reserved_qty_for_sub_contract
erpnext.patches.v10_0.taxes_issue_with_pos
erpnext.patches.v10_0.set_qty_in_transactions_based_on_serial_no_input
erpnext.patches.v10_0.show_leaves_of_all_department_members_in_calendar
erpnext.patches.v10_0.update_status_in_purchase_receipt

View File

@@ -9,4 +9,13 @@ def execute():
ss = frappe.get_doc("Stock Settings")
ss.set_qty_in_transactions_based_on_serial_no_input = 1
if ss.default_warehouse \
and not frappe.db.exists("Warehouse", ss.default_warehouse):
ss.default_warehouse = None
if ss.stock_uom and not frappe.db.exists("UOM", ss.stock_uom):
ss.stock_uom = None
ss.flags.ignore_mandatory = True
ss.save()

View File

@@ -0,0 +1,7 @@
import frappe
def execute():
frappe.reload_doc("stock", "doctype", "purchase_receipt")
frappe.db.sql('''
UPDATE `tabPurchase Receipt` SET status = "Completed" WHERE per_billed = 100 AND docstatus = 1
''')

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, getdate, get_url
from frappe.utils import flt, getdate, get_url, now
from frappe import _
from frappe.model.document import Document
@@ -60,6 +60,7 @@ class Project(Document):
self.validate_weights()
self.sync_tasks()
self.tasks = []
self.load_tasks()
self.send_welcome_email()
def validate_project_name(self):
@@ -75,7 +76,7 @@ class Project(Document):
sum = 0
for task in self.tasks:
if task.task_weight > 0:
sum = sum + task.task_weight
sum = flt(sum + task.task_weight, task.precision('task_weight'))
if sum > 0 and sum != 1:
frappe.throw(_("Total of all task weights should be 1. Please adjust weights of all Project tasks accordingly"))
@@ -83,36 +84,68 @@ class Project(Document):
"""sync tasks and remove table"""
if self.flags.dont_sync_tasks: return
task_names = []
existing_task_data = {}
for d in frappe.get_all('Project Task',
fields = ["title", "status", "start_date", "end_date", "description", "task_weight", "task_id"],
filters = {'parent': self.name}):
existing_task_data.setdefault(d.task_id, d)
for t in self.tasks:
if t.task_id:
task = frappe.get_doc("Task", t.task_id)
else:
task = frappe.new_doc("Task")
task.project = self.name
task.update({
"subject": t.title,
"status": t.status,
"exp_start_date": t.start_date,
"exp_end_date": t.end_date,
"description": t.description,
"task_weight": t.task_weight
})
self.map_custom_fields(t, task)
if not t.task_id or self.is_row_updated(t, existing_task_data):
task.update({
"subject": t.title,
"status": t.status,
"exp_start_date": t.start_date,
"exp_end_date": t.end_date,
"description": t.description,
"task_weight": t.task_weight
})
task.flags.ignore_links = True
task.flags.from_project = True
task.flags.ignore_feed = True
task.save(ignore_permissions = True)
task_names.append(task.name)
self.map_custom_fields(t, task)
task.flags.ignore_links = True
task.flags.from_project = True
task.flags.ignore_feed = True
if t.task_id:
task.update({
"modified_by": frappe.session.user,
"modified": now()
})
task.validate()
task.db_update()
else:
task.save(ignore_permissions = True)
task_names.append(task.name)
else:
task_names.append(task.name)
# delete
for t in frappe.get_all("Task", ["name"], {"project": self.name, "name": ("not in", task_names)}):
frappe.delete_doc("Task", t.name)
def update_costing_and_percentage_complete(self):
self.update_percent_complete()
self.update_costing()
def is_row_updated(self, row, existing_task_data):
if self.get("__islocal") or not existing_task_data: return True
d = existing_task_data.get(row.task_id)
if (d and (row.title != d.title or row.status != d.status
or getdate(row.start_date) != getdate(d.start_date) or getdate(row.end_date) != getdate(d.end_date)
or row.description != d.description or row.task_weight != d.task_weight)):
return True
def map_custom_fields(self, source, target):
project_task_custom_fields = frappe.get_all("Custom Field", {"dt": "Project Task"}, "fieldname")
@@ -207,6 +240,9 @@ class Project(Document):
self.total_billed_amount = total_billed_amount and total_billed_amount[0][0] or 0
def after_rename(self, old_name, new_name, merge=False):
if old_name == self.copied_from:
frappe.db.set_value('Project', new_name, 'copied_from', new_name)
def send_welcome_email(self):
url = get_url("/project/?name={0}".format(self.name))
@@ -227,8 +263,7 @@ class Project(Document):
user.welcome_email_sent=1
def on_update(self):
self.load_tasks()
self.sync_tasks()
self.update_costing_and_percentage_complete()
self.update_dependencies_on_duplicated_project()
def update_dependencies_on_duplicated_project(self):
@@ -251,9 +286,7 @@ class Project(Document):
continue
name = _task.name
depends_on_tasks = _task.depends_on_tasks
depends_on_tasks = [x for x in depends_on_tasks.split(',') if x]
dependency_map[task.title] = [ x['subject'] for x in frappe.get_list(
'Task Depends On', {"parent": name}, ['subject'])]
@@ -264,7 +297,8 @@ class Project(Document):
for dt in value:
dt_name = frappe.db.get_value('Task', {"subject": dt, "project": self.name })
task_doc.append('depends_on', {"task": dt_name})
task_doc.save()
task_doc.db_update()
def get_timeline_data(doctype, name):
'''Return timeline for attendance'''

View File

@@ -61,7 +61,7 @@
"label": "Status",
"length": 0,
"no_copy": 1,
"options": "Open\nWorking\nPending Review\nClosed\nCancelled",
"options": "Open\nWorking\nPending Review\nOverdue\nClosed\nCancelled",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -371,7 +371,7 @@
"remember_last_selected_value": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
}
@@ -386,7 +386,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-12-19 14:49:15.886339",
"modified": "2018-07-05 19:34:31.204454",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project Task",

View File

@@ -38,7 +38,7 @@
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
@@ -70,7 +70,7 @@
"remember_last_selected_value": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
@@ -1214,7 +1214,7 @@
"istable": 0,
"max_attachments": 5,
"menu_index": 0,
"modified": "2017-11-10 18:37:19.660293",
"modified": "2018-06-26 11:46:06.678115",
"modified_by": "Administrator",
"module": "Projects",
"name": "Task",

View File

@@ -420,9 +420,10 @@ def get_timesheets_list(doctype, txt, filters, limit_start, limit_page_length=20
# find customer name from contact.
customer = frappe.db.sql('''SELECT dl.link_name FROM `tabContact` AS c inner join \
`tabDynamic Link` AS dl ON c.first_name=dl.link_name WHERE c.email_id=%s''',user)
# find list of Sales Invoice for made for customer.
sales_invoice = frappe.db.sql('''SELECT name FROM `tabSales Invoice` WHERE customer = %s''',customer)
if customer:
# find list of Sales Invoice for made for customer.
sales_invoice = frappe.db.sql('''SELECT name FROM `tabSales Invoice` WHERE customer = %s''',customer)
# Return timesheet related data to web portal.
return frappe. db.sql('''SELECT ts.name, tsd.activity_type, ts.status, ts.total_billable_hours, \
tsd.sales_invoice, tsd.project FROM `tabTimesheet` AS ts inner join `tabTimesheet Detail` \

View File

@@ -338,12 +338,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
// store tax breakup for each item
var key = item.item_code || item.item_name;
var item_wise_tax_amount = current_tax_amount * this.frm.doc.conversion_rate;
if (tax.item_wise_tax_detail && tax.item_wise_tax_detail[key])
item_wise_tax_amount += tax.item_wise_tax_detail[key][1];
let tax_detail = tax.item_wise_tax_detail;
let key = item.item_code || item.item_name;
tax.item_wise_tax_detail[key] = [tax_rate, flt(item_wise_tax_amount, precision("base_tax_amount", tax))];
let item_wise_tax_amount = current_tax_amount * this.frm.doc.conversion_rate;
if (tax_detail && tax_detail[key])
item_wise_tax_amount += tax_detail[key][1];
tax_detail[key] = [tax_rate, flt(item_wise_tax_amount, precision("base_tax_amount", tax))];
},
round_off_totals: function(tax) {

View File

@@ -106,7 +106,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
if(
this.frm.docstatus < 2
this.frm.docstatus < 2
&& this.frm.fields_dict["payment_terms_template"]
&& this.frm.fields_dict["payment_schedule"]
&& this.frm.doc.payment_terms_template
@@ -1094,6 +1094,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
me.in_apply_price_list = false;
}
}
}).always(() => {
me.in_apply_price_list = false;
});
},

View File

@@ -169,21 +169,25 @@ erpnext.utils.validate_mandatory = function(frm, label, value, trigger_on) {
}
erpnext.utils.get_shipping_address = function(frm, callback){
frappe.call({
method: "frappe.contacts.doctype.address.address.get_shipping_address",
args: {
company: frm.doc.company,
address: frm.doc.shipping_address
},
callback: function(r){
if(r.message){
frm.set_value("shipping_address", r.message[0]) //Address title or name
frm.set_value("shipping_address_display", r.message[1]) //Address to be displayed on the page
}
if (frm.doc.company) {
frappe.call({
method: "frappe.contacts.doctype.address.address.get_shipping_address",
args: {
company: frm.doc.company,
address: frm.doc.shipping_address
},
callback: function(r){
if(r.message){
frm.set_value("shipping_address", r.message[0]) //Address title or name
frm.set_value("shipping_address_display", r.message[1]) //Address to be displayed on the page
}
if(callback){
return callback();
if(callback){
return callback();
}
}
}
});
});
} else {
frappe.msgprint(__("Select company first"));
}
}

View File

@@ -23,7 +23,7 @@ class Gstr1Report(object):
posting_date,
base_grand_total,
base_rounded_total,
customer_gstin,
COALESCE(NULLIF(customer_gstin,''), NULLIF(billing_address_gstin, '')) as customer_gstin,
place_of_supply,
ecommerce_gstin,
reverse_charge,
@@ -144,17 +144,10 @@ class Gstr1Report(object):
""" % (self.doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1)
for d in items:
item_details = {}
item_details[d.item_code] = d.base_net_amount
if d.parent in self.invoice_items:
parent_dict = self.invoice_items[d.parent]
if d.item_code in parent_dict:
item_details[d.item_code] += parent_dict[d.item_code]
else:
item_details.update(parent_dict)
self.invoice_items[d.parent] = item_details
if d.item_code not in self.invoice_items.get(d.parent, {}):
self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
sum(i.get('base_net_amount', 0) for i in items
if i.item_code == d.item_code and i.parent == d.parent))
def get_items_based_on_tax_rate(self):
self.tax_details = frappe.db.sql("""

View File

@@ -17,7 +17,7 @@ def setup(company=None, patch=True):
def make_custom_fields():
invoice_fields = [
dict(fieldname='vat_section', label='VAT Details', fieldtype='Section Break',
insert_after='select_print_heading', print_hide=1, collapsible=1),
insert_after='group_same_items', print_hide=1, collapsible=1),
dict(fieldname='permit_no', label='Permit Number',
fieldtype='Data', insert_after='vat_section', print_hide=1),
dict(fieldname='reverse_charge_applicable', label='Reverse Charge Applicable',

View File

@@ -79,7 +79,7 @@ class Customer(TransactionBase):
def update_customer_groups(self):
ignore_doctypes = ["Lead", "Opportunity", "POS Profile", "Tax Rule", "Pricing Rule"]
if frappe.flags.customer_group_changed:
update_linked_doctypes('Customer', self.name, 'Customer Group',
update_linked_doctypes('Customer', frappe.db.escape(self.name), 'Customer Group',
self.customer_group, ignore_doctypes)
def create_primary_contact(self):
@@ -316,7 +316,7 @@ def make_address(args, is_primary_address=1):
return address
def get_customer_primary_contact(doctype, txt, searchfield, start, page_len, filters):
customer = frappe.db.escape(filters.get('customer'))
customer = filters.get('customer')
return frappe.db.sql("""
select `tabContact`.name from `tabContact`, `tabDynamic Link`
where `tabContact`.name = `tabDynamic Link`.parent and `tabDynamic Link`.link_name = %(customer)s

View File

@@ -186,7 +186,7 @@ cur_frm.cscript['Declare Order Lost'] = function(){
return cur_frm.call({
method: "declare_order_lost",
doc: cur_frm.doc,
args: args.reason,
args: args,
callback: function(r) {
if(r.exc) {
frappe.msgprint(__("There were errors."));

View File

@@ -1076,7 +1076,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2439,8 +2439,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "select_print_heading",
"fieldtype": "Link",
"fieldname": "group_same_items",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -2448,18 +2448,16 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Print Heading",
"label": "Group same items",
"length": 0,
"no_copy": 1,
"oldfieldname": "select_print_heading",
"oldfieldtype": "Link",
"options": "Print Heading",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
@@ -2496,6 +2494,38 @@
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "select_print_heading",
"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": "Print Heading",
"length": 0,
"no_copy": 1,
"oldfieldname": "select_print_heading",
"oldfieldtype": "Link",
"options": "Print Heading",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2881,8 +2911,8 @@
"istable": 0,
"max_attachments": 1,
"menu_index": 0,
"modified": "2017-12-19 14:52:28.966139",
"modified_by": "nabinhait@gmail.com",
"modified": "2018-07-06 03:23:15.354674",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
"owner": "Administrator",

View File

@@ -70,10 +70,10 @@ class Quotation(SellingController):
opp.status = None
opp.set_status(update=True)
def declare_order_lost(self, arg):
def declare_order_lost(self, reason):
if not self.has_sales_order():
frappe.db.set(self, 'status', 'Lost')
frappe.db.set(self, 'order_lost_reason', arg)
frappe.db.set(self, 'order_lost_reason', reason)
self.update_opportunity()
self.update_lead()
else:
@@ -185,6 +185,7 @@ def _make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
target.run_method("calculate_taxes_and_totals")
def update_item(obj, target, source_parent):
target.cost_center = None
target.stock_qty = flt(obj.qty) * flt(obj.conversion_factor)
doclist = get_mapped_doc("Quotation", source_name, {

View File

@@ -1131,7 +1131,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3529,7 +3529,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-01-12 15:56:12.483019",
"modified": "2018-07-06 15:56:12.483019",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",

View File

@@ -7,12 +7,12 @@
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-02-24 20:08:44.614482",
"modified": "2018-06-18 16:42:05.860309",
"modified_by": "Administrator",
"module": "Selling",
"name": "Item-wise Sales History",
"owner": "Administrator",
"query": "select\n so_item.item_code as \"Item Code:Link/Item:120\",\n\tso_item.item_name as \"Item Name::120\",\n so_item.item_group as \"Item Group:Link/Item Group:120\",\n\tso_item.description as \"Description::150\",\n\tso_item.qty as \"Qty:Float:100\",\n\tso_item.stock_uom as \"UOM:Link/UOM:80\",\n\tso_item.base_rate as \"Rate:Currency:120\",\n\tso_item.base_amount as \"Amount:Currency:120\",\n\tso.name as \"Sales Order:Link/Sales Order:120\",\n\tso.transaction_date as \"Transaction Date:Date:140\",\n\tso.customer as \"Customer:Link/Customer:130\",\n cu.customer_name as \"Customer Name::150\",\n\tso.territory as \"Territory:Link/Territory:130\",\n so.project as \"Project:Link/Project:130\",\n\tifnull(so_item.delivered_qty, 0) as \"Delivered Qty:Float:120\",\n\tifnull(so_item.billed_amt, 0) as \"Billed Amount:Currency:120\",\n\tso.company as \"Company:Link/Company:\"\nfrom\n\t`tabSales Order` so, `tabSales Order Item` so_item, `tabCustomer` cu\nwhere\n\tso.name = so_item.parent and so.customer=cu.name\n\tand so.docstatus = 1\norder by so.name desc",
"query": "select\n so_item.item_code as \"Item Code:Link/Item:120\",\n\tso_item.item_name as \"Item Name::120\",\n so_item.item_group as \"Item Group:Link/Item Group:120\",\n\tso_item.description as \"Description::150\",\n\tso_item.qty as \"Qty:Data:100\",\n\tso_item.uom as \"UOM:Link/UOM:80\",\n\tso_item.base_rate as \"Rate:Currency:120\",\n\tso_item.base_amount as \"Amount:Currency:120\",\n\tso.name as \"Sales Order:Link/Sales Order:120\",\n\tso.transaction_date as \"Transaction Date:Date:140\",\n\tso.customer as \"Customer:Link/Customer:130\",\n cu.customer_name as \"Customer Name::150\",\n\tso.territory as \"Territory:Link/Territory:130\",\n so.project as \"Project:Link/Project:130\",\n\tifnull(so_item.delivered_qty, 0) as \"Delivered Qty:Float:120\",\n\tifnull(so_item.billed_amt, 0) as \"Billed Amount:Currency:120\",\n\tso.company as \"Company:Link/Company:\"\nfrom\n\t`tabSales Order` so, `tabSales Order Item` so_item, `tabCustomer` cu\nwhere\n\tso.name = so_item.parent and so.customer=cu.name\n\tand so.docstatus = 1\norder by so.name desc",
"ref_doctype": "Sales Order",
"report_name": "Item-wise Sales History",
"report_type": "Query Report",

View File

@@ -91,17 +91,22 @@ def get_achieved_details(filters, sales_person, all_sales_persons, target_item_g
start_date, end_date = get_fiscal_year(fiscal_year = filters["fiscal_year"])[1:]
item_details = frappe.db.sql("""
select
sum(soi.stock_qty * (st.allocated_percentage/100)) as qty,
sum(soi.base_net_amount * (st.allocated_percentage/100)) as amount,
st.sales_person, MONTHNAME(so.transaction_date) as month_name
SELECT st.sales_person, MONTHNAME(so.transaction_date) as month_name,
CASE
WHEN so.status = "Closed" THEN sum(soi.delivered_qty * soi.conversion_factor * (st.allocated_percentage/100))
ELSE sum(soi.stock_qty * (st.allocated_percentage/100))
END as qty,
CASE
WHEN so.status = "Closed" THEN sum(soi.delivered_qty * soi.conversion_factor * soi.base_net_rate * (st.allocated_percentage/100))
ELSE sum(soi.base_net_amount * (st.allocated_percentage/100))
END as amount
from
`tabSales Order Item` soi, `tabSales Order` so, `tabSales Team` st
where
soi.parent=so.name and so.docstatus=1 and st.parent=so.name
and so.transaction_date>=%s and so.transaction_date<=%s
and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name=st.sales_person)
and exists(select name from `tabItem Group` where lft >= %s and rgt <= %s and name=soi.item_group)
and exists(SELECT name from `tabSales Person` where lft >= %s and rgt <= %s and name=st.sales_person)
and exists(SELECT name from `tabItem Group` where lft >= %s and rgt <= %s and name=soi.item_group)
group by
sales_person, month_name
""",

View File

@@ -59,5 +59,11 @@ frappe.query_reports["Sales Person-wise Transaction Summary"] = {
fieldtype: "Link",
options: "Territory",
},
{
fieldname:"show_return_entries",
label: __("Show Return Entries"),
fieldtype: "Check",
default: 0,
},
]
}

View File

@@ -15,11 +15,12 @@ def execute(filters=None):
data = []
for d in entries:
data.append([
d.name, d.customer, d.territory, d.posting_date, d.item_code,
item_details.get(d.item_code, {}).get("item_group"), item_details.get(d.item_code, {}).get("brand"),
d.stock_qty, d.base_net_amount, d.sales_person, d.allocated_percentage, d.contribution_amt
])
if d.stock_qty > 0 or filters.get('show_return_entries', 0):
data.append([
d.name, d.customer, d.territory, d.posting_date, d.item_code,
item_details.get(d.item_code, {}).get("item_group"), item_details.get(d.item_code, {}).get("brand"),
d.stock_qty, d.base_net_amount, d.sales_person, d.allocated_percentage, d.contribution_amt
])
if data:
total_row = [""]*len(data[0])
@@ -40,18 +41,34 @@ def get_columns(filters):
def get_entries(filters):
date_field = filters["doc_type"] == "Sales Order" and "transaction_date" or "posting_date"
if filters["doc_type"] == "Sales Order":
qty_field = "delivered_qty"
else:
qty_field = "qty"
conditions, values = get_conditions(filters, date_field)
entries = frappe.db.sql("""
select
dt.name, dt.customer, dt.territory, dt.%s as posting_date, dt_item.item_code,
dt_item.stock_qty, dt_item.base_net_amount, st.sales_person, st.allocated_percentage,
dt_item.base_net_amount*st.allocated_percentage/100 as contribution_amt
st.sales_person, st.allocated_percentage,
CASE
WHEN dt.status = "Closed" THEN dt_item.%s * dt_item.conversion_factor
ELSE dt_item.stock_qty
END as stock_qty,
CASE
WHEN dt.status = "Closed" THEN (dt_item.base_net_rate * dt_item.%s * dt_item.conversion_factor)
ELSE dt_item.base_net_amount
END as base_net_amount,
CASE
WHEN dt.status = "Closed" THEN ((dt_item.base_net_rate * dt_item.%s * dt_item.conversion_factor) * st.allocated_percentage/100)
ELSE dt_item.base_net_amount * st.allocated_percentage/100
END as contribution_amt
from
`tab%s` dt, `tab%s Item` dt_item, `tabSales Team` st
where
st.parent = dt.name and dt.name = dt_item.parent and st.parenttype = %s
and dt.docstatus = 1 %s order by st.sales_person, dt.name desc
""" %(date_field, filters["doc_type"], filters["doc_type"], '%s', conditions),
""" %(date_field, qty_field, qty_field, qty_field, filters["doc_type"], filters["doc_type"], '%s', conditions),
tuple([filters["doc_type"]] + values), as_dict=1)
return entries

View File

@@ -40,7 +40,7 @@ class AuthorizationControl(TransactionBase):
chk = 1
add_cond1,add_cond2 = '',''
if based_on == 'Itemwise Discount':
add_cond1 += " and master_name = '"+cstr(item).replace("'", "\\'")+"'"
add_cond1 += " and master_name = '"+frappe.db.escape(cstr(item))+"'"
itemwise_exists = frappe.db.sql("""select value from `tabAuthorization Rule`
where transaction = %s and value <= %s
and based_on = %s and company = %s and docstatus != 2 %s %s""" %

View File

@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe, unittest
from frappe.utils import flt
from erpnext.setup.utils import get_exchange_rate
test_records = frappe.get_test_records('Currency Exchange')
@@ -44,7 +45,7 @@ class TestCurrencyExchange(unittest.TestCase):
# Start with allow_stale is True
exchange_rate = get_exchange_rate("USD", "INR", "2016-01-01")
self.assertEqual(exchange_rate, 60.0)
self.assertEqual(flt(exchange_rate, 3), 60.0)
exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15")
self.assertEqual(exchange_rate, 65.1)
@@ -56,7 +57,7 @@ class TestCurrencyExchange(unittest.TestCase):
self.clear_cache()
exchange_rate = get_exchange_rate("USD", "INR", "2015-12-15")
self.assertFalse(exchange_rate == 60)
self.assertEqual(exchange_rate, 66.894)
self.assertEqual(flt(exchange_rate, 3), 66.894)
def test_exchange_rate_strict(self):
# strict currency settings
@@ -69,7 +70,7 @@ class TestCurrencyExchange(unittest.TestCase):
# Will fetch from fixer.io
self.clear_cache()
exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15")
self.assertEqual(exchange_rate, 67.79)
self.assertEqual(flt(exchange_rate, 3), 67.79)
exchange_rate = get_exchange_rate("USD", "INR", "2016-01-30")
self.assertEqual(exchange_rate, 62.9)
@@ -77,7 +78,7 @@ class TestCurrencyExchange(unittest.TestCase):
# Exchange rate as on 15th Dec, 2015, should be fetched from fixer.io
self.clear_cache()
exchange_rate = get_exchange_rate("USD", "INR", "2015-12-15")
self.assertEqual(exchange_rate, 66.894)
self.assertEqual(flt(exchange_rate, 3), 66.894)
exchange_rate = get_exchange_rate("INR", "NGN", "2016-01-10")
self.assertEqual(exchange_rate, 65.1)
@@ -100,4 +101,4 @@ class TestCurrencyExchange(unittest.TestCase):
# Will fetch from fixer.io
self.clear_cache()
exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15")
self.assertEqual(exchange_rate, 67.79)
self.assertEqual(flt(exchange_rate, 3), 67.79)

View File

@@ -417,8 +417,9 @@ class EmailDigest(Document):
value, count, billed_value, delivered_value = frappe.db.sql("""select ifnull(sum(grand_total),0), count(*),
ifnull(sum(grand_total*per_billed/100),0), ifnull(sum(grand_total*{0}/100),0) from `tab{1}`
where (transaction_date <= %(to_date)s)
and status not in ('Closed','Cancelled', 'Completed') """.format(getfield, doc_type),
{"to_date": self.future_to_date})[0]
and status not in ('Closed','Cancelled', 'Completed')
and company = %(company)s """.format(getfield, doc_type),
{"to_date": self.future_to_date, "company": self.company})[0]
return {
"label": self.meta.get_label(fieldname),
@@ -432,11 +433,13 @@ class EmailDigest(Document):
value, count = frappe.db.sql("""select ifnull(sum(grand_total),0), count(*) from `tabQuotation`
where (transaction_date <= %(to_date)s)
and status not in ('Ordered','Cancelled', 'Lost') """,{"to_date": self.future_to_date})[0]
and company = %(company)s
and status not in ('Ordered','Cancelled', 'Lost') """,{"to_date": self.future_to_date, "company": self.company})[0]
last_value = frappe.db.sql("""select ifnull(sum(grand_total),0) from `tabQuotation`
where (transaction_date <= %(to_date)s)
and status not in ('Ordered','Cancelled', 'Lost') """,{"to_date": self.past_to_date})[0][0]
and company = %(company)s
and status not in ('Ordered','Cancelled', 'Lost') """,{"to_date": self.past_to_date, "company": self.company})[0][0]
return {
"label": self.meta.get_label(fieldname),
@@ -462,8 +465,9 @@ class EmailDigest(Document):
def get_total_on(self, doc_type, from_date, to_date):
return frappe.db.sql("""select ifnull(sum(grand_total),0), count(*) from `tab{0}`
where (transaction_date between %(from_date)s and %(to_date)s) and status not in ('Cancelled')""".format(doc_type),
{"from_date": from_date, "to_date": to_date})[0]
where (transaction_date between %(from_date)s and %(to_date)s) and company=%(company)s
and status not in ('Cancelled')""".format(doc_type),
{"from_date": from_date, "to_date": to_date, "company": self.company})[0]
def get_from_to_date(self):
today = now_datetime().date()

View File

@@ -95,7 +95,7 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None):
if not value:
import requests
api_url = "http://api.fixer.io/{0}".format(transaction_date)
api_url = "https://exchangeratesapi.io/api/{0}".format(transaction_date)
response = requests.get(api_url, params={
"base": from_currency,
"symbols": to_currency

View File

@@ -1253,7 +1253,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3157,6 +3157,36 @@
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "group_same_items",
"fieldtype": "Check",
"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": "Group same items",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -3701,7 +3731,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2018-03-13 15:35:02.234116",
"modified": "2018-07-06 03:03:35.035396",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",

View File

@@ -82,6 +82,8 @@ class DeliveryNote(SellingController):
for f in fieldname:
toggle_print_hide(self.meta if key == "parent" else item_meta, f)
super(DeliveryNote, self).before_print()
def set_actual_qty(self):
for d in self.get('items'):
if d.item_code and d.warehouse:

View File

@@ -501,7 +501,7 @@ class Item(WebsiteGenerator):
def update_item_price(self):
frappe.db.sql("""update `tabItem Price` set item_name=%s,
item_description=%s, modified=NOW() where item_code=%s""",
item_description=%s where item_code=%s""",
(self.item_name, self.description, self.name))
def on_trash(self):

View File

@@ -294,7 +294,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -716,7 +716,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-10-05 18:24:17.148782",
"modified": "2018-07-06 18:24:17.148782",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request",

View File

@@ -417,6 +417,7 @@ def raise_production_orders(material_request):
prod_order.material_request_item = d.name
prod_order.planned_start_date = mr.transaction_date
prod_order.company = mr.company
prod_order.set_production_order_operations()
prod_order.save()
production_orders.append(prod_order.name)
else:

View File

@@ -7,7 +7,7 @@ def get_data():
'transactions': [
{
'label': _('Related'),
'items': ['Request for Quotation', 'Supplier Quotation', 'Purchase Order']
'items': ['Request for Quotation', 'Supplier Quotation', 'Purchase Order', "Stock Entry"]
},
{
'label': _('Manufacturing'),

View File

@@ -6,10 +6,12 @@
from __future__ import unicode_literals
import frappe
from erpnext.controllers.print_settings import print_settings_for_item_table
from frappe.model.document import Document
class MaterialRequestItem(Document):
pass
def __setup__(self):
print_settings_for_item_table(self)
def on_doctype_update():
frappe.db.add_index("Material Request Item", ["item_code", "warehouse"])

View File

@@ -49,7 +49,8 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip
pi.qty = flt(qty)
pi.description = description
if not pi.warehouse:
pi.warehouse = item.default_warehouse or main_item_row.warehouse
pi.warehouse = (main_item_row.warehouse
if (doc.get('is_pos') or not item.default_warehouse) else item.default_warehouse)
if not pi.batch_no:
pi.batch_no = cstr(main_item_row.get("batch_no"))
if not pi.target_warehouse:

View File

@@ -88,6 +88,7 @@
"label": "Item Name",
"length": 0,
"no_copy": 0,
"options": "item_code.item_name",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -435,7 +436,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-02-20 13:30:26.818408",
"modified": "2018-06-01 07:21:58.220980",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packing Slip Item",

View File

@@ -1038,7 +1038,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2978,10 +2978,69 @@
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "group_same_items",
"fieldtype": "Check",
"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": "Group same items",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_97",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "other_details",
"fieldtype": "HTML",
"hidden": 1,
@@ -3242,7 +3301,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-11-29 14:15:10.309900",
"modified": "2018-07-06 02:59:59.609643",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",

View File

@@ -120,6 +120,8 @@ class PurchaseReceipt(BuyingController):
self.update_prevdoc_status()
if self.per_billed < 100:
self.update_billing_status()
else:
self.status = "Completed"
# Updating stock ledger should always be called after updating prevdoc status,
# because updating ordered qty, reserved_qty_for_subcontract in bin

View File

@@ -263,7 +263,7 @@ class StockEntry(StockController):
d.actual_qty = previous_sle.get("qty_after_transaction") or 0
# validate qty during submit
if d.docstatus==1 and d.s_warehouse and not allow_negative_stock and d.actual_qty < d.transfer_qty:
if d.docstatus==1 and d.s_warehouse and not allow_negative_stock and flt(d.actual_qty, d.precision("actual_qty")) < flt(d.transfer_qty, d.precision("actual_qty")):
frappe.throw(_("Row {0}: Qty not available for {4} in warehouse {1} at posting time of the entry ({2} {3})").format(d.idx,
frappe.bold(d.s_warehouse), formatdate(self.posting_date),
format_time(self.posting_time), frappe.bold(d.item_code))

View File

@@ -77,8 +77,8 @@ class StockLedgerEntry(Document):
elif not frappe.db.get_value("Batch",{"item": self.item_code, "name": self.batch_no}):
frappe.throw(_("{0} is not a valid Batch Number for Item {1}").format(self.batch_no, self.item_code))
elif item_det.has_batch_no ==0 and self.batch_no:
frappe.throw(_("The Item {0} cannot have Batch").format(self.item_code))
elif item_det.has_batch_no ==0 and self.batch_no and self.is_cancelled == "No":
frappe.throw(_("The Item {0} cannot have Batch").format(self.item_code))
if item_det.has_variants:
frappe.throw(_("Stock cannot exist for Item {0} since has variants").format(self.item_code),

View File

@@ -39,6 +39,8 @@ frappe.ui.form.on("Warehouse", {
frm.toggle_enable(['is_group', 'company'], false);
frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Warehouse'};
frm.fields_dict['parent_warehouse'].get_query = function(doc) {
return {
filters: {

View File

@@ -14,6 +14,19 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = {
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.datetime.get_today()
},
{
"fieldname":"item_group",
"label": __("Item Group"),
"fieldtype": "Link",
"options": "Item Group",
"reqd": 1
},
{
"fieldname":"brand",
"label": __("Brand"),
"fieldtype": "Link",
"options": "Brand"
}
]
}

View File

@@ -10,7 +10,7 @@ def execute(filters=None):
if not filters: filters = {}
float_preceision = frappe.db.get_default("float_preceision")
condition =get_condition(filters)
condition = get_condition(filters)
avg_daily_outgoing = 0
diff = ((getdate(filters.get("to_date")) - getdate(filters.get("from_date"))).days)+1
@@ -18,7 +18,7 @@ def execute(filters=None):
frappe.throw(_("'From Date' must be after 'To Date'"))
columns = get_columns()
items = get_item_info()
items = get_item_info(filters)
consumed_item_map = get_consumed_items(condition)
delivered_item_map = get_delivered_items(condition)
@@ -28,23 +28,31 @@ def execute(filters=None):
avg_daily_outgoing = flt(total_outgoing / diff, float_preceision)
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.safety_stock)
data.append([item.name, item.item_name, item.description, item.safety_stock, item.lead_time_days,
consumed_item_map.get(item.name, 0), delivered_item_map.get(item.name,0), total_outgoing,
avg_daily_outgoing, reorder_level])
data.append([item.name, item.item_name, item.item_group, item.brand, item.description,
item.safety_stock, item.lead_time_days, consumed_item_map.get(item.name, 0),
delivered_item_map.get(item.name,0), total_outgoing, avg_daily_outgoing, reorder_level])
return columns , data
def get_columns():
return[
_("Item") + ":Link/Item:120", _("Item Name") + ":Data:120", _("Description") + "::160",
_("Item") + ":Link/Item:120", _("Item Name") + ":Data:120", _("Item Group") + ":Link/Item Group:100",
_("Brand") + ":Link/Brand:100", _("Description") + "::160",
_("Safety Stock") + ":Float:160", _("Lead Time Days") + ":Float:120", _("Consumed") + ":Float:120",
_("Delivered") + ":Float:120", _("Total Outgoing") + ":Float:120", _("Avg Daily Outgoing") + ":Float:160",
_("Reorder Level") + ":Float:120"
]
def get_item_info():
return frappe.db.sql("""select name, item_name, description, safety_stock,
lead_time_days from tabItem""", as_dict=1)
def get_item_info(filters):
from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition
conditions = [get_item_group_condition(filters.get("item_group"))]
if filters.get("brand"):
conditions.append("item.brand=%(brand)s")
return frappe.db.sql("""select name, item_name, description, brand, item_group,
safety_stock, lead_time_days from `tabItem` item where {}"""
.format(" and ".join(conditions)), filters, as_dict=1)
def get_consumed_items(condition):
cn_items = frappe.db.sql("""select se_item.item_code,

View File

@@ -56,7 +56,7 @@ def get_stock_ledger_entries(filters, items):
item_conditions_sql = ''
if items:
item_conditions_sql = 'and sle.item_code in ({})'\
.format(', '.join(['"' + frappe.db.escape(i,percent=False) + '"' for i in items]))
.format(', '.join(['"' + frappe.db.escape(i) + '"' for i in items]))
return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date,
item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate,

View File

@@ -926,6 +926,37 @@
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "via_customer_portal",
"fieldtype": "Check",
"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": "Via Customer Portal",
"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,
@@ -939,7 +970,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-04-13 13:03:14.748090",
"modified": "2018-05-07 05:53:20.684275",
"modified_by": "Administrator",
"module": "Support",
"name": "Issue",

View File

@@ -17,6 +17,8 @@ class Issue(Document):
return "{0}: {1}".format(_(self.status), self.subject)
def validate(self):
if (self.get("__islocal") and self.via_customer_portal):
self.flags.create_communication = True
if not self.raised_by:
self.raised_by = frappe.session.user
self.update_status()
@@ -26,6 +28,12 @@ class Issue(Document):
from frappe.desk.form.assign_to import clear
clear(self.doctype, self.name)
def on_update(self):
# create the communication email and remove the description
if (self.flags.create_communication and self.via_customer_portal):
self.create_communication()
self.flags.communication_created = None
def set_lead_contact(self, email_id):
import email.utils
email_id = email.utils.parseaddr(email_id)[1]
@@ -53,6 +61,26 @@ class Issue(Document):
# if no date, it should be set as None and not a blank string "", as per mysql strict config
self.resolution_date = None
def create_communication(self):
communication = frappe.new_doc("Communication")
communication.update({
"communication_type": "Communication",
"communication_medium": "Email",
"sent_or_received": "Received",
"email_status": "Open",
"subject": self.subject,
"sender": self.raised_by,
"content": self.description,
"status": "Linked",
"reference_doctype": "Issue",
"reference_name": self.name
})
communication.ignore_permissions = True
communication.ignore_mandatory = True
communication.save()
self.db_set("description", "")
def get_list_context(context=None):
return {
"title": _("Issues"),

View File

@@ -18,7 +18,7 @@
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
"modified": "2017-07-25 22:49:10.762704",
"modified": "2018-05-07 05:54:22.213127",
"modified_by": "Administrator",
"module": "Support",
"name": "issues",
@@ -83,6 +83,17 @@
"max_value": 0,
"read_only": 0,
"reqd": 0
},
{
"default": "1",
"fieldname": "via_customer_portal",
"fieldtype": "Check",
"hidden": 1,
"label": "Via Customer Portal",
"max_length": 0,
"max_value": 0,
"read_only": 1,
"reqd": 0
}
]
}

View File

@@ -4,4 +4,5 @@ import frappe
def get_context(context):
# do your magic here
pass
if context.doc:
context.read_only = 1

View File

@@ -16,16 +16,16 @@
<tr>
<td>{{ item }}</td>
<td class='text-right'>
{{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, company_currency) }}
{{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, currency) }}
</td>
{% for tax_account in tax_accounts %}
{% set tax_details = taxes.get(tax_account) %}
{% if tax_details %}
<td class='text-right'>
{% if tax_details.tax_rate or not tax_details.tax_amount %}
({{ tax_details.tax_rate }}%)
({{ tax_details.tax_rate }}%)
{% endif %}
{{ frappe.utils.fmt_money(tax_details.tax_amount, None, company_currency) }}
{{ frappe.utils.fmt_money(tax_details.tax_amount / conversion_rate, None, currency) }}
</td>
{% else %}
<td></td>

View File

@@ -20,7 +20,7 @@
<div class="row transaction-subheading">
<div class="col-xs-6">
<span class="indicator {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}">
{{ _(doc.indicator_title) or _(doc.status) or _("Submitted") }}
{{ _(doc.get("status")) or _(doc.get("indicator_title")) or _("Submitted") }}
</span>
</div>
<div class="col-xs-6 text-muted text-right small">

View File

@@ -85,7 +85,7 @@ frappe.Leaderboard = Class.extend({
this.$sidebar_list.on('click', 'li', function(e) {
let $li = $(this);
let doctype = $li.find('span').html();
let doctype = $li.find('span').attr("doctype-value");
me.options.selected_company = frappe.defaults.get_default('company');
me.options.selected_doctype = doctype;
@@ -146,7 +146,6 @@ frappe.Leaderboard = Class.extend({
me.$graph_area.show().empty();
let args = {
parent: '.leaderboard-graph',
data: {
datasets: [
{
@@ -160,7 +159,7 @@ frappe.Leaderboard = Class.extend({
type: 'bar',
height: 140
};
new Chart(args);
new frappeChart.Chart('.leaderboard-graph', args);
notify(me, r, $container);
}
@@ -173,7 +172,7 @@ frappe.Leaderboard = Class.extend({
$container.find(".leaderboard-list").html(me.render_list_view(res.message));
} else {
me.$graph_area.hide();
me.message = "No items found.";
me.message = __("No items found.");
$container.find(".leaderboard-list").html(me.render_list_view());
}
},
@@ -280,7 +279,7 @@ frappe.Leaderboard = Class.extend({
fields.map(col => {
let val = item[col];
if(col=="name") {
var formatted_value = `<a class="grey list-id ellipsis"
var formatted_value = `<a class="grey list-id ellipsis"
href="#Form/${me.options.selected_doctype}/${item["name"]}"> ${val} </a>`
} else {
var formatted_value = `<span class="text-muted ellipsis">
@@ -302,7 +301,7 @@ frappe.Leaderboard = Class.extend({
get_sidebar_item: function(item) {
return $(`<li class="strong module-sidebar-item">
<a class="module-link">
<span>${ item }</span></a>
<span doctype-value="${item}">${ __(item) }</span></a>
</li>`);
}
});