Compare commits

..

177 Commits

Author SHA1 Message Date
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
Nabin Hait
02a40e9d7b Merge branch 'hotfix' 2018-05-05 14:33:33 +05:30
Nabin Hait
ea199f9cd9 bumped to version 10.1.30 2018-05-05 15:03:33 +06:00
Nabin Hait
161f35a687 Update sales_invoice.py 2018-05-05 14:32:31 +05:30
Nabin Hait
fcb984b294 Merge branch 'hotfix' 2018-05-05 12:13:29 +05:30
Nabin Hait
723fe8fb1b bumped to version 10.1.29 2018-05-05 12:43:29 +06:00
Ameya Shenoy
47c0c8ba49 removed bad code and made compatible with pip 10 (#13805) 2018-05-04 19:20:20 +05:30
Rohit Waghchaure
3e0a937cb8 [Fix] Tax not changes when user change the POS profile in the sales invoice 2018-05-04 19:20:20 +05:30
Jamsheer
bd63f0056a Patient medical record updation and deletion fixes (#13891) 2018-05-04 18:13:28 +05:30
Shreya Shah
55daa9cd24 fix taxable amount for same items (#13927) 2018-05-04 18:01:23 +05:30
Shreya Shah
764b9bfeba cint for Item field has_variants (#13916)
* convert none type value to int

* Fix typo
2018-05-04 17:58:36 +05:30
Nabin Hait
62b985d405 [fix] Update show_in_website in template 2018-05-04 12:21:15 +05:30
Saurabh
ed393d1025 [fix] consider user permissions in leave application calendar view (#13902)
* [fix] consider user permissions in leave application calendar view

* add hr settings to control leave calendar view

* add patch
2018-05-03 18:52:25 +05:30
Nabin Hait
ed376cacc8 Set Qty in transactions based on serial no via Stock Settings (#13897) 2018-05-03 16:24:52 +05:30
Saurabh
7461806b1c Merge pull request #13892 from codingCoffee/travis
dark magic to revive travis
2018-05-02 23:23:07 +05:30
Ameya Shenoy
bb7c5ac0f8 dark magic to revive travis
It seems that some process inside travis is using port no 9000. Hence
adding this line in the travis.yml to change common_site_config.json and
use port no 9001 for socket_io
2018-05-02 17:32:39 +05:30
Saurabh
0272fc05bf Merge branch 'hotfix' 2018-05-02 14:48:09 +05:30
Saurabh
4f6b68fef2 bumped to version 10.1.28 2018-05-02 15:18:09 +06:00
Faris Ansari
eae2ddac69 validate_conversion_rate in taxes_and_totals (#13880) 2018-05-02 12:19:30 +05:30
Prateeksha Singh
99be9d17d5 Merge pull request #13850 from netchampfaris/msgprint-to-alert
Change msgprint to alert
2018-05-01 18:52:49 +05:30
Faris Ansari
5df63e36d4 Merge branch 'hotfix' of https://github.com/frappe/erpnext into hotfix 2018-05-01 10:52:15 +05:30
Faris Ansari
bd99606a14 Change msgprint to unobtrusive alert 2018-05-01 10:52:02 +05:30
Zarrar
b0a46f397a display customer's name while printing receivable report (#13830) 2018-04-30 19:40:18 +05:30
Prateeksha Singh
53c9b63c0b Merge pull request #13842 from pratu16x7/hotfix
[fix] setup_website, fixes #11143
2018-04-30 18:21:53 +05:30
Prateeksha Singh
9b2078feab [fix] setup_website, fixes #11143 2018-04-30 18:11:20 +05:30
Faris Ansari
30304e68ff [fix] Current stock qty calculation in case of different UOM 2018-04-30 15:44:49 +05:30
Zarrar
6bc500bffa [Minor] Validate dates in Salary Structure (#13807)
* validate date

* fix date trigger issue
2018-04-30 11:14:09 +05:30
Faris Ansari
8be895091e Set is_pos to 0 in Opening Invoice Tool (#13810) 2018-04-30 11:13:06 +05:30
Ameya Shenoy
f5f8a1f288 i still don't know why we're still using travis (#13817) 2018-04-30 11:10:39 +05:30
Gaurav Naik
c925a38f79 Ignore mandatory for default warehouses (#13812) 2018-04-27 15:31:11 +05:30
Prateeksha Singh
c23230faea Merge pull request #13786 from pratu16x7/hotfix
[fix] featured product thumbnail
2018-04-25 13:04:19 +05:30
Prateeksha Singh
6855b87f76 [fix] featured product thumbnail 2018-04-25 13:03:11 +05:30
Saurabh
07d030208f Merge branch 'hotfix' 2018-04-25 12:46:48 +05:30
Saurabh
47f6e32920 bumped to version 10.1.27 2018-04-25 13:16:48 +06:00
Saurabh
7bd1453f8f Merge pull request #13785 from rohitwaghchaure/fix_patch_pos_taxes
[Fix] POS Patch
2018-04-25 12:44:20 +05:30
Rohit Waghchaure
bf416cfbf8 [Fix] POS Patch 2018-04-25 12:32:22 +05:30
Saurabh
67918fff32 Merge branch 'hotfix' 2018-04-25 11:31:48 +05:30
Saurabh
132dac9712 bumped to version 10.1.26 2018-04-25 12:01:48 +06:00
rohitwaghchaure
57914f140e [HotFix] Taxes not adding in POS sales invoice (#13776) 2018-04-24 19:19:47 +05:30
Saurabh
ede0af97cd Merge branch 'hotfix' 2018-04-24 12:09:38 +05:30
Saurabh
ad4ede0e23 bumped to version 10.1.25 2018-04-24 12:39:38 +06:00
Saurabh
cfcf9b3832 Merge pull request #13772 from saurabh6790/supp_240418
typo fix
2018-04-24 12:08:38 +05:30
Saurabh
d2065ce3bf typo fix 2018-04-24 12:07:37 +05:30
Rohit Waghchaure
31edddace6 [Fix] Tax not changes when user change the POS profile in the sales invoice 2018-04-24 11:43:31 +05:30
Saurabh
8f29159fb7 Merge branch 'hotfix' 2018-04-24 11:12:07 +05:30
Saurabh
d9f1b539dc bumped to version 10.1.24 2018-04-24 11:42:07 +06:00
Prateeksha Singh
60bd383a25 Merge pull request #13763 from pratu16x7/hotfix
[fix] cal view start end date field discrepancies
2018-04-23 13:34:49 +05:30
Prateeksha Singh
c0ec3c3f7b [fix] cal view start end date field discrepancies 2018-04-23 13:32:59 +05:30
Manas Solanki
60aa1170d5 Merge pull request #13762 from manassolanki/fix-patient-appointment
fixed the gantt view of patient appointment
2018-04-23 12:39:28 +05:30
Manas Solanki
9630aa3d7f fixed the gantt view of patient appointment 2018-04-23 12:37:11 +05:30
Manas Solanki
aa6576c0ea Merge pull request #13755 from Zlash65/typo
[Minor] Typo fix in Leaderboard
2018-04-23 11:09:18 +05:30
Zlash65
fa5ecb066e typo fix in leaderboard 2018-04-22 12:11:01 +05:30
Nabin Hait
c36524ec54 Update chart_of_accounts.py 2018-04-20 11:00:20 +05:30
Saurabh
cba3570cf6 Merge pull request #13734 from rohitwaghchaure/pos_special_character_item_issue
[Fix] Item with special character not adding in the POS cart
2018-04-19 15:58:35 +05:30
Saurabh
5b7503c074 Merge pull request #13691 from saurabh6790/supp_180417_1
[hotfix] multiple fixes
2018-04-19 15:57:35 +05:30
Rohit Waghchaure
8441dd9184 [Fix] Item with special character not adding in the POS cart 2018-04-19 12:55:06 +05:30
Julian Robbins
78869f1e77 Update manual-feedback-request.md (#13709)
Changed wording to reflect current wording of Feedback Request rather than 'Ask a Feedback'
2018-04-18 03:12:30 -08:00
Rushabh Mehta
ff8f1bc88e Revert "removed bad code and made compatible with pip 10 (#13685)" (#13713)
This reverts commit 91b0dce4d8.
2018-04-18 02:57:44 -08:00
Ameya Shenoy
91b0dce4d8 removed bad code and made compatible with pip 10 (#13685) 2018-04-18 02:57:04 -08:00
Zarrar
59f7b8c4a1 issue routing to report (#13710) 2018-04-18 02:56:02 -08:00
Saurabh
2476a8aab9 a[fix] check content before making in condition 2018-04-17 20:45:06 +05:30
Saurabh
46ffbb74ff fix cheque print measurements 2018-04-17 20:44:37 +05:30
Saurabh
492aff2a8b [fix] check if academic_year exists (#13665) 2018-04-17 14:21:40 +05:30
Saurabh
c3fbc04aab Merge branch 'hotfix' 2018-04-17 12:00:19 +05:30
Saurabh
5b866db6bc bumped to version 10.1.23 2018-04-17 12:30:19 +06:00
Saurabh
9fbb8192e1 [fix] do not escape % while using clause (#13677) 2018-04-17 11:56:46 +05:30
Saurabh
ea1408f2e0 [fix] enqueue salary slip print email after completing accounting entries (#13633) 2018-04-15 21:38:49 -08:00
Saurabh
f2a941b1a4 [fix] check if supplier value exists (#13616) 2018-04-15 21:37:14 -08:00
110 changed files with 1340 additions and 329 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

@@ -11,6 +11,7 @@ install:
- pip install flake8==3.3.0
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
- sudo rm /etc/apt/sources.list.d/docker.list
- sudo apt-get install hhvm && rm -rf /home/travis/.kiex/
- sudo apt-get purge -y mysql-common mysql-server mysql-client
- nvm install v7.10.0
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
@@ -32,6 +33,7 @@ before_script:
- bench reinstall --yes
- bench build
- bench scheduler disable
- sed -i 's/9000/9001/g' sites/common_site_config.json
- bench start &
- sleep 10

View File

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

View File

@@ -71,7 +71,7 @@ frappe.treeview_settings["Account"] = {
// financial statements
for (let report of ['Trial Balance', 'General Ledger', 'Balance Sheet',
'Profit and Loss', 'Cash Flow Statement', 'Accounts Payable', 'Accounts Receivable']) {
'Profit and Loss Statement', 'Cash Flow Statement', 'Accounts Payable', 'Accounts Receivable']) {
treeview.page.add_inner_button(__(report), function() {
frappe.set_route('query-report', report, {company: get_company()});
}, __('Financial Statements'));

View File

@@ -165,7 +165,7 @@ def build_account_tree(tree, parent, all_accounts):
tree[child.account_name] = {}
# assign account_type and root_type
if child.account_type:
if child.account_number:
tree[child.account_name]["account_number"] = child.account_number
if child.account_type:
tree[child.account_name]["account_type"] = child.account_type
@@ -175,4 +175,4 @@ def build_account_tree(tree, parent, all_accounts):
tree[child.account_name]["root_type"] = child.root_type
# call recursively to build a subtree for current account
build_account_tree(tree[child.account_name], child, all_accounts)
build_account_tree(tree[child.account_name], child, all_accounts)

View File

@@ -27,22 +27,32 @@ 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)s }}cm; left: {{ %(acc_pay_dist_from_left_edge)s }}cm;
border-bottom: solid 1px;border-top:solid 1px; position: absolute;">
<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; width:2cm;text-align: center; position: absolute;">
%(message_to_show)s
</span>
<span style="top:%(date_dist_from_top_edge)s cm; left:%(date_dist_from_left_edge)scm;
<span style="top:%(date_dist_from_top_edge)scm; left:%(date_dist_from_left_edge)scm;
position: absolute;">
{{ 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

@@ -82,7 +82,7 @@ class JournalEntry(AccountsController):
d.reference_type = ''
d.reference_name = ''
d.db_update()
def unlink_asset_reference(self):
for d in self.get("accounts"):
if d.reference_type=="Asset" and d.reference_name:
@@ -125,7 +125,7 @@ class JournalEntry(AccountsController):
if (d.party_type == 'Customer' and flt(d.credit) > 0) or \
(d.party_type == 'Supplier' and flt(d.debit) > 0):
if d.is_advance=="No":
msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account))
msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account), alert=1)
elif d.reference_type in ("Sales Order", "Purchase Order") and d.is_advance != "Yes":
frappe.throw(_("Row {0}: Payment against Sales/Purchase Order should always be marked as advance").format(d.idx))

View File

@@ -138,7 +138,8 @@ class OpeningInvoiceCreationTool(Document):
income_expense_account_field = "expense_account"
item = get_item_dict()
return frappe._dict({
args = frappe._dict({
"items": [item],
"is_opening": "Yes",
"set_posting_time": 1,
@@ -150,6 +151,11 @@ class OpeningInvoiceCreationTool(Document):
"currency": frappe.db.get_value("Company", self.company, "default_currency")
})
if self.invoice_type == "Sales":
args["is_pos"] = 0
return args
@frappe.whitelist()
def get_temporary_opening_account(company=None):
if not company:

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)
@@ -828,6 +832,11 @@ frappe.ui.form.on('Payment Entry Reference', {
$.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();
}
}

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

@@ -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-05-28 02:38:40.310899",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -319,6 +319,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
},
pos_profile: function() {
this.frm.doc.taxes = []
this.set_pos_data();
},

View File

@@ -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-05-28 04:47:29.879475",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -39,18 +39,20 @@ frappe.ui.form.on("Tax Rule", "customer", function(frm) {
});
frappe.ui.form.on("Tax Rule", "supplier", function(frm) {
frappe.call({
method:"erpnext.accounts.doctype.tax_rule.tax_rule.get_party_details",
args: {
"party": frm.doc.supplier,
"party_type": "supplier"
},
callback: function(r) {
if(!r.exc) {
$.each(r.message, function(k, v) {
frm.set_value(k, v);
});
if(frm.doc.supplier) {
frappe.call({
method:"erpnext.accounts.doctype.tax_rule.tax_rule.get_party_details",
args: {
"party": frm.doc.supplier,
"party_type": "supplier"
},
callback: function(r) {
if(!r.exc) {
$.each(r.message, function(k, v) {
frm.set_value(k, v);
});
}
}
}
});
});
}
});

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

@@ -19,7 +19,13 @@
<h2 class="text-center">{%= __(report.report_name) %}</h2>
<h4 class="text-center">{%= filters.customer || filters.supplier %} </h4>
<h4 class="text-center">
{% if (filters.customer_name) { %}
{%= filters.customer_name %}
{% } else { %}
{%= filters.customer || filters.supplier %}
{% } %}
</h4>
<h6 class="text-center">
{% if (filters.tax_id) { %}
{%= __("Tax Id: ")%} {%= filters.tax_id %}

View File

@@ -17,8 +17,9 @@ frappe.query_reports["Accounts Receivable"] = {
"options": "Customer",
on_change: () => {
var customer = frappe.query_report_filters_by_name.customer.get_value();
frappe.db.get_value('Customer', customer, "tax_id", function(value) {
frappe.db.get_value('Customer', customer, ["tax_id", "customer_name"], function(value) {
frappe.query_report_filters_by_name.tax_id.set_value(value["tax_id"]);
frappe.query_report_filters_by_name.customer_name.set_value(value["customer_name"]);
});
}
},
@@ -81,6 +82,12 @@ frappe.query_reports["Accounts Receivable"] = {
"label": __("Tax Id"),
"fieldtype": "Data",
"hidden": 1
},
{
"fieldname":"customer_name",
"label": __("Customer Name"),
"fieldtype": "Data",
"hidden": 1
}
],

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

@@ -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

@@ -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

@@ -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-05-28 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()
@@ -232,7 +233,7 @@ class AccountsController(TransactionBase):
tax_master_doctype = self.meta.get_field("taxes_and_charges").options
if self.is_new() and not self.get("taxes"):
if (self.is_new() or self.is_pos_profile_changed()) and not self.get("taxes"):
if self.company and not self.get("taxes_and_charges"):
# get the default tax master
self.taxes_and_charges = frappe.db.get_value(tax_master_doctype,
@@ -240,6 +241,11 @@ class AccountsController(TransactionBase):
self.append_taxes_from_master(tax_master_doctype)
def is_pos_profile_changed(self):
if (self.doctype == 'Sales Invoice' and self.is_pos and
self.pos_profile != frappe.db.get_value('Sales Invoice', self.name, 'pos_profile')):
return True
def append_taxes_from_master(self, tax_master_doctype=None):
if self.get("taxes_and_charges"):
if not tax_master_doctype:
@@ -658,6 +664,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

@@ -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

@@ -83,15 +83,15 @@ def validate_returned_items(doc):
else:
ref = valid_items.get(d.item_code, frappe._dict())
validate_quantity(doc, d, ref, valid_items, already_returned_items)
if ref.rate and doc.doctype in ("Delivery Note", "Sales Invoice") and flt(d.rate) > ref.rate:
frappe.throw(_("Row # {0}: Rate cannot be greater than the rate used in {1} {2}")
.format(d.idx, doc.doctype, doc.return_against))
elif ref.batch_no and d.batch_no not in ref.batch_no:
frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}")
.format(d.idx, doc.doctype, doc.return_against))
elif ref.serial_no:
if not d.serial_no:
frappe.throw(_("Row # {0}: Serial No is mandatory").format(d.idx))
@@ -120,25 +120,30 @@ def validate_quantity(doc, args, ref, valid_items, already_returned_items):
for column in fields:
returned_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0
reference_qty = (ref.get(column) if column == 'stock_qty'
else ref.get(column) * ref.get("conversion_factor", 1.0))
if column == 'stock_qty':
reference_qty = ref.get(column)
current_stock_qty = args.get(column)
else:
reference_qty = ref.get(column) * ref.get("conversion_factor", 1.0)
current_stock_qty = args.get(column) * args.get("conversion_factor", 1.0)
max_returnable_qty = flt(reference_qty) - returned_qty
label = column.replace('_', ' ').title()
if reference_qty:
if reference_qty:
if flt(args.get(column)) > 0:
frappe.throw(_("{0} must be negative in return document").format(label))
elif returned_qty >= reference_qty and args.get(column):
frappe.throw(_("Item {0} has already been returned")
.format(args.item_code), StockOverReturnError)
elif (abs(args.get(column)) * args.get("conversion_factor", 1.0)) > max_returnable_qty:
elif abs(current_stock_qty) > max_returnable_qty:
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
.format(args.idx, reference_qty, args.item_code), StockOverReturnError)
def get_ref_item_dict(valid_items, ref_item_row):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
valid_items.setdefault(ref_item_row.item_code, frappe._dict({
"qty": 0,
"rate": 0,
@@ -160,10 +165,10 @@ def get_ref_item_dict(valid_items, ref_item_row):
if ref_item_row.get("serial_no"):
item_dict["serial_no"] += get_serial_nos(ref_item_row.serial_no)
if ref_item_row.get("batch_no"):
item_dict["batch_no"].append(ref_item_row.batch_no)
return valid_items
def get_already_returned_items(doc):

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

@@ -29,6 +29,7 @@ class calculate_taxes_and_totals(object):
self.set_item_wise_tax_breakup()
def _calculate(self):
self.validate_conversion_rate()
self.calculate_item_values()
self.initialize_taxes()
self.determine_exclusive_rate()
@@ -37,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
@@ -327,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():
@@ -557,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
)
)
@@ -590,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

@@ -4,7 +4,7 @@ We can also send the feedback request to Customer/User without configuring the
Feedback Trigger.
To request a feedback manually go to respective document e.g. Sales Order, Issue etc.
and click on Ask a Feedback option in Menu.
and click on Request Feedback option in Menu.
<img class="screenshot" alt="Setting Condition" src="/docs/assets/img/setup/feedback/manual-feedback-request-option.png">

View File

@@ -82,36 +82,39 @@ frappe.ui.form.on("Student Group", {
max_roll_no = d.group_roll_number;
}
});
frappe.call({
method: "erpnext.education.doctype.student_group.student_group.get_students",
args: {
"academic_year": frm.doc.academic_year,
"academic_term": frm.doc.academic_term,
"group_based_on": frm.doc.group_based_on,
"program": frm.doc.program,
"batch" : frm.doc.batch,
"course": frm.doc.course
},
callback: function(r) {
if(r.message) {
$.each(r.message, function(i, d) {
if(!in_list(student_list, d.student)) {
var s = frm.add_child("students");
s.student = d.student;
s.student_name = d.student_name;
if (d.active === 0) {
s.active = 0;
if(frm.doc.academic_year) {
frappe.call({
method: "erpnext.education.doctype.student_group.student_group.get_students",
args: {
"academic_year": frm.doc.academic_year,
"academic_term": frm.doc.academic_term,
"group_based_on": frm.doc.group_based_on,
"program": frm.doc.program,
"batch" : frm.doc.batch,
"course": frm.doc.course
},
callback: function(r) {
if(r.message) {
$.each(r.message, function(i, d) {
if(!in_list(student_list, d.student)) {
var s = frm.add_child("students");
s.student = d.student;
s.student_name = d.student_name;
if (d.active === 0) {
s.active = 0;
}
s.group_roll_number = ++max_roll_no;
}
s.group_roll_number = ++max_roll_no;
}
});
refresh_field("students");
frm.save();
} else {
frappe.msgprint(__("Student Group is already updated."))
});
refresh_field("students");
frm.save();
} else {
frappe.msgprint(__("Student Group is already updated."))
}
}
}
})
})
}
} else {
frappe.msgprint(__("Select students manually for the Activity based Group"));
}

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
@@ -113,9 +113,11 @@ def insert_consultation_to_medical_record(doc):
def update_consultation_to_medical_record(consultation):
medical_record_id = frappe.db.sql("select name from `tabPatient Medical Record` where reference_name=%s", (consultation.name))
if(medical_record_id[0][0]):
if medical_record_id and medical_record_id[0][0]:
subject = set_subject_field(consultation)
frappe.db.set_value("Patient Medical Record", medical_record_id[0][0], "subject", subject)
else:
insert_consultation_to_medical_record(consultation)
def delete_medical_record(consultation):
frappe.db.sql("""delete from `tabPatient Medical Record` where reference_name = %s""", (consultation.name))
@@ -123,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
@@ -244,7 +244,7 @@ def insert_lab_test_to_medical_record(doc):
def delete_lab_test_from_medical_record(self):
medical_record_id = frappe.db.sql("select name from `tabPatient Medical Record` where reference_name=%s",(self.name))
if(medical_record_id[0][0]):
if medical_record_id and medical_record_id[0][0]:
frappe.delete_doc("Patient Medical Record", medical_record_id[0][0])
def create_item_line(test_code, sales_invoice):

View File

@@ -1,8 +1,8 @@
frappe.views.calendar["Patient Appointment"] = {
field_map: {
"start": "start",
"end": "end",
"start": "appointment_date",
"end": "appointment_datetime",
"id": "name",
"title": "patient",
"allDay": "allDay"

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):
@@ -27,22 +28,22 @@ def insert_vital_signs_to_medical_record(doc):
def delete_vital_signs_from_medical_record(doc):
medical_record_id = frappe.db.sql("select name from `tabPatient Medical Record` where reference_name=%s",(doc.name))
if(medical_record_id[0][0]):
if medical_record_id and medical_record_id[0][0]:
frappe.delete_doc("Patient Medical Record", medical_record_id[0][0])
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

@@ -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

@@ -3,8 +3,8 @@
frappe.views.calendar["Holiday List"] = {
field_map: {
"start": "holiday_date",
"end": "holiday_date",
"start": "from_date",
"end": "to_date",
"id": "name",
"title": "description",
"allDay": "allDay"

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -11,6 +12,7 @@
"editable_grid": 1,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -21,6 +23,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Employee Settings",
@@ -38,6 +41,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -50,6 +54,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Retirement Age",
@@ -68,6 +73,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -80,6 +86,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Employee Records to be created by",
@@ -98,6 +105,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -108,6 +116,7 @@
"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,
@@ -125,6 +134,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -136,6 +146,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Stop Birthday Reminders",
@@ -153,6 +164,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -163,6 +175,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Maintain Billing Hours and Working Hours Same on Timesheet",
@@ -181,6 +194,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -191,6 +205,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Payroll Settings",
@@ -208,6 +223,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -219,6 +235,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Include holidays in Total no. of Working Days",
@@ -236,6 +253,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -248,6 +266,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Email Salary Slip to Employee",
@@ -266,6 +285,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -276,6 +296,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Max working hours against Timesheet",
@@ -292,21 +313,81 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "leave_settings",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Leave Settings",
"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": "show_leaves_of_all_department_members_in_calendar",
"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": "Show Leaves Of All Department Members In Calendar",
"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
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-cog",
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-01-16 14:01:31.183485",
"modified_by": "anastasiadis.st00@gmail.com",
"modified": "2018-05-03 15:35:13.015466",
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",
"owner": "Administrator",
@@ -321,7 +402,6 @@
"export": 0,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -336,6 +416,7 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_order": "ASC",
"track_changes": 0,
"track_seen": 0

View File

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

View File

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

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
@@ -494,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

@@ -146,6 +146,7 @@ class PayrollEntry(Document):
ss_list = self.get_sal_slip_list(ss_status=0)
submitted_ss = []
not_submitted_ss = []
frappe.flags.via_payroll_entry = True
for ss in ss_list:
ss_obj = frappe.get_doc("Salary Slip",ss[0])
ss_dict = {}
@@ -159,7 +160,7 @@ class PayrollEntry(Document):
else:
try:
ss_obj.submit()
submitted_ss.append(ss_dict)
submitted_ss.append(ss_obj)
except frappe.ValidationError:
not_submitted_ss.append(ss_dict)
@@ -168,8 +169,15 @@ class PayrollEntry(Document):
frappe.msgprint(_("Salary Slip submitted for period from {0} to {1}")
.format(ss_obj.start_date, ss_obj.end_date))
self.email_salary_slip(submitted_ss)
return create_submit_log(submitted_ss, not_submitted_ss, jv_name)
def email_salary_slip(self, submitted_ss):
if frappe.db.get_single_value("HR Settings", "email_salary_slip_to_employee"):
for ss in submitted_ss:
ss.email_salary_slip()
def get_loan_details(self):
"""
Get loan details from submitted salary slip based on selected criteria

View File

@@ -29,9 +29,10 @@ frappe.ui.form.on("Salary Slip", {
})
},
start_date: function(frm){
start_date: function(frm, dt, dn){
if(frm.doc.start_date){
frm.trigger("set_end_date");
get_emp_and_leave_details(frm.doc, dt, dn);
}
},
@@ -65,18 +66,20 @@ frappe.ui.form.on("Salary Slip", {
cur_frm.fields_dict['deductions'].grid.set_column_disp(salary_detail_fields,false);
},
salary_slip_based_on_timesheet: function(frm) {
salary_slip_based_on_timesheet: function(frm, dt, dn) {
frm.trigger("toggle_fields");
frm.set_value('start_date', '');
get_emp_and_leave_details(frm.doc, dt, dn);
},
payroll_frequency: function(frm) {
payroll_frequency: function(frm, dt, dn) {
frm.trigger("toggle_fields");
frm.set_value('end_date', '');
frm.set_value('start_date', '');
get_emp_and_leave_details(frm.doc, dt, dn);
},
employee: function(frm){
frm.set_value('start_date', '');
employee: function(frm, dt, dn) {
get_emp_and_leave_details(frm.doc, dt, dn);
},
toggle_fields: function(frm) {
@@ -109,7 +112,7 @@ frappe.ui.form.on('Salary Slip Timesheet', {
// Get leave details
//---------------------------------------------------------------------
cur_frm.cscript.start_date = function(doc, dt, dn){
var get_emp_and_leave_details = function(doc, dt, dn) {
if(!doc.start_date){
return frappe.call({
method: 'get_emp_and_leave_details',
@@ -122,11 +125,9 @@ cur_frm.cscript.start_date = function(doc, dt, dn){
}
}
cur_frm.cscript.payroll_frequency = cur_frm.cscript.salary_slip_based_on_timesheet = cur_frm.cscript.start_date;
cur_frm.cscript.employee = function(doc,dt,dn){
doc.salary_structure = ''
cur_frm.cscript.start_date(doc, dt, dn)
get_emp_and_leave_details(doc, dt, dn);
}
cur_frm.cscript.leave_without_pay = function(doc,dt,dn){

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()
@@ -411,13 +415,17 @@ class SalarySlip(TransactionBase):
else:
self.set_status()
self.update_status(self.name)
if(frappe.db.get_single_value("HR Settings", "email_salary_slip_to_employee")):
if(frappe.db.get_single_value("HR Settings", "email_salary_slip_to_employee")) and not frappe.flags.via_payroll_entry:
self.email_salary_slip()
def on_cancel(self):
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

@@ -161,6 +161,28 @@ frappe.ui.form.on('Salary Structure', {
}
});
frappe.ui.form.on('Salary Structure Employee', {
from_date: function(frm, cdt, cdn) {
validate_date(frm, cdt, cdn);
},
to_date: function(frm, cdt, cdn) {
validate_date(frm, cdt, cdn);
}
});
var validate_date = function(frm, cdt, cdn) {
var doc = locals[cdt][cdn];
if(doc.to_date && doc.from_date) {
var from_date = frappe.datetime.str_to_obj(doc.from_date);
var to_date = frappe.datetime.str_to_obj(doc.to_date);
if(to_date < from_date) {
frappe.model.set_value(cdt, cdn, "to_date", "");
frappe.throw(__("From Date cannot be greater than To Date"));
}
}
}
cur_frm.cscript.amount = function(doc, cdt, cdn){
calculate_totals(doc, cdt, cdn);

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

@@ -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

@@ -64,7 +64,7 @@ class ProductionOrder(Document):
so.name, so_item.delivery_date, so.project
from
`tabSales Order` so, `tabSales Order Item` so_item, `tabPacked Item` packed_item
where so.name=%s
where so.name=%s
and so.name=so_item.parent
and so.name=packed_item.parent
and so_item.item_code = packed_item.parent_item
@@ -88,7 +88,7 @@ class ProductionOrder(Document):
self.wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse")
if not self.fg_warehouse:
self.fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse")
def validate_warehouse_belongs_to_company(self):
warehouses = [self.fg_warehouse, self.wip_warehouse]
for d in self.get("required_items"):
@@ -524,7 +524,7 @@ def get_item_details(item, project = None):
if not res["bom_no"]:
if project:
res = get_item_details(item)
frappe.msgprint(_("Default BOM not found for Item {0} and Project {1}").format(item, project))
frappe.msgprint(_("Default BOM not found for Item {0} and Project {1}").format(item, project), alert=1)
else:
frappe.throw(_("Default BOM for {0} not found").format(item))
@@ -642,5 +642,5 @@ def query_sales_order(production_item):
select distinct so.name from `tabSales Order` so, `tabPacked Item` pi_item
where pi_item.parent=so.name and pi_item.item_code=%s and so.docstatus=1
""", (production_item, production_item))
return out

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

@@ -498,4 +498,8 @@ erpnext.patches.v10_0.update_reserved_qty_for_purchase_order
erpnext.patches.v10_0.update_hub_connector_domain
erpnext.patches.v10_0.set_student_party_type
erpnext.patches.v10_0.update_project_in_sle
erpnext.patches.v10_0.fix_reserved_qty_for_sub_contract
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

@@ -0,0 +1,21 @@
# Copyright (c) 2017, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doc("stock", "doctype", "stock_settings")
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,5 @@
import frappe
def execute():
frappe.reload_doc("hr", "doctype", "hr_settings")
frappe.db.set_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar", 1)

View File

@@ -0,0 +1,26 @@
# Copyright (c) 2017, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
for d in frappe.get_all('Sales Invoice', fields=["name"],
filters = {'is_pos':1, 'docstatus': 1, 'creation': ('>', '2018-04-23')}):
doc = frappe.get_doc('Sales Invoice', d.name)
if (not doc.taxes and doc.taxes_and_charges and doc.pos_profile and doc.outstanding_amount != 0 and
frappe.db.get_value('POS Profile', doc.pos_profile, 'taxes_and_charges', cache=True) == doc.taxes_and_charges):
doc.append_taxes_from_master()
doc.calculate_taxes_and_totals()
for d in doc.taxes:
d.db_update()
doc.db_update()
delete_gle_for_voucher(doc.name)
doc.make_gl_entries(repost_future_gle=False)
def delete_gle_for_voucher(voucher_no):
frappe.db.sql("""delete from `tabGL Entry` where voucher_no = %(voucher_no)s""",
{'voucher_no': voucher_no})

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

@@ -75,7 +75,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"))

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
@@ -401,7 +401,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
item.serial_no = valid_serial_nos.join('\n');
refresh_field("serial_no", item.name, item.parentfield);
if(!doc.is_return) {
if(!doc.is_return && cint(user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
frappe.model.set_value(item.doctype, item.name,
"qty", valid_serial_nos.length / item.conversion_factor);
frappe.model.set_value(item.doctype, item.name, "stock_qty", valid_serial_nos.length);
@@ -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,7 +144,10 @@ class Gstr1Report(object):
""" % (self.doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1)
for d in items:
self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, d.base_net_amount)
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

@@ -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

@@ -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-05-28 03:23:15.354674",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
"owner": "Administrator",

View File

@@ -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

@@ -774,7 +774,7 @@ class POSCart {
});
this.numpad.reset_value();
} else {
const item_code = this.selected_item.attr('data-item-code');
const item_code = unescape(this.selected_item.attr('data-item-code'));
const field = this.selected_item.active_field;
const value = this.numpad.get_value();
@@ -819,7 +819,7 @@ class POSCart {
}
update_item(item) {
const $item = this.$cart_items.find(`[data-item-code="${item.item_code}"]`);
const $item = this.$cart_items.find(`[data-item-code="${escape(item.item_code)}"]`);
if(item.qty > 0) {
const is_stock_item = this.get_item_details(item.item_code).is_stock_item;
@@ -841,7 +841,7 @@ class POSCart {
const rate = format_currency(item.rate, this.frm.doc.currency);
const indicator_class = (!is_stock_item || item.actual_qty >= item.qty) ? 'green' : 'red';
return `
<div class="list-item indicator ${indicator_class}" data-item-code="${item.item_code}" title="Item: ${item.item_name} Available Qty: ${item.actual_qty}">
<div class="list-item indicator ${indicator_class}" data-item-code="${escape(item.item_code)}" title="Item: ${item.item_name} Available Qty: ${item.actual_qty}">
<div class="item-name list-item__content list-item__content--flex-1.5 ellipsis">
${item.item_name}
</div>
@@ -883,18 +883,18 @@ class POSCart {
}
exists(item_code) {
let $item = this.$cart_items.find(`[data-item-code="${item_code}"]`);
let $item = this.$cart_items.find(`[data-item-code="${escape(item_code)}"]`);
return $item.length > 0;
}
highlight_item(item_code) {
const $item = this.$cart_items.find(`[data-item-code="${item_code}"]`);
const $item = this.$cart_items.find(`[data-item-code="${escape(item_code)}"]`);
$item.addClass('highlight');
setTimeout(() => $item.removeClass('highlight'), 1000);
}
scroll_to_item(item_code) {
const $item = this.$cart_items.find(`[data-item-code="${item_code}"]`);
const $item = this.$cart_items.find(`[data-item-code="${escape(item_code)}"]`);
if ($item.length === 0) return;
const scrollTop = $item.offset().top - this.$cart_items.offset().top + this.$cart_items.scrollTop();
this.$cart_items.animate({ scrollTop });
@@ -909,7 +909,7 @@ class POSCart {
'[data-action="increment"], [data-action="decrement"]', function() {
const $btn = $(this);
const $item = $btn.closest('.list-item[data-item-code]');
const item_code = $item.attr('data-item-code');
const item_code = unescape($item.attr('data-item-code'));
const action = $btn.attr('data-action');
if(action === 'increment') {
@@ -932,7 +932,7 @@ class POSCart {
this.$cart_items.on('change', '.quantity input', function() {
const $input = $(this);
const $item = $input.closest('.list-item[data-item-code]');
const item_code = $item.attr('data-item-code');
const item_code = unescape($item.attr('data-item-code'));
events.on_field_change(item_code, 'qty', flt($input.val()));
});
@@ -1200,7 +1200,7 @@ class POSItems {
var me = this;
this.wrapper.on('click', '.pos-item-wrapper', function() {
const $item = $(this);
const item_code = $item.attr('data-item-code');
const item_code = unescape($item.attr('data-item-code'));
me.events.update_cart(item_code, 'qty', '+1');
});
}
@@ -1226,7 +1226,7 @@ class POSItems {
const item_title = item_name || item_code;
const template = `
<div class="pos-item-wrapper image-view-item" data-item-code="${item_code}">
<div class="pos-item-wrapper image-view-item" data-item-code="${escape(item_code)}">
<div class="image-view-header">
<div>
<a class="grey list-id" data-name="${item_code}" title="${item_title}">

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

@@ -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:
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

@@ -122,6 +122,7 @@ class Company(Document):
if not wh_detail["is_group"] else ""
})
warehouse.flags.ignore_permissions = True
warehouse.flags.ignore_mandatory = True
warehouse.insert()
def create_default_accounts(self):

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

@@ -113,8 +113,7 @@ def create_logo(args):
"<img src='{0}' style='max-width: 40px; max-height: 25px;'> {1}".format(fileurl, args.get("company_name") ))
def create_website(args):
if args.get('setup_website'):
website_maker(args)
website_maker(args)
def get_fy_details(fy_start_date, fy_end_date):
start_year = getdate(fy_start_date).year

View File

@@ -12,7 +12,7 @@ class website_maker(object):
self.args = args
self.company = args.company_name
self.tagline = args.company_tagline
self.user = args.name
self.user = args.get('email')
self.make_web_page()
self.make_website_settings()
self.make_blog()
@@ -50,6 +50,17 @@ class website_maker(object):
website_settings.save()
def make_blog(self):
blog_category = frappe.get_doc({
"doctype": "Blog Category",
"category_name": "general",
"published": 1,
"title": _("General")
}).insert()
if not self.user:
# Admin setup
return
blogger = frappe.new_doc("Blogger")
user = frappe.get_doc("User", self.user)
blogger.user = self.user
@@ -58,13 +69,6 @@ class website_maker(object):
blogger.avatar = user.user_image
blogger.insert()
blog_category = frappe.get_doc({
"doctype": "Blog Category",
"category_name": "general",
"published": 1,
"title": _("General")
}).insert()
frappe.get_doc({
"doctype": "Blog Post",
"title": "Welcome",

View File

@@ -37,6 +37,7 @@ def set_default_settings(args):
stock_settings.auto_indent = 1
stock_settings.auto_insert_price_list_rate_if_missing = 1
stock_settings.automatically_set_serial_nos_based_on_fifo = 1
stock_settings.set_qty_in_transactions_based_on_serial_no_input = 1
stock_settings.save()
selling_settings = frappe.get_doc("Selling Settings")

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

@@ -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-05-28 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):
@@ -604,19 +604,20 @@ class Item(WebsiteGenerator):
def update_template_item(self):
"""Set Show in Website for Template Item if True for its Variant"""
if self.variant_of and self.show_in_website:
self.show_variant_in_website = 1
self.show_in_website = 0
if self.variant_of:
if self.show_in_website:
self.show_variant_in_website = 1
self.show_in_website = 0
if self.show_variant_in_website:
# show template
template_item = frappe.get_doc("Item", self.variant_of)
if self.show_variant_in_website:
# show template
template_item = frappe.get_doc("Item", self.variant_of)
if not template_item.show_in_website:
template_item.show_in_website = 1
template_item.flags.dont_update_variants = True
template_item.flags.ignore_permissions = True
template_item.save()
if not template_item.show_in_website:
template_item.show_in_website = 1
template_item.flags.dont_update_variants = True
template_item.flags.ignore_permissions = True
template_item.save()
def update_variants(self):
if self.flags.dont_update_variants or \
@@ -640,9 +641,9 @@ class Item(WebsiteGenerator):
def validate_stock_exists_for_template_item(self):
if self.stock_ledger_created() and self._doc_before_save:
if (self._doc_before_save.has_variants != self.has_variants
if (cint(self._doc_before_save.has_variants) != cint(self.has_variants)
or self._doc_before_save.variant_of != self.variant_of):
frappe.throw(_("Cannot change Variant properties after stock transction. You will have to make a new Item to do this.").format(self.name),
frappe.throw(_("Cannot change Variant properties after stock transaction. You will have to make a new Item to do this.").format(self.name),
StockExistsForTemplate)
if self.has_variants or self.variant_of:

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

@@ -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

@@ -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-05-28 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

@@ -198,7 +198,7 @@ def validate_serial_no(sle, item_det):
frappe.throw(_("Serial No {0} quantity {1} cannot be a fraction").format(sle.item_code, sle.actual_qty))
if len(serial_nos) and len(serial_nos) != abs(cint(sle.actual_qty)):
frappe.throw(_("{0} Serial Numbers required for Item {1}. You have provided {2}.").format(sle.actual_qty, sle.item_code, len(serial_nos)),
frappe.throw(_("{0} Serial Numbers required for Item {1}. You have provided {2}.").format(abs(sle.actual_qty), sle.item_code, len(serial_nos)),
SerialNoQtyError)
if len(serial_nos) != len(set(serial_nos)):

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

@@ -463,6 +463,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "set_qty_in_transactions_based_on_serial_no_input",
"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": "Set Qty in Transactions based on Serial No Input",
"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,
@@ -679,7 +710,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-11-17 01:35:49.562613",
"modified": "2018-05-03 12:37:12.905394",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Settings",

View File

@@ -11,8 +11,9 @@ from frappe.utils.html_utils import clean_html
class StockSettings(Document):
def validate(self):
for key in ["item_naming_by", "item_group", "stock_uom", "allow_negative_stock", "default_warehouse"]:
frappe.db.set_default(key, self.get(key, ""))
for key in ["item_naming_by", "item_group", "stock_uom",
"allow_negative_stock", "default_warehouse", "set_qty_in_transactions_based_on_serial_no_input"]:
frappe.db.set_default(key, self.get(key, ""))
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
set_by_naming_series("Item", "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,

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