Compare commits

...

117 Commits

Author SHA1 Message Date
Nabin Hait
11137850cb Merge branch 'hotfix' 2018-07-27 12:35:42 +05:30
Nabin Hait
584153a1b1 bumped to version 10.1.44 2018-07-27 13:05:42 +06:00
Shreya Shah
eed0a4e2df Do not copy remarks field while duplicating (#15023) 2018-07-27 11:26:35 +05:30
FinByz Tech Pvt. Ltd
f5cc1bd44c Created Eway Bill Report (#14926)
* Created Eway Bill Report

* Field value changes

* Changed module from Stock to Regional

* Added comments and minor fix

* minor fix
2018-07-27 11:21:42 +05:30
Yaqin Shurrab
cc56ff5c37 Get the correct Summation of Closing Balances (#14990)
Fix total raw values for Closing Credit and Closing Debit
2018-07-27 11:13:00 +05:30
rohitwaghchaure
20d3bef3c3 [Fix] Deducted tax amount adding up in the total amount in the GST Itemised Purchase Register report (#14994) 2018-07-27 11:03:53 +05:30
Shreya Shah
1f4c263a63 [minor] Program Enrollment Tool (#15013)
* Make academic term field mandatory

* Add disabled field to Student Group

* Mandatory check in Education Settings for Academic Term

* Fix as per review
2018-07-27 10:59:14 +05:30
Nabin Hait
d0a2b1619b Optimization for marking student attendance 2018-07-27 10:51:55 +05:30
rohitwaghchaure
0fe6ced99d [Fix] Valuation rate for serialized items (#15017) 2018-07-27 10:33:30 +05:30
Nabin Hait
e50e0e4b30 Update repost_reserved_qty_for_production.py 2018-07-25 17:49:47 +05:30
Shreya Shah
cd717e422f Modify renaming process of Account (#14839)
* Disable renaming for Account Master

* Update account name along with account number

* Fix as per suggestions

* Update account.js

* Fix typo

* Remove after_rename and before_rename methods

* Modify test case

* Modify field placement

* Remove unused method
2018-07-23 14:15:20 +05:30
rohitwaghchaure
6b862fcae5 [Fix] Rounded total is not working in the purchase receipt (#14984) 2018-07-23 13:02:07 +05:30
Zarrar
a22e0d0c99 return empty if no stock ledger entry found (#14968) 2018-07-23 11:31:04 +05:30
Saurabh
8ca5940f76 Merge branch 'hotfix' 2018-07-18 16:24:54 +05:30
Saurabh
6c46b4edc4 bumped to version 10.1.43 2018-07-18 16:54:54 +06:00
Shreya Shah
8395a7ad6f Modifications in last purchase rate button (#14948)
* Make last purchase rate button visible until submitted

* Move buttons

- Get last purchase rate and link to material request buttons moved to toolbar under Tools button

* Remove disable fetch last rate functionality

* Make last purchase rate field read_only
2018-07-18 12:27:27 +05:30
rohitwaghchaure
6863b03790 Naming series increase even if there is an exception while saving the invoice from the backend (#14938) 2018-07-17 17:20:15 +05:30
rohitwaghchaure
a76067eea1 [Fix] Per billed showing as 100% in the sales order even if sales return has made against the sales order (#14899)
* [Fix] Per billed showing as 100% in the sales order even if sales return has made against the sales order

* Added test cases
2018-07-17 16:50:50 +05:30
rohitwaghchaure
216f9373c9 Provision to select the cost center in the asset (#14934) 2018-07-17 16:47:51 +05:30
rohitwaghchaure
5fe88ea93e [Fix] Not able to update the current value of the prefixes which are defined in the autoname field (#14918) 2018-07-17 12:45:25 +05:30
Shreya Shah
fbeab5bf73 Show opening balance of leaves (#14925)
* Show opening balance of leaves

* Update employee_leave_balance.py
2018-07-17 11:59:51 +05:30
rohitwaghchaure
a3e070bc6b [Fix] Invoices not showing in the gross profit report against which sales return entry has created (#14914) 2018-07-16 18:11:19 +05:30
rohitwaghchaure
3ffe89659a [Fix] System always fetches the payment terms template from the company even if it's removed from the sales invoice (#14879) 2018-07-13 17:40:48 +05:30
Ameya Shenoy
5c3b69476d shift to self-hosted frankfurter api (#14792) 2018-07-13 12:46:07 +05:30
Nabin Hait
da17ceea73 patch fixes 2018-07-13 12:04:06 +05:30
rohitwaghchaure
2d84945839 [Fix] Stock reconciliation wrong difference amount calculation (#14893) 2018-07-13 11:07:27 +05:30
Shreya Shah
8dc4c945dc Fix UX (#14862) 2018-07-11 14:36:49 +05:30
rohitwaghchaure
cc9c7d5e2a [Fix] GSTIN not displaying in the address print (#14855)
* [Fix] GSTIN not displaying in the address print

* Made changes in the patch and set Patch as False

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

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

* Fix as per suggestion

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

Merge conflict for taxable value having same item

* Update gstr_1.py

* Minor Fix

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

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

* check if items are subcontractable or saleable

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

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

* add check field to group items during print

* call common before_print in delivery note

* fix precision issue while calculating average
2018-05-28 17:41:09 +05:30
rohitwaghchaure
a8c6ec27c0 Merge pull request #14252 from rohitwaghchaure/leaderboard_translation_issue
[Fix] Translation issue in leaderboard
2018-05-28 15:51:00 +05:30
Saurabh
3c1b153cdb Merge pull request #14111 from netchampfaris/stock-ledger-report-hotfix
[fix] Stock Ledger report item filter
2018-05-28 15:23:21 +05:30
Rohit Waghchaure
06f91e2dc1 [Fix] Translation issue in leaderboard 2018-05-28 14:43:17 +05:30
Shreya Shah
13f39eb821 Display rate on the basis of stock UOM (#14246) 2018-05-28 11:50:28 +05:30
rohitwaghchaure
a8fb2db001 [Fix] If two po consolidated in one purchase invoice, Total Net Weight not get summed (#14230) 2018-05-26 09:23:02 +05:30
Ranjith Kurungadam
27cf190269 healthcare fix - str encode to utf-8 (#14213) 2018-05-24 17:15:22 +05:30
Faris Ansari
9e4889d756 [fix] Stock Ledger report item filter
- breaks when Item Code contains % symbol
2018-05-17 12:18:28 +05:30
121 changed files with 2033 additions and 767 deletions

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

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

View File

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

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

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

1
.gitignore vendored
View File

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

BIN
.swp

Binary file not shown.

View File

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

View File

@@ -49,7 +49,7 @@ frappe.ui.form.on('Account', {
}
if(!frm.doc.__islocal) {
frm.add_custom_button(__('Update Account Number'), function () {
frm.add_custom_button(__('Update Account Name / Number'), function () {
frm.trigger("update_account_number");
});
}
@@ -100,18 +100,25 @@ frappe.ui.form.on('Account', {
update_account_number: function(frm) {
var d = new frappe.ui.Dialog({
title: __('Update Account Number'),
title: __('Update Account Number / Name'),
fields: [
{
"label": "Account Name",
"fieldname": "account_name",
"fieldtype": "Data",
"reqd": 1,
"default": frm.doc.account_name
},
{
"label": "Account Number",
"fieldname": "account_number",
"fieldtype": "Data",
"reqd": 1
"default": frm.doc.account_number
}
],
primary_action: function() {
var data = d.get_values();
if(data.account_number === frm.doc.account_number) {
if(data.account_number === frm.doc.account_number && data.account_name === frm.doc.account_name) {
d.hide();
return;
}
@@ -120,6 +127,7 @@ frappe.ui.form.on('Account', {
method: "erpnext.accounts.doctype.account.account.update_account_number",
args: {
account_number: data.account_number,
account_name: data.account_name,
name: frm.doc.name
},
callback: function(r) {
@@ -128,6 +136,7 @@ frappe.ui.form.on('Account', {
frappe.set_route("Form", "Account", r.message);
} else {
frm.set_value("account_number", data.account_number);
frm.set_value("account_name", data.account_name);
}
d.hide();
}
@@ -138,4 +147,4 @@ frappe.ui.form.on('Account', {
});
d.show();
}
});
});

View File

@@ -2,7 +2,7 @@
"allow_copy": 1,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"allow_rename": 0,
"beta": 0,
"creation": "2013-01-30 12:49:46",
"custom": 0,
@@ -40,6 +40,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -68,6 +69,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "50%"
},
@@ -100,6 +102,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -130,6 +133,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -161,6 +165,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -193,6 +198,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -223,6 +229,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -253,6 +260,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -285,6 +293,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -313,6 +322,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "50%"
},
@@ -346,6 +356,7 @@
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -379,6 +390,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -411,6 +423,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -444,6 +457,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -474,6 +488,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -503,6 +518,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -532,6 +548,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -561,6 +578,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@@ -575,7 +593,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-08-22 17:39:10.711343",
"modified": "2018-07-08 09:47:04.287841",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",

View File

@@ -165,53 +165,6 @@ class Account(NestedSet):
super(Account, self).on_trash(True)
def before_rename(self, old, new, merge=False):
# Add company abbr if not provided
from erpnext.setup.doctype.company.company import get_name_with_abbr
new_account = get_name_with_abbr(new, self.company)
if not merge:
new_account = get_name_with_number(new_account, self.account_number)
else:
# Validate properties before merging
if not frappe.db.exists("Account", new):
throw(_("Account {0} does not exist").format(new))
val = list(frappe.db.get_value("Account", new_account,
["is_group", "root_type", "company"]))
if val != [self.is_group, self.root_type, self.company]:
throw(_("""Merging is only possible if following properties are same in both records. Is Group, Root Type, Company"""))
if self.is_group and frappe.db.get_value("Account", new, "parent_account") == old:
frappe.db.set_value("Account", new, "parent_account",
frappe.db.get_value("Account", old, "parent_account"))
return new_account
def after_rename(self, old, new, merge=False):
super(Account, self).after_rename(old, new, merge)
if not merge:
new_acc = frappe.db.get_value("Account", new, ["account_name", "account_number"], as_dict=1)
# exclude company abbr
new_parts = new.split(" - ")[:-1]
# update account number and remove from parts
if new_parts[0][0].isdigit():
# if account number is separate by space, split using space
if len(new_parts) == 1:
new_parts = new.split(" ")
if new_acc.account_number != new_parts[0]:
self.account_number = new_parts[0]
self.db_set("account_number", new_parts[0])
new_parts = new_parts[1:]
# update account name
account_name = " - ".join(new_parts)
if new_acc.account_name != account_name:
self.account_name = account_name
self.db_set("account_name", account_name)
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select name from tabAccount
where is_group = 1 and docstatus != 2 and company = %s
@@ -252,25 +205,15 @@ def validate_account_number(name, account_number, company):
.format(account_number, account_with_same_number))
@frappe.whitelist()
def update_account_number(name, account_number):
account = frappe.db.get_value("Account", name, ["account_name", "company"], as_dict=True)
def update_account_number(name, account_name, account_number=None):
account = frappe.db.get_value("Account", name, ["company"], as_dict=True)
validate_account_number(name, account_number, account.company)
frappe.db.set_value("Account", name, "account_number", account_number)
account_name = account.account_name
if account_name[0].isdigit():
separator = " - " if " - " in account_name else " "
account_name = account_name.split(separator, 1)[1]
frappe.db.set_value("Account", name, "account_name", account_name)
if account_number:
frappe.db.set_value("Account", name, "account_number", account_number.strip())
frappe.db.set_value("Account", name, "account_name", account_name.strip())
new_name = get_account_autoname(account_number, account_name, account.company)
if name != new_name:
frappe.rename_doc("Account", name, new_name)
frappe.rename_doc("Account", name, new_name, ignore_permissions=1)
return new_name
def get_name_with_number(new_account, account_number):
if account_number and not new_account[0].isdigit():
new_account = account_number + " - " + new_account
return new_account

View File

@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import unittest
import frappe
from erpnext.stock import get_warehouse_account, get_company_default_inventory_account
from erpnext.accounts.doctype.account.account import update_account_number
class TestAccount(unittest.TestCase):
def test_rename_account(self):
@@ -21,21 +22,18 @@ class TestAccount(unittest.TestCase):
self.assertEqual(account_number, "1210")
self.assertEqual(account_name, "Debtors")
frappe.rename_doc("Account", "1210 - Debtors - _TC", "1211 - Debtors 1 - _TC")
new_account_number = "1211-11-4 - 6 - "
new_account_name = "Debtors 1 - Test - "
new_acc = frappe.db.get_value("Account", "1211 - Debtors 1 - _TC",
update_account_number("1210 - Debtors - _TC", new_account_number, new_account_name)
new_acc = frappe.db.get_value("Account", "1211-11-4 - 6 - - Debtors 1 - Test - - _TC",
["account_name", "account_number"], as_dict=1)
self.assertEqual(new_acc.account_name, "Debtors 1")
self.assertEqual(new_acc.account_number, "1211")
frappe.rename_doc("Account", "1211 - Debtors 1 - _TC", "Debtors 2")
self.assertEqual(new_acc.account_name, "Debtors 1 - Test -")
self.assertEqual(new_acc.account_number, "1211-11-4 - 6 -")
new_acc = frappe.db.get_value("Account", "1211 - Debtors 2 - _TC",
["account_name", "account_number"], as_dict=1)
self.assertEqual(new_acc.account_name, "Debtors 2")
self.assertEqual(new_acc.account_number, "1211")
frappe.delete_doc("Account", "1211 - Debtors 2 - _TC")
frappe.delete_doc("Account", "1211-11-4 - 6 - Debtors 1 - Test - - _TC")
def _make_test_records(verbose):
from frappe.test_runner import make_test_objects

View File

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

View File

@@ -40,7 +40,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -72,7 +71,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 1,
"translatable": 0,
"unique": 0
},
{
@@ -104,7 +102,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -134,7 +131,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -166,7 +162,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -198,7 +193,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -230,7 +224,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -262,7 +255,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -296,7 +288,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -329,7 +320,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -359,7 +349,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -392,7 +381,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -423,7 +411,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -455,7 +442,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -488,7 +474,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -521,7 +506,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -554,7 +538,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -584,7 +567,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -617,7 +599,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -650,7 +631,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -683,7 +663,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -716,7 +695,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -749,7 +727,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -781,7 +758,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -814,7 +790,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -844,7 +819,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -877,7 +851,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -909,7 +882,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -942,7 +914,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -975,7 +946,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1008,7 +978,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1041,7 +1010,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1073,7 +1041,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1105,7 +1072,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1138,7 +1104,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1169,7 +1134,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1199,7 +1163,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1231,7 +1194,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1264,7 +1226,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1296,7 +1257,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1329,7 +1289,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1361,7 +1320,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1392,7 +1350,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1424,7 +1381,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1454,7 +1410,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1486,7 +1441,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1518,7 +1472,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1551,7 +1504,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1584,7 +1536,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1604,7 +1555,7 @@
"in_standard_filter": 0,
"label": "Remarks",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -1615,7 +1566,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1645,7 +1595,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1677,7 +1626,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1709,7 +1657,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1740,7 +1687,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1772,7 +1718,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1803,7 +1748,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@@ -1834,7 +1778,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@@ -1848,7 +1791,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-02-19 16:58:23.899015",
"modified": "2018-07-27 01:49:24.720317",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

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

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

View File

@@ -507,5 +507,6 @@ def save_invoice(doc, name, name_list):
name_list.append(name)
except Exception:
frappe.log_error(frappe.get_traceback())
frappe.db.rollback()
return name_list

View File

@@ -639,6 +639,66 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_21",
"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,
"depends_on": "eval: doc.is_return && doc.return_against",
"fieldname": "update_billed_amount_in_sales_order",
"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": "Update Billed Amount in Sales Order",
"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,
@@ -1459,7 +1519,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3742,12 +3802,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 +3815,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 +3891,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 +4773,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2018-03-16 15:19:54.711885",
"modified": "2018-07-17 13:46:52.449142",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
@@ -4774,7 +4864,7 @@
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 1,
"search_fields": "posting_date, due_date, customer, base_grand_total, outstanding_amount",
"search_fields": "posting_date,due_date,customer,base_grand_total,outstanding_amount",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",

View File

@@ -116,7 +116,7 @@ class SalesInvoice(SellingController):
self.check_prev_docstatus()
if self.is_return:
if self.is_return and not self.update_billed_amount_in_sales_order:
# NOTE status updating bypassed for is_return
self.status_updater = []
@@ -161,7 +161,7 @@ class SalesInvoice(SellingController):
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
unlink_ref_doc_from_payment_entries(self)
if self.is_return:
if self.is_return and not self.update_billed_amount_in_sales_order:
# NOTE status updating bypassed for is_return
self.status_updater = []
@@ -318,6 +318,7 @@ class SalesInvoice(SellingController):
if not for_validate and not self.customer:
self.customer = pos.customer
self.ignore_pricing_rule = pos.ignore_pricing_rule
if pos.get('account_for_change_amount'):
self.account_for_change_amount = pos.get('account_for_change_amount')

View File

@@ -20,8 +20,8 @@ from erpnext import get_default_currency, get_company_currency
class DuplicatePartyAccountError(frappe.ValidationError): pass
@frappe.whitelist()
def get_party_details(party=None, account=None, party_type="Customer", company=None,
posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False):
def get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True):
if not party:
return {}
@@ -30,10 +30,10 @@ def get_party_details(party=None, account=None, party_type="Customer", company=N
frappe.throw(_("{0}: {1} does not exists").format(party_type, party))
return _get_party_details(party, account, party_type,
company, posting_date, price_list, currency, doctype, ignore_permissions)
company, posting_date, price_list, currency, doctype, ignore_permissions, fetch_payment_terms_template)
def _get_party_details(party=None, account=None, party_type="Customer", company=None,
posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False):
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True):
out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, doctype))
@@ -50,7 +50,9 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
set_other_values(out, party, party_type)
set_price_list(out, party, party_type, price_list)
out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_type)
out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
if fetch_payment_terms_template:
out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
if not out.get("currency"):
out["currency"] = currency
@@ -272,6 +274,7 @@ def get_due_date(posting_date, party_type, party, company=None):
if posting_date and party:
due_date = posting_date
template_name = get_pyt_term_template(party, party_type, company)
if template_name:
due_date = get_due_date_from_template(template_name, posting_date).strftime("%Y-%m-%d")
else:
@@ -304,11 +307,13 @@ def get_due_date_from_template(template_name, posting_date):
return due_date
def validate_due_date(posting_date, due_date, party_type, party, company=None):
def validate_due_date(posting_date, due_date, party_type, party, company=None, template_name=None):
if getdate(due_date) < getdate(posting_date):
frappe.throw(_("Due Date cannot be before Posting Date"))
else:
default_due_date = get_due_date(posting_date, party_type, party, company)
if not template_name: return
default_due_date = get_due_date_from_template(template_name, posting_date).strftime("%Y-%m-%d")
if not default_due_date:
return
@@ -404,10 +409,21 @@ def get_timeline_data(doctype, name):
from frappe.desk.form.load import get_communication_data
out = {}
fields = 'date(creation), count(name)'
after = add_years(None, -1).strftime('%Y-%m-%d')
group_by='group by date(creation)'
data = get_communication_data(doctype, name,
fields = 'date(creation), count(name)',
after = add_years(None, -1).strftime('%Y-%m-%d'),
group_by='group by date(creation)', as_dict=False)
fields=fields, after=after, group_by=group_by, as_dict=False)
# fetch and append data from Activity Log
data += frappe.db.sql("""select {fields}
from `tabActivity Log`
where reference_doctype="{doctype}" and reference_name="{name}"
and status!='Success' and creation > {after}
{group_by} order by creation desc
""".format(doctype=frappe.db.escape(doctype), name=frappe.db.escape(name), fields=fields,
group_by=group_by, after=after), as_dict=False)
timeline_items = dict(data)

View File

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

View File

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

View File

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

View File

@@ -171,7 +171,7 @@ class GrossProfitGenerator(object):
row.qty += returned_item_row.qty
row.base_amount += returned_item_row.base_amount
row.buying_amount = row.qty * row.buying_rate
if row.qty:
if row.qty or row.base_amount:
row = self.set_average_rate(row)
self.grouped_data.append(row)

View File

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

View File

@@ -53,7 +53,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom
]
row += [d.base_net_rate/d.stock_qty, d.base_net_amount] \
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount] \
if d.stock_uom != d.uom else [d.base_net_rate, d.base_net_amount]
total_tax = 0
@@ -133,7 +133,7 @@ def get_items(filters, additional_query_columns):
`tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate,
`tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name,
`tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom {0}
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
from `tabSales Invoice`, `tabSales Invoice Item`
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
and `tabSales Invoice`.docstatus = 1 %s %s
@@ -157,6 +157,9 @@ def get_delivery_notes_against_sales_order(item_list):
return so_dn_map
def get_deducted_taxes():
return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'")
def get_tax_accounts(item_list, columns, company_currency,
doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"):
import json
@@ -176,9 +179,10 @@ def get_tax_accounts(item_list, columns, company_currency,
if doctype == "Purchase Invoice":
conditions = " and category in ('Total', 'Valuation and Total') and base_tax_amount_after_discount_amount != 0"
deducted_tax = get_deducted_taxes()
tax_details = frappe.db.sql("""
select
parent, description, item_wise_tax_detail,
name, parent, description, item_wise_tax_detail,
charge_type, base_tax_amount_after_discount_amount
from `tab%s`
where
@@ -190,7 +194,7 @@ def get_tax_accounts(item_list, columns, company_currency,
""" % (tax_doctype, '%s', ', '.join(['%s']*len(invoice_item_row)), conditions),
tuple([doctype] + invoice_item_row.keys()))
for parent, description, item_wise_tax_detail, charge_type, tax_amount in tax_details:
for name, parent, description, item_wise_tax_detail, charge_type, tax_amount in tax_details:
description = handle_html(description)
if description not in tax_columns and tax_amount:
# as description is text editor earlier and markup can break the column convention in reports
@@ -219,9 +223,13 @@ def get_tax_accounts(item_list, columns, company_currency,
item_tax_amount = flt((tax_amount * d.base_net_amount) / item_net_amount) \
if item_net_amount else 0
if item_tax_amount:
tax_amount = flt(item_tax_amount, tax_amount_precision)
tax_amount = (tax_amount * -1
if (doctype == 'Purchase Invoice' and name in deducted_tax) else tax_amount)
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
"tax_rate": tax_rate,
"tax_amount": flt(item_tax_amount, tax_amount_precision)
"tax_amount": tax_amount
})
except ValueError:

View File

@@ -162,8 +162,6 @@ def calculate_values(accounts, gl_entries_by_account, opening_balances, filters,
total_row["credit"] += d["credit"]
total_row["opening_debit"] += d["opening_debit"]
total_row["opening_credit"] += d["opening_credit"]
total_row["closing_debit"] += (d["opening_debit"] + d["debit"])
total_row["closing_credit"] += (d["opening_credit"] + d["credit"])
return total_row
@@ -176,6 +174,8 @@ def accumulate_values_into_parents(accounts, accounts_by_name):
def prepare_data(accounts, filters, total_row, parent_children_map, company_currency):
data = []
total_row["closing_debit"] = total_row["closing_credit"] = 0
for d in accounts:
has_value = False
row = {
@@ -200,6 +200,10 @@ def prepare_data(accounts, filters, total_row, parent_children_map, company_curr
row["has_value"] = has_value
data.append(row)
if not d.parent_account:
total_row["closing_debit"] += (d["debit"] - d["credit"]) if (d["debit"] - d["credit"]) > 0 else 0
total_row["closing_credit"] += abs(d["debit"] - d["credit"]) if (d["debit"] - d["credit"]) < 0 else 0
data.extend([{},total_row])
return data

View File

@@ -23,6 +23,14 @@ frappe.ui.form.on('Asset', {
}
};
});
frm.set_query("cost_center", function() {
return {
"filters": {
"company": frm.doc.company,
}
};
});
},
refresh: function(frm) {

View File

@@ -415,6 +415,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cost_center",
"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": "Cost Center",
"length": 0,
"no_copy": 0,
"options": "Cost Center",
"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,
@@ -1221,7 +1252,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-19 12:58:44.137460",
"modified": "2018-07-17 06:30:25.506194",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@@ -38,7 +38,7 @@ def make_depreciation_entry(asset_name, date=None):
depreciation_cost_center, depreciation_series = frappe.db.get_value("Company", asset.company,
["depreciation_cost_center", "series_for_depreciation_entry"])
depreciation_cost_center = asset.cost_center or depreciation_cost_center
for d in asset.get("schedules"):
if not d.journal_entry and getdate(d.schedule_date) <= getdate(date):
@@ -154,6 +154,7 @@ def restore_asset(asset_name):
def get_gl_entries_on_asset_disposal(asset, selling_amount=0):
fixed_asset_account, accumulated_depr_account, depr_expense_account = get_depreciation_accounts(asset)
disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(asset.company)
depreciation_cost_center = asset.cost_center or depreciation_cost_center
accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(asset.value_after_depreciation)

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

@@ -1,231 +1,276 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2013-06-25 11:04:03",
"custom": 0,
"description": "Settings for Buying Module",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Other",
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Supplier Name",
"fieldname": "supp_master_name",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Supplier Naming By",
"length": 0,
"no_copy": 0,
"options": "Supplier Name\nNaming Series",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "supplier_type",
"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": "Default Supplier Type",
"length": 0,
"no_copy": 0,
"options": "Supplier Type",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "buying_price_list",
"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": "Default Buying Price List",
"length": 0,
"no_copy": 0,
"options": "Price List",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"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,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "po_required",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Purchase Order Required",
"length": 0,
"no_copy": 0,
"options": "No\nYes",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "pr_required",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Purchase Receipt Required",
"length": 0,
"no_copy": 0,
"options": "No\nYes",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "maintain_same_rate",
"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": "Maintain same rate throughout purchase cycle",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_multiple_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": "Allow Item to be added multiple times in a transaction",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"description": "If enabled, last purchase details of items will not be fetched from previous purchase order or purchase receipt",
"fieldname": "disable_fetch_last_purchase_rate",
"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": "Disable Fetching Last Purchase Details in Purchase Order",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-cog",
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"modified": "2017-12-27 15:20:06.052342",
"max_attachments": 0,
"modified": "2018-07-18 07:52:38.062488",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
@@ -252,6 +297,10 @@
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0
"read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 0,
"track_seen": 0
}

View File

@@ -32,12 +32,7 @@ frappe.ui.form.on("Purchase Order", {
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
if (frm.doc.__onload) {
frm.toggle_display('get_last_purchase_rate',
frm.doc.__onload.disable_fetch_last_purchase_rate);
}
},
}
});
frappe.ui.form.on("Purchase Order Item", {
@@ -318,6 +313,73 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
})
}, __("Add items from"));
this.frm.add_custom_button(__('Update rate as per last purchase'),
function() {
frappe.call({
"method": "get_last_purchase_rate",
"doc": me.frm.doc,
callback: function(r, rt) {
me.frm.dirty();
me.frm.cscript.calculate_taxes_and_totals();
}
})
}, __("Tools"));
this.frm.add_custom_button(__('Link to Material Request'),
function() {
var my_items = [];
for (var i in me.frm.doc.items) {
if(!me.frm.doc.items[i].material_request){
my_items.push(me.frm.doc.items[i].item_code);
}
}
frappe.call({
method: "erpnext.buying.utils.get_linked_material_requests",
args:{
items: my_items
},
callback: function(r) {
if(r.exc) return;
var i = 0;
var item_length = me.frm.doc.items.length;
while (i < item_length) {
var qty = me.frm.doc.items[i].qty;
(r.message[0] || []).forEach(function(d) {
if (d.qty > 0 && qty > 0 && me.frm.doc.items[i].item_code == d.item_code && !me.frm.doc.items[i].material_request_item)
{
me.frm.doc.items[i].material_request = d.mr_name;
me.frm.doc.items[i].material_request_item = d.mr_item;
var my_qty = Math.min(qty, d.qty);
qty = qty - my_qty;
d.qty = d.qty - my_qty;
me.frm.doc.items[i].stock_qty = my_qty * me.frm.doc.items[i].conversion_factor;
me.frm.doc.items[i].qty = my_qty;
frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + me.frm.doc.items[i].idx + ")");
if (qty > 0) {
frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
var new_row = frappe.model.add_child(me.frm.doc, me.frm.doc.items[i].doctype, "items");
item_length++;
for (var key in me.frm.doc.items[i]) {
new_row[key] = me.frm.doc.items[i][key];
}
new_row.idx = item_length;
new_row["stock_qty"] = new_row.conversion_factor * qty;
new_row["qty"] = qty;
new_row["material_request"] = "";
new_row["material_request_item"] = "";
}
}
});
i++;
}
refresh_field("items");
}
});
}, __("Tools"));
},
tc_name: function() {
@@ -346,17 +408,6 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
cur_frm.cscript.update_status('Deliver', 'Delivered')
},
get_last_purchase_rate: function() {
frappe.call({
"method": "get_last_purchase_rate",
"doc": cur_frm.doc,
callback: function(r, rt) {
cur_frm.dirty();
cur_frm.cscript.calculate_taxes_and_totals();
}
})
},
items_on_form_rendered: function() {
set_schedule_date(this.frm);
},

View File

@@ -1207,7 +1207,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1238,68 +1238,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
"fieldname": "get_last_purchase_rate",
"fieldtype": "Button",
"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": "Get last purchase rate",
"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,
"depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
"fieldname": "link_to_mrs",
"fieldtype": "Button",
"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": "Link to material requests",
"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,
@@ -3355,7 +3293,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-02-17 11:00:05.037716",
"modified": "2018-07-18 07:49:53.131408",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",

View File

@@ -33,12 +33,6 @@ class PurchaseOrder(BuyingController):
'percent_join_field': 'material_request'
}]
def onload(self):
super(PurchaseOrder, self).onload()
self.set_onload('disable_fetch_last_purchase_rate',
cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")))
def validate(self):
super(PurchaseOrder, self).validate()
@@ -122,7 +116,6 @@ class PurchaseOrder(BuyingController):
def get_last_purchase_rate(self):
"""get last purchase rates for all items"""
if cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")): return
conversion_rate = flt(self.get('conversion_rate')) or 1.0
for d in self.get("items"):
@@ -286,7 +279,6 @@ class PurchaseOrder(BuyingController):
def item_last_purchase_rate(name, conversion_rate, item_code, conversion_factor= 1.0):
"""get last purchase rate for an item"""
if cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")): return
conversion_rate = flt(conversion_rate) or 1.0

View File

@@ -1,156 +0,0 @@
QUnit.module('Buying');
QUnit.test("test: purchase order with last purchase rate", function(assert) {
assert.expect(9);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Purchase Order', [
{supplier: 'Test Supplier'},
{is_subcontracted: 'No'},
{currency: 'INR'},
{items: [
[
{"item_code": 'Test Product 4'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 800},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
],
[
{"item_code": 'Test Product 1'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 400},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
]
]}
]);
},
() => {
// Get item details
assert.ok(cur_frm.doc.items[0].item_name == 'Test Product 4', "Item 1 name correct");
assert.ok(cur_frm.doc.items[1].item_name == 'Test Product 1', "Item 2 name correct");
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(1),
() => {
return frappe.tests.make('Purchase Order', [
{supplier: 'Test Supplier'},
{is_subcontracted: 'No'},
{currency: 'INR'},
{items: [
[
{"item_code": 'Test Product 4'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 600},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
],
[
{"item_code": 'Test Product 1'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 200},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
]
]}
]);
},
() => frappe.timeout(2),
// Get the last purchase rate of items
() => {
assert.ok(cur_frm.doc.items[0].last_purchase_rate == 800, "Last purchase rate of item 1 correct");
assert.ok(cur_frm.doc.items[1].last_purchase_rate != 0);
},
() => {
assert.ok(cur_frm.doc.items[1].last_purchase_rate == 400, "Last purchase rate of item 2 correct");
assert.ok(cur_frm.doc.items[1].last_purchase_rate != 0);
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(1),
() => {
assert.ok(cur_frm.doc.status == 'To Receive and Bill', "Submitted successfully");
},
// enable allow_last_purchase_rate
() => {
return frappe.tests.make('Buying Settings', [
// values to be set
{"disable_fetch_last_purchase_rate": 1}
]);
},
() => {
return frappe.tests.make('Purchase Order', [
{supplier: 'Test Supplier'},
{is_subcontracted: 'No'},
{currency: 'INR'},
{items: [
[
{"item_code": 'Test Product 4'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 800},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
],
[
{"item_code": 'Test Product 1'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 400},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
]
]}
]);
},
() => {
// Get item details
assert.ok(cur_frm.doc.items[0].last_purchase_rate == 0);
assert.ok(cur_frm.doc.items[1].last_purchase_rate == 0);
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(1),
// enable allow_last_purchase_rate
() => frappe.tests.make('Buying Settings', [
// values to be set
{"disable_fetch_last_purchase_rate": 0}
]),
() => done()
]);
});

View File

@@ -680,7 +680,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -1897,7 +1897,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-12-14 09:36:40.837027",
"modified": "2018-07-18 07:53:54.677844",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",

View File

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

View File

@@ -36,13 +36,13 @@ def get_data():
"items": [
{
"type": "doctype",
"name": "Job Applicant",
"description": _("Applicant for a Job."),
"name": "Job Opening",
"description": _("Opening for a Job."),
},
{
"type": "doctype",
"name": "Job Opening",
"description": _("Opening for a Job."),
"name": "Job Applicant",
"description": _("Applicant for a Job."),
},
{
"type": "doctype",

View File

@@ -82,7 +82,8 @@ class AccountsController(TransactionBase):
self.validate_non_invoice_documents_schedule()
def before_print(self):
if self.doctype in ['Purchase Order', 'Sales Order']:
if self.doctype in ['Purchase Order', 'Sales Order', 'Sales Invoice', 'Purchase Invoice',
'Supplier Quotation', 'Purchase Receipt', 'Delivery Note', 'Quotation']:
if self.get("group_same_items"):
self.group_similar_items()
@@ -130,14 +131,18 @@ class AccountsController(TransactionBase):
self.meta.get_label(date_field), self)
def validate_due_date(self):
if self.get('is_pos'): return
from erpnext.accounts.party import validate_due_date
if self.doctype == "Sales Invoice":
if not self.due_date:
frappe.throw(_("Due Date is mandatory"))
validate_due_date(self.posting_date, self.due_date, "Customer", self.customer, self.company)
validate_due_date(self.posting_date, self.due_date,
"Customer", self.customer, self.company, self.payment_terms_template)
elif self.doctype == "Purchase Invoice":
validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company)
validate_due_date(self.posting_date, self.due_date,
"Supplier", self.supplier, self.company, self.payment_terms_template)
def set_price_list_currency(self, buying_or_selling):
if self.meta.get_field("posting_date"):
@@ -663,6 +668,7 @@ class AccountsController(TransactionBase):
if item.item_code in group_item_qty:
item.qty = group_item_qty[item.item_code]
item.amount = group_item_amount[item.item_code]
item.rate = flt(flt(item.amount)/flt(item.qty), item.precision("rate"))
del group_item_qty[item.item_code]
else:
duplicate_list.append(item)

View File

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

View File

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

View File

@@ -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()
@@ -51,9 +52,15 @@ class SellingController(StockController):
def set_missing_lead_customer_details(self):
if getattr(self, "customer", None):
from erpnext.accounts.party import _get_party_details
fetch_payment_terms_template = False
if (self.get("__islocal") or
self.company != frappe.db.get_value(self.doctype, self.name, 'company')):
fetch_payment_terms_template = True
party_details = _get_party_details(self.customer,
ignore_permissions=self.flags.ignore_permissions,
doctype=self.doctype, company=self.company)
doctype=self.doctype, company=self.company,
fetch_payment_terms_template=fetch_payment_terms_template)
if not self.meta.get_field("sales_team"):
party_details.pop("sales_team")
@@ -337,6 +344,11 @@ class SellingController(StockController):
po_nos = frappe.get_all('Sales Order', 'po_no', filters = {'name': ('in', sales_orders)})
self.po_no = ', '.join(list(set([d.po_no for d in po_nos if d.po_no])))
def validate_items(self):
# validate items to see if they have is_sales_item enabled
from erpnext.controllers.buying_controller import validate_item_type
validate_item_type(self, "is_sales_item", "sales")
def check_active_sales_items(obj):
for d in obj.get("items"):
if d.item_code:

View File

@@ -38,6 +38,7 @@ class calculate_taxes_and_totals(object):
self.manipulate_grand_total_for_inclusive_tax()
self.calculate_totals()
self._cleanup()
self.calculate_total_net_weight()
def validate_conversion_rate(self):
# validate conversion rate
@@ -328,6 +329,13 @@ class calculate_taxes_and_totals(object):
self.set_rounded_total()
def calculate_total_net_weight(self):
if self.doc.meta.get_field('total_net_weight'):
self.doc.total_net_weight = 0.0
for d in self.doc.items:
if d.total_weight:
self.doc.total_net_weight += d.total_weight
def set_rounded_total(self):
if self.doc.meta.get_field("rounded_total"):
if self.doc.is_rounded_total_disabled():
@@ -592,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

@@ -51,12 +51,12 @@ def enroll_random_student(current_date):
def assign_student_group(student, student_name, program, courses, batch):
course_list = [d["course"] for d in courses]
for d in frappe.get_list("Student Group", fields=("name"), filters={"program": program, "course":("in", course_list)}):
for d in frappe.get_list("Student Group", fields=("name"), filters={"program": program, "course":("in", course_list), "disabled": 0}):
student_group = frappe.get_doc("Student Group", d.name)
student_group.append("students", {"student": student, "student_name": student_name,
"group_roll_number":len(student_group.students)+1, "active":1})
student_group.save()
student_batch = frappe.get_list("Student Group", fields=("name"), filters={"program": program, "group_based_on":"Batch", "batch":batch})[0]
student_batch = frappe.get_list("Student Group", fields=("name"), filters={"program": program, "group_based_on":"Batch", "batch":batch, "disabled": 0})[0]
student_batch_doc = frappe.get_doc("Student Group", student_batch.name)
student_batch_doc.append("students", {"student": student, "student_name": student_name,
"group_roll_number":len(student_batch_doc.students)+1, "active":1})
@@ -65,7 +65,7 @@ def assign_student_group(student, student_name, program, courses, batch):
def mark_student_attendance(current_date):
status = ["Present", "Absent"]
for d in frappe.db.get_list("Student Group", filters={"group_based_on": "Batch"}):
for d in frappe.db.get_list("Student Group", filters={"group_based_on": "Batch", "disabled": 0}):
students = get_student_group_students(d.name)
for stud in students:
make_attendance_records(stud.student, stud.student_name, status[weighted_choice([9,4])], None, d.name, current_date)
@@ -77,7 +77,7 @@ def make_fees():
def make_assessment_plan(date):
for d in range(1,4):
random_group = get_random("Student Group", {"group_based_on": "Course"}, True)
random_group = get_random("Student Group", {"group_based_on": "Course", "disabled": 0}, True)
doc = frappe.new_doc("Assessment Plan")
doc.student_group = random_group.name
doc.course = random_group.course

View File

@@ -88,16 +88,14 @@ def make_attendance_records(student, student_name, status, course_schedule=None,
:param course_schedule: Course Schedule.
:param status: Status (Present/Absent)
"""
student_attendance_list = frappe.get_list("Student Attendance", fields = ['name'], filters = {
student_attendance = frappe.get_doc({
"doctype": "Student Attendance",
"student": student,
"course_schedule": course_schedule,
"student_group": student_group,
"date": date
})
if student_attendance_list:
student_attendance = frappe.get_doc("Student Attendance", student_attendance_list[0])
else:
if not student_attendance:
student_attendance = frappe.new_doc("Student Attendance")
student_attendance.student = student
student_attendance.student_name = student_name

View File

@@ -195,6 +195,38 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"description": "If enabled, field Academic Term will be Mandatory in Program Enrollment Tool.",
"fieldname": "academic_term_reqd",
"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": "Make Academic Term Mandatory",
"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,
@@ -267,7 +299,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-11-28 15:45:30.324324",
"modified": "2018-07-26 04:43:35.406690",
"modified_by": "Administrator",
"module": "Education",
"name": "Education Settings",

View File

@@ -31,7 +31,8 @@ frappe.ui.form.on('Fee Schedule', {
return {
"program": frm.doc.program,
"academic_term": frm.doc.academic_term,
"academic_year": frm.doc.academic_year
"academic_year": frm.doc.academic_year,
"disabled": 0
};
});
frappe.realtime.on("fee_schedule_progress", function(data) {

View File

@@ -671,7 +671,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-12-27 10:59:36.838548",
"modified": "2018-07-26 04:44:03.781418",
"modified_by": "Administrator",
"module": "Education",
"name": "Program Enrollment",

View File

@@ -86,7 +86,6 @@ def get_program_courses(doctype, txt, searchfield, start, page_len, filters):
"program": filters['program']
})
@frappe.whitelist()
def get_students(doctype, txt, searchfield, start, page_len, filters):
if not filters.get("academic_term"):

View File

@@ -5,6 +5,9 @@ frappe.ui.form.on("Program Enrollment Tool", {
setup: function(frm) {
frm.add_fetch("student", "title", "student_name");
frm.add_fetch("student_applicant", "title", "student_name");
if(frm.doc.__onload && frm.doc.__onload.academic_term_reqd) {
frm.toggle_reqd("academic_term", true);
}
},
"refresh": function(frm) {

View File

@@ -513,7 +513,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2018-01-02 11:59:40.230689",
"modified": "2018-07-26 04:44:13.232146",
"modified_by": "Administrator",
"module": "Education",
"name": "Program Enrollment Tool",

View File

@@ -7,8 +7,13 @@ import frappe
from frappe import _
from frappe.model.document import Document
from erpnext.education.api import enroll_student
from frappe.utils import cint
class ProgramEnrollmentTool(Document):
def onload(self):
academic_term_reqd = cint(frappe.db.get_single_value('Education Settings', 'academic_term_reqd'))
self.set_onload("academic_term_reqd", academic_term_reqd)
def get_students(self):
students = []
if not self.get_students_from:

View File

@@ -3,7 +3,7 @@
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "SA.######",
"autoname": "",
"beta": 0,
"creation": "2015-11-05 15:20:23.045996",
"custom": 0,
@@ -40,7 +40,7 @@
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
@@ -101,7 +101,7 @@
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
@@ -239,7 +239,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-11-10 19:09:51.041960",
"modified": "2018-07-27 10:48:22.301531",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Attendance",

View File

@@ -7,7 +7,8 @@ frappe.ui.form.on('Student Attendance Tool', {
frm.set_query("student_group", function() {
return {
"filters": {
"group_based_on": frm.doc.group_based_on
"group_based_on": frm.doc.group_based_on,
"disabled": 0
}
};
});

View File

@@ -293,6 +293,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "disabled",
"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": "Disabled",
"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,
@@ -459,7 +490,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-11-10 19:09:37.370864",
"modified": "2018-07-26 04:17:10.836912",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Group",

View File

@@ -99,7 +99,7 @@ def get_guardian_map(student_list):
def get_student_roll_no(academic_year, program, batch):
student_group = frappe.get_all("Student Group",
filters={"academic_year":academic_year, "program":program, "batch":batch})
filters={"academic_year":academic_year, "program":program, "batch":batch, "disabled": 0})
if student_group:
roll_no_dict = dict(frappe.db.sql('''select student, group_roll_number from `tabStudent Group Student` where parent=%s''',
(student_group[0].name)))

View File

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

View File

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

View File

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

View File

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

View File

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

@@ -60,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)):
@@ -116,7 +117,7 @@ class LeaveApplication(Document):
frappe.db.sql("""update `tabAttendance` set status = %s, leave_type = %s\
where name = %s""",(status, self.leave_type, d.name))
elif self.to_date <= nowdate():
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:
@@ -138,6 +139,13 @@ class LeaveApplication(Document):
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
@@ -347,7 +355,7 @@ def get_approvers(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist()
def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None):
number_of_days = 0
if half_day == 1:
if cint(half_day) == 1:
if from_date == to_date:
number_of_days = 0.5
else:

View File

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

View File

@@ -24,6 +24,7 @@ def get_columns(leave_types):
]
for leave_type in leave_types:
columns.append(_(leave_type) + " " + _("Opening") + ":Float:160")
columns.append(_(leave_type) + " " + _("Taken") + ":Float:160")
columns.append(_(leave_type) + " " + _("Balance") + ":Float:160")
@@ -32,6 +33,7 @@ def get_columns(leave_types):
def get_data(filters, leave_types):
user = frappe.session.user
allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date)
active_employees = frappe.get_all("Employee",
filters = { "status": "Active", "company": filters.company},
@@ -48,13 +50,17 @@ def get_data(filters, leave_types):
# leaves taken
leaves_taken = get_approved_leaves_for_period(employee.name, leave_type,
filters.from_date, filters.to_date)
# opening balance
opening = get_leave_balance_on(employee.name, leave_type, filters.from_date,
allocation_records_based_on_from_date.get(employee.name, frappe._dict()))
# closing balance
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
allocation_records_based_on_to_date.get(employee.name, frappe._dict()))
row += [leaves_taken, closing]
row += [opening, leaves_taken, closing]
data.append(row)
return data
return data

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -266,7 +266,6 @@ erpnext.patches.v6_24.map_customer_address_to_shipping_address_on_po
erpnext.patches.v6_27.fix_recurring_order_status
erpnext.patches.v6_20x.update_product_bundle_description
erpnext.patches.v7_0.update_party_status #2016-09-22
erpnext.patches.v7_0.update_item_projected
erpnext.patches.v7_0.remove_features_setup
erpnext.patches.v7_0.update_home_page
execute:frappe.delete_doc_if_exists("Page", "financial-analytics")
@@ -502,3 +501,5 @@ 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
erpnext.patches.v10_0.update_address_template_for_india

View File

@@ -0,0 +1,12 @@
# Copyright (c) 2017, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from erpnext.regional.india.setup import update_address_template
def execute():
if frappe.db.get_value('Company', {'country': 'India'}, 'name'):
address_template = frappe.db.get_value('Address Template', 'India', 'template')
if not address_template or "gstin" not in address_template:
update_address_template()

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

@@ -9,7 +9,7 @@ def execute():
def repost_bin_qty():
for bin in frappe.db.sql(""" select name from `tabBin`
where (actual_qty + ordered_qty + indented_qty + planned_qty- reserved_qty - reserved_qty_for_production) != projected_qty """, as_dict=1):
where (actual_qty + ordered_qty + indented_qty + planned_qty - reserved_qty - reserved_qty_for_production - reserved_qty_for_sub_contract) != projected_qty """, as_dict=1):
bin_doc = frappe.get_doc('Bin', bin.name)
bin_doc.set_projected_qty()
bin_doc.db_set("projected_qty", bin_doc.projected_qty, update_modified = False)

View File

@@ -1,7 +0,0 @@
import frappe
def execute():
frappe.reload_doctype("Item")
from erpnext.stock.doctype.bin.bin import update_item_projected_qty
for item in frappe.get_all("Item", filters={"is_stock_item": 1}):
update_item_projected_qty(item.name)

View File

@@ -1,7 +1,8 @@
import frappe
def execute():
frappe.reload_doc("stock", "doctype", "bin")
bins = frappe.db.sql("select name from `tabBin` where reserved_qty_for_production > 0")
for d in bins:
bin_doc = frappe.get_doc("Bin", d[0])
bin_doc.update_reserved_qty_for_production()
bin_doc.update_reserved_qty_for_production()

View File

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

View File

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

View File

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

View File

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

View File

@@ -222,60 +222,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
tc_name: function() {
this.get_terms();
},
link_to_mrs: function() {
var my_items = [];
for (var i in cur_frm.doc.items) {
if(!cur_frm.doc.items[i].material_request){
my_items.push(cur_frm.doc.items[i].item_code);
}
}
frappe.call({
method: "erpnext.buying.utils.get_linked_material_requests",
args:{
items: my_items
},
callback: function(r) {
if(r.exc) return;
var i = 0;
var item_length = cur_frm.doc.items.length;
while (i < item_length) {
var qty = cur_frm.doc.items[i].qty;
(r.message[0] || []).forEach(function(d) {
if (d.qty > 0 && qty > 0 && cur_frm.doc.items[i].item_code == d.item_code && !cur_frm.doc.items[i].material_request_item)
{
cur_frm.doc.items[i].material_request = d.mr_name;
cur_frm.doc.items[i].material_request_item = d.mr_item;
var my_qty = Math.min(qty, d.qty);
qty = qty - my_qty;
d.qty = d.qty - my_qty;
cur_frm.doc.items[i].stock_qty = my_qty*cur_frm.doc.items[i].conversion_factor;
cur_frm.doc.items[i].qty = my_qty;
frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + cur_frm.doc.items[i].idx + ")");
if (qty > 0) {
frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
item_length++;
for (var key in cur_frm.doc.items[i]) {
newrow[key] = cur_frm.doc.items[i][key];
}
newrow.idx = item_length;
newrow["stock_qty"] = newrow.conversion_factor*qty;
newrow["qty"] = qty;
newrow["material_request"] = "";
newrow["material_request_item"] = "";
}
}
});
i++;
}
refresh_field("items");
}
});
}
});

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

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

@@ -0,0 +1,33 @@
// Copyright (c) 2016, FinByz Tech Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Eway Bill"] = {
"filters": [
{
'fieldname': 'delivery_note',
'label': __("Delivery Note"),
'fieldtype': 'Link',
'options': 'Delivery Note'
},
{
'fieldname': 'posting_date',
'label': __("Date"),
'fieldtype': 'DateRange',
'default': [frappe.datetime.nowdate(), frappe.datetime.nowdate()]
},
{
'fieldname': 'customer',
'label': __("Customer"),
'fieldtype': 'Link',
'options': 'Customer'
},
{
"fieldname":"company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_user_default("Company")
},
]
}

View File

@@ -0,0 +1,32 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2018-07-13 19:59:18.922829",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2018-07-19 12:08:07.400295",
"modified_by": "Administrator",
"module": "Regional",
"name": "Eway Bill",
"owner": "Administrator",
"ref_doctype": "Delivery Note",
"report_name": "Eway Bill",
"report_type": "Script Report",
"roles": [
{
"role": "Stock User"
},
{
"role": "Stock Manager"
},
{
"role": "Sales User"
},
{
"role": "Accounts User"
}
]
}

View File

@@ -0,0 +1,385 @@
# Copyright (c) 2013, FinByz Tech Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
import json
import re
from frappe import _
from frappe.utils import nowdate
def execute(filters=None):
if not filters: filters.setdefault('posting_date', [nowdate(), nowdate()])
columns, data = [], []
columns = get_columns()
data = get_data(filters)
return columns, data
def get_data(filters):
conditions = get_conditions(filters)
data = frappe.db.sql("""
SELECT
dn.name as dn_id, dn.posting_date, dn.company, dn.company_gstin, dn.customer, dn.customer_gstin, dni.item_code, dni.item_name, dni.description, dni.gst_hsn_code, dni.uom, dni.qty, dni.amount, dn.transport_mode, dn.distance, dn.transporter_name, dn.transporter, dn.lr_no, dn.lr_date, dn.vehicle_no, dn.vehicle_type, dn.company_address, dn.shipping_address_name
FROM
`tabDelivery Note` AS dn join `tabDelivery Note Item` AS dni on (dni.parent = dn.name)
WHERE
dn.docstatus < 2
%s """ % conditions, as_dict=1)
unit = {
'Bag': "BAGS",
'Bottle': "BOTTLES",
'Kg': "KILOGRAMS",
'Liter': "LITERS",
'Meter': "METERS",
'Nos': "NUMBERS",
'PKT': "PACKS",
'Roll': "ROLLS",
'Set': "SETS"
}
# Regular expression set to remove all the special characters
special_characters = "[$%^*()+\\[\]{};':\"\\|<>.?]"
for row in data:
set_defaults(row)
set_taxes(row, filters)
set_address_details(row, special_characters)
# Eway Bill accepts date as dd/mm/yyyy and not dd-mm-yyyy
row.posting_date = '/'.join(str(row.posting_date).replace("-", "/").split('/')[::-1])
row.lr_date = '/'.join(str(row.lr_date).replace("-", "/").split('/')[::-1])
row.item_name = re.sub(special_characters, " ", row.item_name)
row.description = row.item_name
row.uom = unit.get(row.uom, row.uom)
# For removing special charactes and numbers from customer.
row.customer = re.sub(special_characters[:-1] + "&0-9" + "]", "", row.customer)
return data
def get_conditions(filters):
conditions = ""
conditions += filters.get('company') and " AND dn.company = '%s' " % filters.get('company') or ""
conditions += filters.get('posting_date') and " AND dn.posting_date >= '%s' AND dn.posting_date <= '%s' " % (filters.get('posting_date')[0], filters.get('posting_date')[1]) or ""
conditions += filters.get('delivery_note') and " AND dn.name = '%s' " % filters.get('delivery_note') or ""
conditions += filters.get('customer') and " AND dn.customer = '%s' " % filters.get('customer').replace("'", "\'") or ""
return conditions
def set_defaults(row):
row.setdefault(u'supply_type', "Outward")
row.setdefault(u'sub_type', "Supply")
row.setdefault(u'doc_type', "Delivery Challan")
def set_address_details(row, special_characters):
if row.get('company_address'):
address_line1, address_line2, city, pincode, state = frappe.db.get_value("Address", row.get('company_address'), ['address_line1', 'address_line2', 'city', 'pincode', 'state'])
row.update({'from_address_1': re.sub(special_characters, "", address_line1 or '')})
row.update({'from_address_2': re.sub(special_characters, "", address_line2 or '')})
row.update({'from_place': city and city.upper() or ''})
row.update({'from_pin_code': pincode and pincode.replace(" ", "") or ''})
row.update({'from_state': state and state.upper() or ''})
row.update({'dispatch_state': row.from_state})
if row.get('shipping_address_name'):
address_line1, address_line2, city, pincode, state = frappe.db.get_value("Address", row.get('shipping_address_name'), ['address_line1', 'address_line2', 'city', 'pincode', 'state'])
row.update({'to_address_1': re.sub(special_characters, "", address_line1 or '')})
row.update({'to_address_2': re.sub(special_characters, "", address_line2 or '')})
row.update({'to_place': city and city.upper() or ''})
row.update({'to_pin_code': pincode and pincode.replace(" ", "") or ''})
row.update({'to_state': state and state.upper() or ''})
row.update({'ship_to_state': row.to_state})
def set_taxes(row, filters):
taxes = frappe.get_list("Sales Taxes and Charges",
filters={
'parent': row.dn_id
},
fields=('item_wise_tax_detail', 'account_head'))
account_list = ["cgst_account", "sgst_account", "igst_account", "cess_account"]
taxes_list = frappe.get_list("GST Account",
filters={
"parent": "GST Settings",
"company": filters.company
},
fields=account_list)
item_tax_rate = {}
for tax in taxes:
item_wise_tax = json.loads(tax.item_wise_tax_detail)
item_tax_rate[tax.account_head] = item_wise_tax.get(row.item_code)
tax_rate = []
tax = taxes_list[0]
for key in account_list:
if tax[key] not in item_tax_rate.keys():
item_tax_rate[tax[key]] = [0.0, 0.0]
tax_rate.append(str(item_tax_rate[tax[key]][0]))
row.update({key[:5] + "amount": round(item_tax_rate.get(tax[key], 0.0)[1], 2)})
item_tax_rate.pop(tax[key])
row.amount = float(row.amount) + sum(i[1] for i in item_tax_rate.values())
row.update({'tax_rate': '+'.join(tax_rate)})
def get_columns():
columns = [
{
"fieldname": "supply_type",
"label": _("Supply Type"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "sub_type",
"label": _("Sub Type"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "doc_type",
"label": _("Doc Type"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "dn_id",
"label": _("Doc Name"),
"fieldtype": "Link",
"options": "Delivery Note",
"width": 140
},
{
"fieldname": "posting_date",
"label": _("Doc Date"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "company",
"label": _("From Party Name"),
"fieldtype": "Link",
"options": "Company",
"width": 120
},
{
"fieldname": "company_gstin",
"label": _("From GSTIN"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "from_address_1",
"label": _("From Address 1"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "from_address_2",
"label": _("From Address 2"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "from_place",
"label": _("From Place"),
"fieldtype": "Data",
"width": 80
},
{
"fieldname": "from_pin_code",
"label": _("From Pin Code"),
"fieldtype": "Data",
"width": 80
},
{
"fieldname": "from_state",
"label": _("From State"),
"fieldtype": "Data",
"width": 80
},
{
"fieldname": "dispatch_state",
"label": _("Dispatch State"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "customer",
"label": _("To Party Name"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "customer_gstin",
"label": _("To GSTIN"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "to_address_1",
"label": _("To Address 1"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "to_address_2",
"label": _("To Address 2"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "to_place",
"label": _("To Place"),
"fieldtype": "Data",
"width": 80
},
{
"fieldname": "to_pin_code",
"label": _("To Pin Code"),
"fieldtype": "Data",
"width": 80
},
{
"fieldname": "to_state",
"label": _("To State"),
"fieldtype": "Data",
"width": 80
},
{
"fieldname": "ship_to_state",
"label": _("Ship To State"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "item_name",
"label": _("Product"),
"fieldtype": "Link",
"options": "Item",
"width": 120
},
{
"fieldname": "description",
"label": _("Description"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "gst_hsn_code",
"label": _("HSN"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "uom",
"label": _("Unit"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "qty",
"label": _("Qty"),
"fieldtype": "Float",
"width": 100
},
{
"fieldname": "amount",
"label": _("Accessable Value"),
"fieldtype": "Float",
"width": 120
},
{
"fieldname": "tax_rate",
"label": _("Tax Rate"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "cgst_amount",
"label": _("CGST Amount"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "sgst_amount",
"label": _("SGST Amount"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "igst_amount",
"label": _("IGST Amount"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "cess_amount",
"label": _("CESS Amount"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "transport_mode",
"label": _("Transport Mode"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "distance",
"label": _("Distance"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "transporter_name",
"label": _("Transporter Name"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "transporter_id",
"label": _("Transporter ID"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "lr_no",
"label": _("Transporter Doc No"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "lr_date",
"label": _("Transporter Date"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "vehicle_no",
"label": _("Vehicle No"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "vehicle_type",
"label": _("Vehicle Type"),
"fieldtype": "Data",
"width": 100
},
]
return columns

View File

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

View File

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

View File

@@ -79,7 +79,7 @@ class Customer(TransactionBase):
def update_customer_groups(self):
ignore_doctypes = ["Lead", "Opportunity", "POS Profile", "Tax Rule", "Pricing Rule"]
if frappe.flags.customer_group_changed:
update_linked_doctypes('Customer', self.name, 'Customer Group',
update_linked_doctypes('Customer', frappe.db.escape(self.name), 'Customer Group',
self.customer_group, ignore_doctypes)
def create_primary_contact(self):

View File

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

View File

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

View File

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

View File

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

View File

@@ -60,6 +60,21 @@ class TestSalesOrder(unittest.TestCase):
si1 = make_sales_invoice(so.name)
self.assertEquals(len(si1.get("items")), 0)
def test_so_billed_amount_against_return_entry(self):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_sales_return
so = make_sales_order(do_not_submit=True)
so.submit()
si = make_sales_invoice(so.name)
si.insert()
si.submit()
si1 = make_sales_return(si.name)
si1.update_billed_amount_in_sales_order = 1
si1.submit()
so.load_from_db()
self.assertEquals(so.per_billed, 0)
def test_make_sales_invoice_with_terms(self):
so = make_sales_order(do_not_submit=True)

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

@@ -98,7 +98,7 @@ def get_achieved_details(filters, sales_person, all_sales_persons, target_item_g
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 soi.base_net_amount * (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

View File

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

View File

@@ -15,7 +15,7 @@ def execute(filters=None):
data = []
for d in entries:
if d.stock_qty > 0:
if d.stock_qty > 0 or filters.get('show_return_entries', 0):
data.append([
d.name, d.customer, d.territory, d.posting_date, d.item_code,
item_details.get(d.item_code, {}).get("item_group"), item_details.get(d.item_code, {}).get("brand"),

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""" %

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