Compare commits

...

122 Commits

Author SHA1 Message Date
Saurabh
4d50fac869 Merge branch 'hotfix' 2018-01-29 16:24:55 +05:30
Saurabh
05eed01eec bumped to version 10.0.15 2018-01-29 16:54:55 +06:00
Nabin Hait
cfa9d1adb7 Patch: Create Payment Terms based on default credit days set in company and use it while setting due_date (#12685)
* Patch: Create Payment Terms based on default credit days set in company and use it while setting due_date

* Payment Terms patch for credit days defined in customer group
2018-01-29 16:07:21 +05:30
tundebabzy
186bea6e95 Merge pull request #12674 from tundebabzy/issue-12673-1
Batch List Shows Wrong Expired Status For Batches #12673
2018-01-27 07:50:12 +01:00
tundebabzy
794ecda618 corrected wrong get_diff arguments 2018-01-27 05:54:40 +01:00
Manas Solanki
8985077652 Assessment Module Report (#12605)
* updated course wise assessment report

* added new report Final assessment grades
2018-01-26 11:20:33 +05:30
rohitwaghchaure
bfa898ff9b [Fix] System pull the valuation rate even if allow zero valuation rate is enabled (#12537) 2018-01-26 10:59:00 +05:30
tundebabzy
0a33a359ca Merge pull request #12659 from tundebabzy/issue-12658
set batch number only in Sales Invoice and Delivery Note - #12659
2018-01-26 06:10:13 +01:00
tundebabzy
f9b5c74871 set batch number only in Sales Invoice and Delivery Note 2018-01-25 19:21:05 +01:00
Prateeksha Singh
4c58299eb0 [fix] encode if letterhead 2018-01-25 17:29:57 +05:30
rohitwaghchaure
fc318ebeff Merge pull request #12642 from mntechnique/fix-to-issue-#12512
Fix to issue #12512
2018-01-25 17:13:05 +05:30
rohitwaghchaure
3574c96c8c Update item_dashboard_list.html 2018-01-25 17:11:52 +05:30
Vinayak Jethe
5743ce2b6b Made changes as per suggestions 2018-01-25 13:37:20 +05:30
Vinayak Jethe
84f7727432 Merge branch 'hotfix' of https://github.com/frappe/erpnext into fix-to-issue-#12512 2018-01-24 19:48:24 +05:30
Vinayak Jethe
549c196beb Fixes issue #12512 2018-01-24 19:47:59 +05:30
rohitwaghchaure
1bf4015567 Merge pull request #12632 from mntechnique/solves_issue_#12588
Solves issue #12588
2018-01-24 18:26:39 +05:30
Saurabh
cadd31cb0c [Fix] Solves issue #12588 2018-01-24 16:38:22 +05:30
Vinayak Jethe
46c82c45e0 Revised changes for codacy 2018-01-24 14:24:58 +05:30
Vinayak Jethe
2c8ce5a717 Fixes issue #12512 2018-01-24 13:51:26 +05:30
Saurabh
6c3289dbcd Merge branch 'hotfix' 2018-01-24 11:22:54 +05:30
Saurabh
381d452b78 bumped to version 10.0.14 2018-01-24 11:52:53 +06:00
Saurabh
769874d0e9 Merge pull request #12628 from saurabh6790/enable_rename_option
[fix] enable rename for payment terms and payment term template
2018-01-24 11:15:53 +05:30
Saurabh
6cc10104f0 [fix] enable rename for payment terms and payment term template 2018-01-24 11:15:02 +05:30
Saurabh
5b67f4d953 Merge pull request #12626 from saurabh6790/item_price_stock_report_fix
[fix] If buying or selling price list not found, return empty dict
2018-01-24 10:55:51 +05:30
Saurabh
4b9a55b0ef [fix] If buying or selling price list not found, return empty dict 2018-01-24 07:48:56 +05:30
Saurabh
c8399fd093 Merge pull request #12614 from rohitwaghchaure/removed_set_only_once_for_batch_serialno
Disabled property set only once for has serial no and has batch no field in item doctype
2018-01-23 18:08:56 +05:30
Rohit Waghchaure
266e66cd1b Disabled property set only once for has serial no and has batch no field in item doctype 2018-01-23 18:06:12 +05:30
rohitwaghchaure
f3a452850e Merge pull request #12617 from saurabh6790/ux_fix
parse value before setting it to dissable_rounded_total on Purchase Invoice
2018-01-23 17:35:16 +05:30
Saurabh
57df096725 Merge pull request #12600 from vishdha/allow_rename
[new] Allow Rename and Member link with user
2018-01-23 16:49:48 +05:30
Saurabh
db2d02a3e3 Merge pull request #12618 from shreyashah115/warehouse-list
Disabled field in list view - Warehouse DocType
2018-01-23 16:48:59 +05:30
Shreya
dfae11bcee disabled warehouse in list view 2018-01-23 16:46:24 +05:30
rohitwaghchaure
d78e6e04ea Run country fixtures if country changed in the company (#12494) 2018-01-23 15:42:46 +05:30
Saurabh
3959aeb848 [fix] parse value before setting it to dissable_rounded_total on Purchase Invoice 2018-01-23 15:40:43 +05:30
rohitwaghchaure
51293390e4 Merge pull request #12611 from shreyashah115/fetch-conversion-factor
[Fix] Fetch uom conversion factor in material request
2018-01-23 12:41:01 +05:30
rohitwaghchaure
63f4da4402 Merge pull request #12612 from shreyashah115/fix-validation
Fix validation message for overbilling
2018-01-23 12:35:37 +05:30
Shreya
a137fe82a1 fix error message 2018-01-23 11:00:58 +05:30
Shreya
e2b31085a7 fetch uom conversion factor in material request 2018-01-23 10:54:23 +05:30
Vishal
a54815fd9d [new] Allow Rename and Member link with user 2018-01-22 16:02:45 +05:30
Saurabh
4f927ac3e8 Merge branch 'hotfix' 2018-01-22 15:29:14 +05:30
Saurabh
b9f678b350 bumped to version 10.0.13 2018-01-22 15:59:14 +06:00
Saurabh
fb4caff0b2 Merge pull request #12573 from rohitwaghchaure/reorder_issue
[Fix] Wrong projected qty for warehouse group in the process of reorder item, which making extra material requests
2018-01-22 16:49:54 +07:00
Saurabh
e72915847c Merge pull request #12570 from rohitwaghchaure/currency_in_balance_column
Added currency in balance column in general ledger print
2018-01-22 16:35:37 +07:00
rohitwaghchaure
1d93bd50eb Merge pull request #12585 from rohitwaghchaure/sales_income_account_issue
[Fix] Income account can not be group
2018-01-22 15:04:46 +05:30
rohitwaghchaure
8e998875a5 Merge pull request #12590 from shreyashah115/total-on-items-remove
[Fix] Calculate taxes when shipping rule not present at removal of item
2018-01-22 15:03:11 +05:30
rohitwaghchaure
c87a3370cd Merge pull request #12595 from rohitwaghchaure/image_path_in_item_search
[Fix] Image path showing in the item link
2018-01-22 15:01:58 +05:30
Rohit Waghchaure
c4c2bf0bfb [Fix] Image patch showing in the item link 2018-01-22 13:47:28 +05:30
Shreya
39adc8f85f calculate total when items are removed 2018-01-22 13:08:05 +05:30
Rohit Waghchaure
8676590cfe [Fix] Income account can not be group 2018-01-22 12:35:36 +05:30
rohitwaghchaure
cf7b6511ba Merge pull request #12574 from rohitwaghchaure/sales_payment_summary_issue
[Fix] Sales payment summary issue
2018-01-20 17:02:13 +05:30
Rohit Waghchaure
bc94914338 [Fix] Sales payment summary issue 2018-01-20 17:01:31 +05:30
Rohit Waghchaure
f83f6aae22 [Fix] Wrong projected qty for warehouse group in the process of reorder item making extra material requests 2018-01-20 15:44:38 +05:30
rohitwaghchaure
6a81acfddf Merge pull request #12563 from Zlash65/general-ledger-fix
[Hotfix] General Ledger report not working for group_by_account filter
2018-01-20 12:55:35 +05:30
Rohit Waghchaure
edef642794 Added currency in balance column in general ledger print 2018-01-20 12:54:25 +05:30
Zlash65
93344dff26 group_by_account not displayed fix 2018-01-19 19:06:39 +05:30
Rohit Waghchaure
03adf84a8d Merge branch 'hotfix' 2018-01-19 15:49:29 +05:30
Rohit Waghchaure
0e61b52022 bumped to version 10.0.12 2018-01-19 16:19:28 +06:00
rohitwaghchaure
0efd7934b8 Merge pull request #12530 from frappe/manassolanki-patch-2
Issue in the data import while importing the invoice
2018-01-19 15:35:23 +05:30
Rohit Waghchaure
16cde58821 Merge branch 'hotfix' 2018-01-19 13:29:56 +05:30
Rohit Waghchaure
e1815f0989 bumped to version 10.0.11 2018-01-19 13:59:56 +06:00
rohitwaghchaure
c59d52d073 Merge pull request #12550 from rohitwaghchaure/po_permission_issue
[Fix] Error in PO. No Permission for Buying Settings
2018-01-19 13:00:36 +05:30
rohitwaghchaure
7b605a628e Merge pull request #12543 from rohitwaghchaure/precision_issue_bom
[Fix] Precision issue while making material requests from production planning tool
2018-01-19 13:00:16 +05:30
Rohit Waghchaure
2f3ad64bd6 [Fix] Precision issue while making material requests from production planning tool 2018-01-19 12:47:55 +05:30
Rohit Waghchaure
86cbde9057 [Fix] Error in PO. No Permission for Buying Settings 2018-01-19 12:45:53 +05:30
rohitwaghchaure
65a669c81e Merge pull request #12534 from rohitwaghchaure/patch_fix_v7
[Fix] Timesheet patch
2018-01-19 11:37:18 +05:30
rohitwaghchaure
39e0d1b7d6 Merge pull request #12539 from rohitwaghchaure/minor_sales_payment_summary_issue
[Fix] Sales payment summary issue
2018-01-19 11:34:48 +05:30
Rohit Waghchaure
de420322b5 [Fix] Sales payment summary issue 2018-01-18 17:20:21 +05:30
rohitwaghchaure
c8e016522d Merge pull request #12533 from rohitwaghchaure/pos_css_issue
[Fix] POS css
2018-01-18 16:12:00 +05:30
Rohit Waghchaure
5c4f52ccf1 [Fix] POS css 2018-01-18 16:10:19 +05:30
Rohit Waghchaure
95adb60a8f Fix patch 2018-01-18 15:52:52 +05:30
Manas Solanki
c6d5611408 Issue in the data import while importing the invoice 2018-01-18 11:20:24 +05:30
rohitwaghchaure
bd47abdc9a [Enhance] Running Balance in GL Report (#12491)
* Running Balance in GL Report

* Supplier invoice no in GL Report/Print Format
2018-01-18 09:32:43 +05:30
Faris Ansari
00e547d319 Encode letterhead filename (#12525) 2018-01-18 09:28:13 +05:30
Nabin Hait
f1b098e03c payment terms filter in AR Summary report (#12529) 2018-01-18 09:23:32 +05:30
Nabin Hait
a7bcf6791e Merge branch 'hotfix' 2018-01-17 18:51:20 +05:30
Nabin Hait
f76fb50685 bumped to version 10.0.10 2018-01-17 19:21:20 +06:00
rohitwaghchaure
da941af687 Set due date in purchase invoice based on suppler invoice date (#12395) 2018-01-17 16:23:04 +05:30
Nabin Hait
91fd29a963 Remove enqueuing update_total_sales method, sometimes it does not include current invoice (#12522) 2018-01-17 16:14:31 +05:30
Umair Sayed
230805b016 Update total.html (#12511) 2018-01-17 14:41:38 +05:30
rohitwaghchaure
60febc5465 [Fix] Gross profit validation issue (#12516) 2018-01-17 14:40:59 +05:30
Faris Ansari
4d4ce3e5cf Rename enquiry_type to opportunity_type in MultiSelect dialog (#12517) 2018-01-17 14:40:27 +05:30
Vishal Dhayagude
052b51ab20 [fix] Fetch UOM conversion and stock_uom from BOM into material request (#12513)
* [fix]Fetch UOM conversion and stock_uom from BOM into material Request

* Update material_request.js
2018-01-17 14:39:54 +05:30
Nabin Hait
2bfa1803e9 GL Entry on asset sale (#12514)
* GL Entry on asset sale

* Asset sale test case fixed
2018-01-17 14:39:05 +05:30
Nabin Hait
b44ef0b249 Delete employee records on deletion of company 2018-01-16 19:21:02 +05:30
Saurabh
dfb1646a16 Merge branch 'hotfix' 2018-01-15 18:36:34 +05:30
Saurabh
d40bfeb7d3 bumped to version 10.0.9 2018-01-15 19:06:34 +06:00
Saurabh
af7df6ba50 Merge pull request #12495 from netchampfaris/hotfix-add-ac-2
[fix] is_root check
2018-01-15 18:35:54 +05:30
Faris Ansari
f18cd2eaf7 [fix] is_root check 2018-01-15 18:30:01 +05:30
Nabin Hait
a2426fcc9e Get default tax template only if tax template not selected or template is for other company (#12492) 2018-01-15 17:45:46 +05:30
Faris Ansari
184491bbbe [hotfix] Validate posting_time (#12484) 2018-01-15 14:18:53 +05:30
Vishal Dhayagude
eec0f7fd6b [non_profit][fix] Chapter listing and join and leave chapter issue (#12463)
* [fix] Chapter listing and Join and leave chapter issue

* [minor] Changes in chapter html, chapter title to chapter name
2018-01-15 14:10:23 +05:30
Vishal Dhayagude
e04aedadcd [fix] Add to cart issue fixed (#12474) 2018-01-15 14:01:05 +05:30
Vishal Dhayagude
e88f928f0f [fix] Image with name listing (#12479) 2018-01-15 12:29:39 +05:30
Saurabh
e43a3c269a Merge branch 'hotfix' 2018-01-12 16:54:26 +05:30
Saurabh
59edc6028d bumped to version 10.0.8 2018-01-12 17:24:26 +06:00
Saurabh
93d3020e4b Merge pull request #12464 from Zlash65/fix-company-bom-deletion
[Fix] Delete BOM only when found
2018-01-12 16:47:54 +05:30
Manas Solanki
b19fd57043 [fix] set required quantity if item in bom found (#12460) 2018-01-12 16:28:30 +05:30
rohitwaghchaure
7b78f6bee6 Added rounded total in the POS and fix rounded issue in js side (#12457) 2018-01-12 16:28:16 +05:30
rohitwaghchaure
9fbed5617f [Fix] Wrong batch showing in the popup (#12421) 2018-01-12 16:22:33 +05:30
Manas Solanki
bba5fd7a38 Assessment module addition (#12417)
* add academic session details in the Assessmet Plan

* add the academic session and few details in the assessment result

* fix codacy
2018-01-12 16:21:09 +05:30
Zlash65
c9172e0079 delete boms only when found 2018-01-12 15:59:13 +05:30
Manas Solanki
6c3082591c change the resolution field to the text editor (#12449) 2018-01-12 12:00:13 +05:30
rohitwaghchaure
3955fa5102 [Fix] Email addres unique key issue (#12450) 2018-01-11 18:21:02 +05:30
rohitwaghchaure
02302ff009 [Fix] Incoming rate for gross profit report (#12422) 2018-01-11 12:58:46 +05:30
rohitwaghchaure
5b45bcf5f3 [Fix] Report Available Stock for Packing Items Menu not working (#12400) 2018-01-11 12:39:09 +05:30
rohitwaghchaure
20dead5d91 [minor] UI change (#12440)
* [minor] UI change

* Update company.js
2018-01-11 12:31:14 +05:30
rohitwaghchaure
752d21e658 Code cleanup for item price stock report and fix report was not exporting properly in excel (#12427) 2018-01-11 12:28:48 +05:30
tundebabzy
3732033d9b Merge pull request #12435 from tundebabzy/packing-slip-msg
Better validation message in Packing Slip
2018-01-11 00:32:26 +01:00
tundebabzy
6f75885d86 better validation message 2018-01-10 23:14:13 +01:00
Nabin Hait
527e6c02b3 Delete BOMs on deletion of company 2018-01-09 16:29:13 +05:30
Nabin Hait
6b89644ca7 Payment terms filter in AR report 2018-01-09 15:39:35 +05:30
Saurabh
471bc618b5 Merge branch 'hotfix' 2018-01-09 11:55:38 +05:30
Saurabh
0b3b63a9af bumped to version 10.0.7 2018-01-09 12:25:38 +06:00
rohitwaghchaure
412e044e8f [Fix] Error in stock move from batch dashboard (#12377) 2018-01-09 11:27:35 +05:30
Zarrar
0f458b1260 show balance if permitted to view gl entry (#12385) 2018-01-09 11:27:14 +05:30
tundebabzy
da22167741 Purchase Invoice - Due Date reverts to first time value on save #12340 (#12382)
* add handler for due_date:
if due_date is changed and payment terms template or payment schedule is set,
ask user to clear them.

* ui test cases

* cleanup
2018-01-09 10:58:44 +05:30
Prateeksha Singh
8b94f1b553 [minor][buying] fix schedule date check (#12375) 2018-01-08 16:46:39 +05:30
rohitwaghchaure
7fcc21bc8b [Fix] Cart remain same even if pos profile change (#12371) 2018-01-08 15:22:22 +05:30
rohitwaghchaure
bf4c114c58 [Enhance] Provision to show inclusive tax in print (#12345)
* [Enhance] Provision to show inclusive tax in print

* POS Print format
2018-01-08 15:20:15 +05:30
Shreya Shah
44fa9a6d9d Last purchase rate button added back (#12135)
* last purchase rate button added

* triggers to update rate on button

* updated modified column in buying settings

* moved trigger to get_item_details.py

* hide get_last_rate button depending on buying settings
2018-01-08 14:58:20 +05:30
Prateeksha Singh
50b6d79758 Merge pull request #12370 from Zlash65/fix-root-node-delete
[Fix] Delete root node for account
2018-01-08 12:51:31 +05:30
Nabin Hait
3a972c4d85 Precision issue in stock reconciliation 2018-01-08 12:35:05 +05:30
Zlash65
745c2658eb delete root node allow 2018-01-08 11:53:52 +05:30
110 changed files with 1999 additions and 802 deletions

View File

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

View File

@@ -163,7 +163,7 @@ class Account(NestedSet):
if self.check_gle_exists():
throw(_("Account with existing transaction can not be deleted"))
super(Account, self).on_trash()
super(Account, self).on_trash(True)
def before_rename(self, old, new, merge=False):
# Add company abbr if not provided

View File

@@ -79,15 +79,17 @@ frappe.treeview_settings["Account"] = {
},
onrender: function(node) {
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
if (node.data && node.data.balance!==undefined) {
$('<span class="balance-area pull-right text-muted small">'
+ (node.data.balance_in_account_currency ?
(format_currency(Math.abs(node.data.balance_in_account_currency),
node.data.account_currency) + " / ") : "")
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
+ " " + dr_or_cr
+ '</span>').insertBefore(node.$ul);
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
if (node.data && node.data.balance!==undefined) {
$('<span class="balance-area pull-right text-muted small">'
+ (node.data.balance_in_account_currency ?
(format_currency(Math.abs(node.data.balance_in_account_currency),
node.data.account_currency) + " / ") : "")
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
+ " " + dr_or_cr
+ '</span>').insertBefore(node.$ul);
}
}
},
toolbar: [

View File

@@ -287,6 +287,95 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "print_settings",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Print Settings",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "show_inclusive_tax_in_print",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Show Inclusive Tax In Print",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_12",
"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,
@@ -422,7 +511,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-25 13:28:05.067615",
"modified": "2018-01-05 15:26:10.357085",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -1,8 +1,8 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:payment_term_name",
"beta": 0,
"creation": "2017-08-10 15:24:54.876365",
@@ -265,7 +265,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-08-10 16:26:03.581501",
"modified": "2018-01-24 11:13:42.800048",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Term",

View File

@@ -1,8 +1,8 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:template_name",
"beta": 0,
"creation": "2017-08-10 15:34:28.058054",
@@ -85,7 +85,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-08-10 15:46:33.877884",
"modified": "2018-01-24 11:13:31.158613",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Terms Template",

View File

@@ -25,7 +25,7 @@ class POSProfile(Document):
`tabPOS Profile User` pfu, `tabPOS Profile` pf
where
pf.name = pfu.parent and pfu.user = %s and pf.name != %s and pf.company = %s
and pfu.default=1""", (row.user, self.name, self.company))
and pfu.default=1 and pf.disabled = 0""", (row.user, self.name, self.company))
if row.default and res:
msgprint(_("Already set default in pos profile {0} for user {1}, kindly disabled default")

View File

@@ -18,7 +18,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
this.frm.set_df_property("credit_to", "print_hide", 0);
}
} else {
this.frm.set_value("disable_rounded_total", frappe.sys_defaults.disable_rounded_total);
this.frm.set_value("disable_rounded_total", cint(frappe.sys_defaults.disable_rounded_total));
}
// formatter for material request item

View File

@@ -96,7 +96,7 @@ class PurchaseInvoice(BuyingController):
if not self.credit_to:
self.credit_to = get_party_account("Supplier", self.supplier, self.company)
if not self.due_date:
self.due_date = get_due_date(self.posting_date, "Supplier", self.supplier)
self.due_date = get_due_date(self.posting_date, "Supplier", self.supplier, self.company)
super(PurchaseInvoice, self).set_missing_values(for_validate)

View File

@@ -1,7 +1,7 @@
QUnit.module('Purchase Invoice');
QUnit.test("test purchase invoice", function(assert) {
assert.expect(6);
assert.expect(9);
let done = assert.async();
frappe.run_serially([
() => {
@@ -39,6 +39,33 @@ QUnit.test("test purchase invoice", function(assert) {
assert.ok(cur_frm.doc.payment_schedule.length > 0, "Payment Term Schedule is not empty");
},
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(0.5),
() => frappe.tests.set_form_values(cur_frm, [{'payment_terms_schedule': ''}]),
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(0.5),
() => frappe.tests.set_form_values(cur_frm, [{'payment_schedule': []}]),
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(!cur_dialog, 'Message is not shown');
},
() => cur_frm.save(),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(1),

View File

@@ -142,7 +142,7 @@ class SalesInvoice(SellingController):
self.update_time_sheet(self.name)
self.update_current_month_sales()
update_company_current_month_sales(self.company)
self.update_project()
def validate_pos_paid_amount(self):
@@ -181,16 +181,9 @@ class SalesInvoice(SellingController):
self.make_gl_entries_on_cancel()
frappe.db.set(self, 'status', 'Cancelled')
self.update_current_month_sales()
update_company_current_month_sales(self.company)
self.update_project()
def update_current_month_sales(self):
if frappe.flags.in_test:
update_company_current_month_sales(self.company)
else:
frappe.enqueue('erpnext.setup.doctype.company.company.update_company_current_month_sales',
company=self.company)
def update_status_updater_args(self):
if cint(self.update_stock):
self.status_updater.extend([{
@@ -244,7 +237,7 @@ class SalesInvoice(SellingController):
if not self.debit_to:
self.debit_to = get_party_account("Customer", self.customer, self.company)
if not self.due_date and self.customer:
self.due_date = get_due_date(self.posting_date, "Customer", self.customer)
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
super(SalesInvoice, self).set_missing_values(for_validate)
@@ -675,28 +668,28 @@ class SalesInvoice(SellingController):
# income account gl entries
for item in self.get("items"):
if flt(item.base_net_amount):
account_currency = get_account_currency(item.income_account)
gl_entries.append(
self.get_gl_dict({
"account": item.income_account,
"against": self.customer,
"credit": item.base_net_amount,
"credit_in_account_currency": item.base_net_amount \
if account_currency==self.company_currency else item.net_amount,
"cost_center": item.cost_center
}, account_currency)
)
if item.is_fixed_asset:
asset = frappe.get_doc("Asset", item.asset)
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(asset, is_sale=True)
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(asset, item.base_net_amount)
for gle in fixed_asset_gl_entries:
gle["against"] = self.customer
gl_entries.append(self.get_gl_dict(gle))
asset.db_set("disposal_date", self.posting_date)
asset.set_status("Sold" if self.docstatus==1 else None)
else:
account_currency = get_account_currency(item.income_account)
gl_entries.append(
self.get_gl_dict({
"account": item.income_account,
"against": self.customer,
"credit": item.base_net_amount,
"credit_in_account_currency": item.base_net_amount \
if account_currency==self.company_currency else item.net_amount,
"cost_center": item.cost_center
}, account_currency)
)
# expense account gl entries
if cint(self.update_stock) and \

View File

@@ -1,7 +1,7 @@
QUnit.module('Sales Invoice');
QUnit.test("test sales Invoice", function(assert) {
assert.expect(6);
assert.expect(9);
let done = assert.async();
frappe.run_serially([
() => {
@@ -38,6 +38,33 @@ QUnit.test("test sales Invoice", function(assert) {
assert.ok(cur_frm.doc.payment_schedule.length > 0, "Payment Term Schedule is not empty");
},
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(0.5),
() => frappe.tests.set_form_values(cur_frm, [{'payment_terms_schedule': ''}]),
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(0.5),
() => frappe.tests.set_form_values(cur_frm, [{'payment_schedule': []}]),
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(!cur_dialog, 'Message is not shown');
},
() => cur_frm.save(),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.3),

View File

@@ -51,7 +51,7 @@ 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)
out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
if not out.get("currency"):
out["currency"] = currency
@@ -164,7 +164,7 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
out = {
party_type.lower(): party,
account_fieldname : account,
"due_date": get_due_date(posting_date, party_type, party)
"due_date": get_due_date(posting_date, party_type, party, company)
}
return out
@@ -267,12 +267,12 @@ def validate_party_accounts(doc):
@frappe.whitelist()
def get_due_date(posting_date, party_type, party):
def get_due_date(posting_date, party_type, party, company=None):
"""Get due date from `Payment Terms Template`"""
due_date = None
if posting_date and party:
due_date = posting_date
template_name = get_pyt_term_template(party, party_type)
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:
@@ -305,12 +305,11 @@ def get_due_date_from_template(template_name, posting_date):
return due_date
def validate_due_date(posting_date, due_date, party_type, party):
def validate_due_date(posting_date, due_date, party_type, party, company=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)
default_due_date = get_due_date(posting_date, party_type, party, company)
if not default_due_date:
return
@@ -360,14 +359,32 @@ def set_taxes(party, party_type, posting_date, company, customer_group=None, sup
@frappe.whitelist()
def get_pyt_term_template(party_name, party_type):
def get_pyt_term_template(party_name, party_type, company=None):
if party_type not in ("Customer", "Supplier"):
return
template = None
if party_type in ('Customer', 'Supplier'):
template = frappe.db.get_value(party_type, party_name, fieldname='payment_terms')
if party_type == 'Customer':
customer = frappe.db.get_value("Customer", party_name,
fieldname=['payment_terms', "customer_group"], as_dict=1)
template = customer.payment_terms
if not template and customer.customer_group:
template = frappe.db.get_value("Customer Group",
customer.customer_group, fieldname='payment_terms')
else:
supplier = frappe.db.get_value("Supplier", party_name,
fieldname=['payment_terms', "supplier_type"], as_dict=1)
template = supplier.payment_terms
if not template and supplier.supplier_type:
template = frappe.db.get_value("Supplier Type", supplier.supplier_type, fieldname='payment_terms')
if not template and company:
template = frappe.db.get_value("Company", company, fieldname='payment_terms')
return template
def validate_party_frozen_disabled(party_type, party_name):
if party_type and party_name:
if party_type in ("Customer", "Supplier"):

View File

@@ -7,10 +7,10 @@
"docstatus": 0,
"doctype": "Print Format",
"font": "Default",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{% if doc.company_address_display %}\n\t\t{% set company_address = doc.company_address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t{% if \"GSTIN\" not in company_address %}\n\t\t\t{{ company_address }}\n\t\t\t<b>{{ _(\"GSTIN\") }}:</b>{{ doc.company_gstin }}\n\t\t{% else %}\n\t\t\t{{ company_address.replace(\"GSTIN\", \"<br>GSTIN\") }}\n\t\t{% endif %}\n\t{% endif %}\n\t<br>\n\t<b>{{ doc.select_print_heading or _(\"Invoice\") }}</b><br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t{% if doc.grand_total > 50000 %}\n\t\t{% set customer_address = doc.address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t<b>{{ _(\"Customer\") }}:</b><br>\n\t\t{{ doc.customer_name }}<br>\n\t\t{{ customer_address }}\n\t{% endif %}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"40%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.gst_hsn_code -%}\n\t\t\t\t\t<br><b>{{ _(\"HSN/SAC\") }}:</b> {{ item.gst_hsn_code }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t<br><b>{{ _(\"Serial No\") }}:</b> {{ item.serial_no }}\n\t\t\t\t{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.rate }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ _(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"net_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t{%- if not row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n<p><b>Tax Breakup:</b></p>\n<div style=\"font-size: 8px\">\n\t{{ doc.other_charges_calculation }}\n</div>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{% if doc.company_address_display %}\n\t\t{% set company_address = doc.company_address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t{% if \"GSTIN\" not in company_address %}\n\t\t\t{{ company_address }}\n\t\t\t<b>{{ _(\"GSTIN\") }}:</b>{{ doc.company_gstin }}\n\t\t{% else %}\n\t\t\t{{ company_address.replace(\"GSTIN\", \"<br>GSTIN\") }}\n\t\t{% endif %}\n\t{% endif %}\n\t<br>\n\t<b>{{ doc.select_print_heading or _(\"Invoice\") }}</b><br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t{% if doc.grand_total > 50000 %}\n\t\t{% set customer_address = doc.address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t<b>{{ _(\"Customer\") }}:</b><br>\n\t\t{{ doc.customer_name }}<br>\n\t\t{{ customer_address }}\n\t{% endif %}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"40%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.gst_hsn_code -%}\n\t\t\t\t\t<br><b>{{ _(\"HSN/SAC\") }}:</b> {{ item.gst_hsn_code }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t<br><b>{{ _(\"Serial No\") }}:</b> {{ item.serial_no }}\n\t\t\t\t{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.rate }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% else %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% endif %}\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t</td>\n\t\t\t<tr>\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.rounded_total -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Rounded Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"rounded_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t</tbody>\n</table>\n<p><b>Tax Breakup:</b></p>\n<div style=\"font-size: 8px\">\n\t{{ doc.other_charges_calculation }}\n</div>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"idx": 0,
"line_breaks": 0,
"modified": "2017-12-15 11:57:11.712191",
"modified": "2018-01-12 11:19:17.432600",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GST POS Invoice",

View File

@@ -1,15 +1,21 @@
{
"align_labels_right": 0,
"creation": "2011-12-21 11:08:55",
"custom_format": 1,
"disabled": 1,
"doc_type": "Sales Invoice",
"docstatus": 0,
"doctype": "Print Format",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Invoice\") }}<br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t<b>{{ _(\"Customer\") }}:</b> {{ doc.customer_name }}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.get_formatted(\"rate\") }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ _(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"net_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t{%- if not row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n{% if doc.get(\"taxes\", filters={\"included_in_print_rate\": 1}) %}\n<hr>\n<p><b>Taxes Included:</b></p>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t{%- for row in doc.taxes -%}\n\t\t{%- if row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount_after_discount_amount\", doc) }}\n\t\t\t</td>\n\t\t<tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n{%- endif -%}\n<hr>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Invoice\") }}<br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t<b>{{ _(\"Customer\") }}:</b> {{ doc.customer_name }}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.get_formatted(\"rate\") }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% else %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% endif %}\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t</td>\n\t\t\t<tr>\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.rounded_total -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Rounded Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"rounded_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t</tbody>\n</table>\n<hr>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"idx": 1,
"modified": "2015-04-21 05:06:29.380856",
"line_breaks": 0,
"modified": "2018-01-12 11:18:54.229254",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
"owner": "Administrator",
"print_format_builder": 0,
"print_format_type": "Server",
"show_section_headings": 0,
"standard": "Yes"
}

View File

@@ -23,10 +23,10 @@ frappe.query_reports["Accounts Receivable"] = {
"options": "Customer Group"
},
{
"fieldname":"credit_days_based_on",
"label": __("Credit Days Based On"),
"fieldtype": "Select",
"options": "\nFixed Days\nLast Day of the Next Month"
"fieldname":"payment_terms_template",
"label": __("Payment Terms Template"),
"fieldtype": "Link",
"options": "Payment Terms Template"
},
{
"fieldtype": "Break",

View File

@@ -283,9 +283,9 @@ class ReceivablePayableReport(object):
where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1}
and name=tabCustomer.customer_group))""".format(lft, rgt))
if self.filters.get("credit_days_based_on"):
conditions.append("party in (select name from tabCustomer where credit_days_based_on=%s)")
values.append(self.filters.get("credit_days_based_on"))
if self.filters.get("payment_terms_template"):
conditions.append("party in (select name from tabCustomer where payment_terms=%s)")
values.append(self.filters.get("payment_terms_template"))
return " and ".join(conditions), values

View File

@@ -23,10 +23,10 @@ frappe.query_reports["Accounts Receivable Summary"] = {
"options": "Customer Group"
},
{
"fieldname":"credit_days_based_on",
"label": __("Credit Days Based On"),
"fieldtype": "Select",
"options": "\nFixed Days\nLast Day of the Next Month"
"fieldname":"payment_terms_template",
"label": __("Payment Terms Template"),
"fieldtype": "Link",
"options": "Payment Terms Template"
},
{
"fieldtype": "Break",

View File

@@ -17,38 +17,70 @@
<table class="table table-bordered">
<thead>
<tr>
<th style="width: 15%">{%= __("Date") %}</th>
<th style="width: 12%">{%= __("Date") %}</th>
<th style="width: 15%">{%= __("Ref") %}</th>
<th style="width: 40%">{%= __("Party") %}</th>
<th style="width: 25%">{%= __("Party") %}</th>
<th style="width: 15%">{%= __("Debit") %}</th>
<th style="width: 15%">{%= __("Credit") %}</th>
<th style="width: 18%">{%= __("Balance") %}</th>
</tr>
</thead>
<tbody>
{% for(var i=0, l=data.length; i<l; i++) { %}
<tr>
{% if(data[i][__("Posting Date")]) { %}
<td>{%= dateutil.str_to_user(data[i][__("Posting Date")]) %}</td>
<td>{%= data[i][__("Voucher Type")] %}
<br>{%= data[i][__("Voucher No")] %}</td>
{% if(data[i].posting_date) { %}
<td>{%= dateutil.str_to_user(data[i].posting_date) %}</td>
<td>{%= data[i].voucher_type %}
<br>{%= data[i].voucher_no %}</td>
<td>
{% if(!(filters.party || filters.account)) { %}
{%= data[i][__("Party")] || data[i][__("Account")] %}
{%= data[i].party || data[i].account %}
<br>
{% } %}
{{ __("Against") }}: {%= data[i][__("Against Account")] %}
<br>{%= __("Remarks") %}: {%= data[i][__("Remarks")] %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Credit")]) %}</td>
{{ __("Against") }}: {%= data[i].against %}
<br>{%= __("Remarks") %}: {%= data[i].remarks %}
{% if(data[i].bill_no) { %}
<br>{%= __("Supplier Invoice No") %}: {%= data[i].bill_no %}
{% } %}
</td>
{% if(filters.print_in_account_currency) { %}
<td style="text-align: right">
{%= format_currency(data[i].debit_in_account_currency, data[i].account_currency) %}
</td>
<td style="text-align: right">
{%= format_currency(data[i].credit_in_account_currency, data[i].account_currency) %}
</td>
{% } else { %}
<td style="text-align: right">
{%= format_currency(data[i].debit) %}</td>
<td style="text-align: right">
{%= format_currency(data[i].credit) %}</td>
{% } %}
{% } else { %}
<td></td>
<td></td>
<td><b>{%= frappe.format(data[i][__("Account")], {fieldtype: "Link"}) || "&nbsp;" %}</b></td>
<td style="text-align: right">
{%= data[i][__("Account")] && format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">
{%= data[i][__("Account")] && format_currency(data[i][__("Credit")]) %}</td>
<td><b>{%= frappe.format(data[i].account, {fieldtype: "Link"}) || "&nbsp;" %}</b></td>
{% if(filters.print_in_account_currency) { %}
<td style="text-align: right">
{%= data[i].account && format_currency(data[i].debit_in_account_currency, data[i].account_currency) %}</td>
<td style="text-align: right">
{%= data[i].account && format_currency(data[i].credit_in_account_currency, data[i].account_currency) %}</td>
{% } else { %}
<td style="text-align: right">
{%= data[i].account && format_currency(data[i].debit) %}
</td>
<td style="text-align: right">
{%= data[i].account && format_currency(data[i].credit) %}
</td>
{% } %}
{% } %}
{% if(filters.print_in_account_currency) { %}
<td style="text-align: right">{%= get_currency_symbol(data[i].account_currency)%}
{%= data[i].balance_in_account_currency %}</td>
{% } else { %}
<td style="text-align: right">{%= get_currency_symbol()%}
{%= data[i].balance %}</td>
{% } %}
</tr>
{% } %}

View File

@@ -105,6 +105,11 @@ frappe.query_reports["General Ledger"] = {
"fieldname":"group_by_account",
"label": __("Group by Account"),
"fieldtype": "Check",
},
{
"fieldname":"print_in_account_currency",
"label": __("Print in Account Currency"),
"fieldtype": "Check",
}
]
}

View File

@@ -3,12 +3,17 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import getdate, cstr, flt
from frappe.utils import getdate, cstr, flt, fmt_money
from frappe import _, _dict
from erpnext.accounts.utils import get_account_currency
def execute(filters=None):
account_details = {}
if filters and filters.get('print_in_account_currency') and \
not filters.get('account'):
frappe.throw(_("Select an account to print in account currency"))
for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1):
account_details.setdefault(acc.name, acc)
@@ -76,28 +81,6 @@ def set_account_currency(filters):
return filters
def get_columns(filters):
columns = [
_("Posting Date") + ":Date:90", _("Account") + ":Link/Account:200",
_("Debit") + ":Float:100", _("Credit") + ":Float:100"
]
if filters.get("show_in_account_currency"):
columns += [
_("Debit") + " (" + filters.account_currency + ")" + ":Float:100",
_("Credit") + " (" + filters.account_currency + ")" + ":Float:100"
]
columns += [
_("Voucher Type") + "::120", _("Voucher No") + ":Dynamic Link/"+_("Voucher Type")+":160",
_("Against Account") + "::120", _("Party Type") + "::80", _("Party") + "::150",
_("Project") + ":Link/Project:100", _("Cost Center") + ":Link/Cost Center:100",
_("Against Voucher Type") + "::120", _("Against Voucher") + ":Dynamic Link/"+_("Against Voucher Type")+":160",
_("Remarks") + "::400"
]
return columns
def get_result(filters, account_details):
gl_entries = get_gl_entries(filters)
@@ -193,24 +176,6 @@ def get_data_with_opening_closing(filters, account_details, gl_entries):
# closing
data.append(totals.closing)
#total closing
total_closing = totals.total_closing
total_debit = totals.closing.get('debit', 0)
total_credit = totals.closing.get('credit', 0)
debit_in_account_currency = totals.closing.get('debit_in_account_currency', 0)
credit_in_account_currency = totals.closing.get('credit_in_account_currency', 0)
total_amount = total_debit - total_credit
if total_amount > 0:
total_closing['debit'] = total_amount
total_closing['debit_in_account_currency'] = debit_in_account_currency - credit_in_account_currency
else:
total_closing['credit'] = abs(total_amount)
total_closing['credit_in_account_currency'] = abs(debit_in_account_currency - credit_in_account_currency)
data.append(totals.total_closing)
return data
def get_totals_dict():
@@ -225,8 +190,7 @@ def get_totals_dict():
return _dict(
opening = _get_debit_credit_dict(_('Opening')),
total = _get_debit_credit_dict(_('Total')),
closing = _get_debit_credit_dict(_('Closing (Opening + Total)')),
total_closing = _get_debit_credit_dict(_('Closing Balance (Dr - Cr)'))
closing = _get_debit_credit_dict(_('Closing (Opening + Total)'))
)
def initialize_gle_map(gl_entries):
@@ -270,17 +234,164 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
return totals, entries
def get_result_as_list(data, filters):
result = []
balance, balance_in_account_currency = 0, 0
inv_details = get_supplier_invoice_details()
for d in data:
row = [d.get("posting_date"), d.get("account"), d.get("debit"), d.get("credit")]
if not d.get('posting_date'):
balance, balance_in_account_currency = 0, 0
balance, label = get_balance(d, balance, 'debit', 'credit')
d['balance'] = '{0} {1}'.format(fmt_money(abs(balance)), label)
if filters.get("show_in_account_currency"):
row += [d.get("debit_in_account_currency"), d.get("credit_in_account_currency")]
balance_in_account_currency, label = get_balance(d, balance_in_account_currency,
'debit_in_account_currency', 'credit_in_account_currency')
d['balance_in_account_currency'] = '{0} {1}'.format(fmt_money(abs(balance_in_account_currency)), label)
else:
d['debit_in_account_currency'] = d.get('debit', 0)
d['credit_in_account_currency'] = d.get('credit', 0)
d['balance_in_account_currency'] = d.get('balance')
row += [d.get("voucher_type"), d.get("voucher_no"), d.get("against"),
d.get("party_type"), d.get("party"), d.get("project"), d.get("cost_center"), d.get("against_voucher_type"), d.get("against_voucher"), d.get("remarks")
]
d['account_currency'] = filters.account_currency
d['bill_no'] = inv_details.get(d.get('against_voucher'), '')
result.append(row)
return data
return result
def get_supplier_invoice_details():
inv_details = {}
for d in frappe.db.sql(""" select name, bill_no from `tabPurchase Invoice`
where docstatus = 1 and bill_no is not null and bill_no != '' """, as_dict=1):
inv_details[d.name] = d.bill_no
return inv_details
def get_balance(row, balance, debit_field, credit_field):
balance += (row.get(debit_field, 0) - row.get(credit_field, 0))
label = 'DR' if balance > 0 else 'CR'
return balance, label
def get_columns(filters):
columns = [
{
"label": _("Posting Date"),
"fieldname": "posting_date",
"fieldtype": "Date",
"width": 90
},
{
"label": _("Account"),
"fieldname": "account",
"fieldtype": "Link",
"options": "Account",
"width": 180
},
{
"label": _("Debit"),
"fieldname": "debit",
"fieldtype": "Float",
"width": 100
},
{
"label": _("Credit"),
"fieldname": "credit",
"fieldtype": "Float",
"width": 100
},
{
"label": _("Balance"),
"fieldname": "balance",
"fieldtype": "Data",
"width": 100
}
]
if filters.get("show_in_account_currency"):
columns.extend([
{
"label": _("Debit") + " (" + filters.account_currency + ")",
"fieldname": "debit_in_account_currency",
"fieldtype": "Float",
"width": 100
},
{
"label": _("Credit") + " (" + filters.account_currency + ")",
"fieldname": "credit_in_account_currency",
"fieldtype": "Float",
"width": 100
},
{
"label": _("Balance") + " (" + filters.account_currency + ")",
"fieldname": "balance_in_account_currency",
"fieldtype": "Data",
"width": 100
}
])
columns.extend([
{
"label": _("Voucher Type"),
"fieldname": "voucher_type",
"width": 120
},
{
"label": _("Voucher No"),
"fieldname": "voucher_no",
"fieldtype": "Dynamic Link",
"options": "voucher_type",
"width": 180
},
{
"label": _("Against Account"),
"fieldname": "against",
"width": 120
},
{
"label": _("Party Type"),
"fieldname": "party_type",
"width": 100
},
{
"label": _("Party"),
"fieldname": "party",
"width": 100
},
{
"label": _("Project"),
"options": "Project",
"fieldname": "project",
"width": 100
},
{
"label": _("Cost Center"),
"options": "Cost Center",
"fieldname": "cost_center",
"width": 100
},
{
"label": _("Against Voucher Type"),
"fieldname": "against_voucher_type",
"width": 100
},
{
"label": _("Against Voucher"),
"fieldname": "against_voucher",
"fieldtype": "Dynamic Link",
"options": "against_voucher_type",
"width": 100
},
{
"label": _("Supplier Invoice No"),
"fieldname": "bill_no",
"fieldtype": "Data",
"width": 100
},
{
"label": _("Remarks"),
"fieldname": "remarks",
"width": 400
}
])
return columns

View File

@@ -6,7 +6,6 @@ import frappe
from frappe import _, scrub
from erpnext.stock.utils import get_incoming_rate
from erpnext.controllers.queries import get_match_cond
from erpnext.stock.stock_ledger import get_valuation_rate
from frappe.utils import flt
@@ -248,6 +247,7 @@ class GrossProfitGenerator(object):
return 0.0
def get_average_buying_rate(self, row, item_code):
args = row
if not item_code in self.average_buying_rate:
if item_code in self.non_stock_items:
self.average_buying_rate[item_code] = flt(frappe.db.sql("""
@@ -255,12 +255,14 @@ class GrossProfitGenerator(object):
from `tabPurchase Invoice Item`
where item_code = %s and docstatus=1""", item_code)[0][0])
else:
average_buying_rate = get_incoming_rate(row)
if not average_buying_rate:
average_buying_rate = get_valuation_rate(item_code, row.warehouse,
row.parenttype, row.parent, allow_zero_rate=True,
currency=self.filters.currency, company=self.filters.company)
args.update({
'voucher_type': row.parenttype,
'voucher_no': row.parent,
'allow_zero_valuation': True,
'company': self.filters.company
})
average_buying_rate = get_incoming_rate(args)
self.average_buying_rate[item_code] = flt(average_buying_rate)
return self.average_buying_rate[item_code]

View File

@@ -36,8 +36,8 @@ def get_sales_payment_data(filters, columns):
return data
def get_conditions(filters):
conditions = ""
if filters.get("from_date"): conditions += "a.posting_date >= %(from_date)s"
conditions = "1=1"
if filters.get("from_date"): conditions += " and a.posting_date >= %(from_date)s"
if filters.get("to_date"): conditions += " and a.posting_date <= %(to_date)s"
if filters.get("company"): conditions += " and a.company=%(company)s"
if filters.get("customer"): conditions += " and a.customer = %(customer)s"

View File

@@ -252,7 +252,7 @@ def add_ac(args=None):
if not ac.parent_account:
ac.parent_account = args.get("parent")
if ac.is_root:
if getattr(ac, 'is_root', None):
ac.parent_account=''
ac.old_parent = ""

View File

@@ -51,9 +51,6 @@ class Asset(Document):
if not self.get(field):
self.set(field, value)
self.value_after_depreciation = (flt(self.gross_purchase_amount) -
flt(self.opening_accumulated_depreciation))
def validate_asset_values(self):
if flt(self.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
frappe.throw(_("Expected Value After Useful Life must be less than Gross Purchase Amount"))
@@ -61,7 +58,10 @@ class Asset(Document):
if not flt(self.gross_purchase_amount):
frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError)
if not self.is_existing_asset and self.calculate_depreciation:
if not self.calculate_depreciation:
return
if not self.is_existing_asset:
self.opening_accumulated_depreciation = 0
self.number_of_depreciations_booked = 0
if not self.next_depreciation_date:
@@ -81,6 +81,9 @@ class Asset(Document):
if cint(self.number_of_depreciations_booked) > cint(self.total_number_of_depreciations):
frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations"))
self.value_after_depreciation = (flt(self.gross_purchase_amount) -
flt(self.opening_accumulated_depreciation))
if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(nowdate()):
frappe.msgprint(_("Next Depreciation Date is entered as past date"), title=_('Warning'), indicator='red')
@@ -106,12 +109,13 @@ class Asset(Document):
n * cint(self.frequency_of_depreciation))
depreciation_amount = self.get_depreciation_amount(value_after_depreciation)
value_after_depreciation -= flt(depreciation_amount)
if depreciation_amount:
value_after_depreciation -= flt(depreciation_amount)
self.append("schedules", {
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount
})
self.append("schedules", {
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount
})
def set_accumulated_depreciation(self):
accumulated_depreciation = flt(self.opening_accumulated_depreciation)

View File

@@ -151,13 +151,11 @@ def restore_asset(asset_name):
asset.set_status()
@frappe.whitelist()
def get_gl_entries_on_asset_disposal(asset, is_sale=False):
def get_gl_entries_on_asset_disposal(asset, selling_amount=0):
fixed_asset_account, accumulated_depr_account, depr_expense_account = get_depreciation_accounts(asset)
accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(asset.value_after_depreciation)
disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(asset.company)
expense_account, cost_center = get_disposal_account_and_cost_center(asset.company)
if is_sale:
expense_account = depr_expense_account
accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(asset.value_after_depreciation)
gl_entries = [
{
@@ -172,12 +170,14 @@ def get_gl_entries_on_asset_disposal(asset, is_sale=False):
}
]
if flt(asset.value_after_depreciation):
profit_amount = flt(selling_amount) - flt(asset.value_after_depreciation)
if profit_amount:
debit_or_credit = "debit" if profit_amount < 0 else "credit"
gl_entries.append({
"account": expense_account,
"cost_center": cost_center,
"debit": flt(asset.value_after_depreciation),
"debit_in_account_currency": flt(asset.value_after_depreciation)
"account": disposal_account,
"cost_center": depreciation_cost_center,
debit_or_credit: abs(profit_amount),
debit_or_credit + "_in_account_currency": abs(profit_amount)
})
return gl_entries

View File

@@ -234,9 +234,8 @@ class TestAsset(unittest.TestCase):
expected_gle = (
("_Test Accumulated Depreciations - _TC", 30000.0, 0.0),
("_Test Depreciations - _TC", 70000.0, 0.0),
("_Test Fixed Asset - _TC", 0.0, 100000.0),
("_Test Gain/Loss on Asset Disposal - _TC", 0.0, 25000.0),
("_Test Gain/Loss on Asset Disposal - _TC", 45000.0, 0.0),
("Debtors - _TC", 25000.0, 0.0)
)

View File

@@ -225,7 +225,7 @@
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"modified": "2015-08-25 04:55:06.052342",
"modified": "2017-12-27 15:20:06.052342",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",

View File

@@ -21,22 +21,17 @@ frappe.ui.form.on("Purchase Order", {
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);
}
frm.set_indicator_formatter('item_code',
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
},
});
frappe.ui.form.on("Purchase Order Item", {
item_code: function(frm) {
frappe.call({
method: "get_last_purchase_rate",
doc: frm.doc,
callback: function(r, rt) {
frm.trigger('calculate_taxes_and_totals');
}
})
},
schedule_date: function(frm, cdt, cdn) {
var row = locals[cdt][cdn];
if (row.schedule_date) {

View File

@@ -41,11 +41,11 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "{supplier_name}",
@@ -292,40 +292,40 @@
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "schedule_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Reqd By Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "schedule_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Reqd By Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1238,6 +1238,37 @@
"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,
@@ -3260,9 +3291,9 @@
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-19 14:53:03.986840",
"modified_by": "nabinhait@gmail.com",
"max_attachments": 0,
"modified": "2017-12-21 14:45:34.140128",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
"owner": "Administrator",

View File

@@ -34,6 +34,12 @@ class PurchaseOrder(BuyingController):
'overflow_type': 'order'
}]
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()
@@ -111,27 +117,26 @@ 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
if not cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")):
conversion_rate = flt(self.get('conversion_rate')) or 1.0
conversion_rate = flt(self.get('conversion_rate')) or 1.0
for d in self.get("items"):
if d.item_code:
last_purchase_details = get_last_purchase_details(d.item_code, self.name)
if last_purchase_details:
d.base_price_list_rate = (last_purchase_details['base_price_list_rate'] *
(flt(d.conversion_factor) or 1.0))
d.discount_percentage = last_purchase_details['discount_percentage']
d.base_rate = last_purchase_details['base_rate'] * (flt(d.conversion_factor) or 1.0)
d.price_list_rate = d.base_price_list_rate / conversion_rate
d.rate = d.base_rate / conversion_rate
d.last_purchase_rate = d.rate
else:
for d in self.get("items"):
if d.item_code:
last_purchase_details = get_last_purchase_details(d.item_code, self.name)
if last_purchase_details:
d.base_price_list_rate = (last_purchase_details['base_price_list_rate'] *
(flt(d.conversion_factor) or 1.0))
d.discount_percentage = last_purchase_details['discount_percentage']
d.base_rate = last_purchase_details['base_rate'] * (flt(d.conversion_factor) or 1.0)
d.price_list_rate = d.base_price_list_rate / conversion_rate
d.last_purchase_rate = d.base_rate / conversion_rate
else:
item_last_purchase_rate = frappe.db.get_value("Item", d.item_code, "last_purchase_rate")
if item_last_purchase_rate:
d.base_price_list_rate = d.base_rate = d.price_list_rate \
= d.last_purchase_rate = item_last_purchase_rate
item_last_purchase_rate = frappe.db.get_value("Item", d.item_code, "last_purchase_rate")
if item_last_purchase_rate:
d.base_price_list_rate = d.base_rate = d.price_list_rate \
= d.rate = d.last_purchase_rate = item_last_purchase_rate
# Check for Closed status
def check_for_closed_status(self):
@@ -256,6 +261,21 @@ class PurchaseOrder(BuyingController):
if item.delivered_by_supplier == 1:
item.received_qty = item.qty
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
last_purchase_details = get_last_purchase_details(item_code, name)
if last_purchase_details:
last_purchase_rate = (last_purchase_details['base_rate'] * (flt(conversion_factor) or 1.0)) / conversion_rate
return last_purchase_rate
else:
item_last_purchase_rate = frappe.db.get_value("Item", item_code, "last_purchase_rate")
if item_last_purchase_rate:
return item_last_purchase_rate
@frappe.whitelist()
def close_or_unclose_purchase_orders(names, status):
if not frappe.has_permission("Purchase Order", "write"):

View File

@@ -9,7 +9,6 @@
"doctype": "Supplier",
"supplier_name": "_Test Supplier P",
"supplier_type": "_Test Supplier Type",
"credit_days_based_on": "Fixed Days"
},
{
"doctype": "Supplier",

View File

@@ -54,6 +54,7 @@ class AccountsController(TransactionBase):
if self.meta.get_field("taxes_and_charges"):
self.validate_enabled_taxes_and_charges()
self.validate_tax_account_company()
self.validate_party()
self.validate_currency()
@@ -134,9 +135,9 @@ class AccountsController(TransactionBase):
if not self.due_date:
frappe.throw(_("Due Date is mandatory"))
validate_due_date(self.posting_date, self.due_date, "Customer", self.customer)
validate_due_date(self.posting_date, self.due_date, "Customer", self.customer, self.company)
elif self.doctype == "Purchase Invoice":
validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier)
validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company)
def set_price_list_currency(self, buying_or_selling):
if self.meta.get_field("posting_date"):
@@ -255,6 +256,14 @@ class AccountsController(TransactionBase):
if frappe.db.get_value(taxes_and_charges_doctype, self.taxes_and_charges, "disabled"):
frappe.throw(_("{0} '{1}' is disabled").format(taxes_and_charges_doctype, self.taxes_and_charges))
def validate_tax_account_company(self):
for d in self.get("taxes"):
if d.account_head:
tax_account_company = frappe.db.get_value("Account", d.account_head, "company")
if tax_account_company != self.company:
frappe.throw(_("Row #{0}: Account {1} does not belong to company {2}")
.format(d.idx, d.account_head, self.company))
def get_gl_dict(self, args, account_currency=None):
"""this method populates the common properties of a gl entry record"""
@@ -375,6 +384,17 @@ class AccountsController(TransactionBase):
return res
def is_inclusive_tax(self):
is_inclusive = cint(frappe.db.get_single_value("Accounts Settings",
"show_inclusive_tax_in_print"))
if is_inclusive:
is_inclusive = 0
if self.get("taxes", filters={"included_in_print_rate": 1}):
is_inclusive = 1
return is_inclusive
def validate_advance_entries(self):
order_field = "sales_order" if self.doctype == "Sales Invoice" else "purchase_order"
order_list = list(set([d.get(order_field)
@@ -464,7 +484,7 @@ class AccountsController(TransactionBase):
max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100)
if total_billed_amt - max_allowed_amt > 0.01:
frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set in Buying Settings").format(item.item_code, item.idx, max_allowed_amt))
frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set in Stock Settings").format(item.item_code, item.idx, max_allowed_amt))
def get_company_default(self, fieldname):
from erpnext.accounts.utils import get_company_default
@@ -646,7 +666,7 @@ class AccountsController(TransactionBase):
self.remove(item)
def set_payment_schedule(self):
posting_date = self.get("posting_date") or self.get("transaction_date")
posting_date = self.get("bill_date") or self.get("posting_date") or self.get("transaction_date")
date = self.get("due_date")
due_date = date or posting_date
grand_total = self.get("rounded_total") or self.grand_total
@@ -711,11 +731,15 @@ def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
@frappe.whitelist()
def get_default_taxes_and_charges(master_doctype, company=None):
def get_default_taxes_and_charges(master_doctype, tax_template=None, company=None):
if not company: return {}
default_tax = frappe.db.get_value(master_doctype,
{"is_default": 1, "company": company})
if tax_template and company:
tax_template_company = frappe.db.get_value(master_doctype, tax_template, "company")
if tax_template_company == company:
return
default_tax = frappe.db.get_value(master_doctype, {"is_default": 1, "company": company})
return {
'taxes_and_charges': default_tax,

View File

@@ -18,7 +18,10 @@ class BuyingController(StockController):
if hasattr(self, "taxes"):
self.flags.print_taxes_with_zero_amount = cint(frappe.db.get_single_value("Print Settings",
"print_taxes_with_zero_amount"))
self.flags.show_inclusive_tax_in_print = self.is_inclusive_tax()
self.print_templates = {
"total": "templates/print_formats/includes/total.html",
"taxes": "templates/print_formats/includes/taxes.html"
}
@@ -430,7 +433,8 @@ class BuyingController(StockController):
if not d.schedule_date:
d.schedule_date = self.schedule_date
if d.schedule_date and getdate(d.schedule_date) < getdate(self.transaction_date):
if (d.schedule_date and self.transaction_date and
getdate(d.schedule_date) < getdate(self.transaction_date)):
frappe.throw(_("Row #{0}: Reqd by Date cannot be before Transaction Date").format(d.idx))
else:
frappe.throw(_("Please enter Reqd by Date"))

View File

@@ -152,7 +152,7 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
conditions = []
return frappe.db.sql("""select tabItem.name, tabItem.item_group, tabItem.image,
return frappe.db.sql("""select tabItem.name, tabItem.item_group,
if(length(tabItem.item_name) > 40,
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
if(length(tabItem.description) > 40, \
@@ -414,10 +414,11 @@ def get_doctype_wise_filters(filters):
@frappe.whitelist()
def get_batch_numbers(doctype, txt, searchfield, start, page_len, filters):
query = 'select batch_id from `tabBatch` ' \
'where (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)'
query = """select batch_id from `tabBatch`
where (expiry_date >= CURDATE() or expiry_date IS NULL)
and name like '{txt}'""".format(txt = frappe.db.escape('%{0}%'.format(txt)))
if filters and filters.get('item_code'):
query += 'where item = %(item_code)s' % filters
if filters and filters.get('item'):
query += " and item = '{item}'".format(item = frappe.db.escape(filters.get('item')))
return frappe.db.sql(query)

View File

@@ -16,7 +16,10 @@ class SellingController(StockController):
if hasattr(self, "taxes"):
self.flags.print_taxes_with_zero_amount = cint(frappe.db.get_single_value("Print Settings",
"print_taxes_with_zero_amount"))
self.flags.show_inclusive_tax_in_print = self.is_inclusive_tax()
self.print_templates = {
"total": "templates/print_formats/includes/total.html",
"taxes": "templates/print_formats/includes/taxes.html"
}

View File

@@ -232,7 +232,7 @@ def make_quotation(source_name, target_doc=None):
quotation.conversion_rate = exchange_rate
# get default taxes
taxes = get_default_taxes_and_charges("Sales Taxes and Charges Template", quotation.company)
taxes = get_default_taxes_and_charges("Sales Taxes and Charges Template", company=quotation.company)
if taxes.get('taxes'):
quotation.update(taxes)

View File

@@ -269,7 +269,10 @@ def get_grade(grading_scale, percentage):
:param Percentage: Score Percentage Percentage
"""
grading_scale_intervals = {}
for d in frappe.get_all("Grading Scale Interval", fields=["grade_code", "threshold"], filters={"parent": grading_scale}):
if not hasattr(frappe.local, 'grading_scale'):
grading_scale = frappe.get_all("Grading Scale Interval", fields=["grade_code", "threshold"], filters={"parent": grading_scale})
frappe.local.grading_scale = grading_scale
for d in frappe.local.grading_scale:
grading_scale_intervals.update({d.threshold:d.grade_code})
intervals = sorted(grading_scale_intervals.keys(), key=float, reverse=True)
for interval in intervals:

View File

@@ -6,5 +6,9 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
STD_CRITERIA = ["total", "total score", "total grade", "maximum score", "score", "grade"]
class AssessmentCriteria(Document):
pass
def validate(self):
if self.assessment_criteria.lower() in STD_CRITERIA:
frappe.throw("Can't create standard criteria. Please rename the criteria")

View File

@@ -1,41 +1,46 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
cur_frm.add_fetch("student_group", "course", "course");
cur_frm.add_fetch("examiner", "instructor_name", "examiner_name");
cur_frm.add_fetch("supervisor", "instructor_name", "supervisor_name");
cur_frm.add_fetch("course", "default_grading_scale", "grading_scale");
frappe.ui.form.on("Assessment Plan", {
onload: function(frm) {
frm.set_query("assessment_group", function(doc, cdt, cdn) {
return{
filters: {
'is_group': 0
}
}
});
},
refresh: function(frm) {
if (frm.doc.docstatus == 1) {
frm.add_custom_button(__("Assessment Result"), function() {
frappe.route_options = {
assessment_plan: frm.doc.name,
student_group: frm.doc.student_group
}
frappe.set_route("Form", "Assessment Result Tool");
});
}
setup: function(frm) {
frm.add_fetch("student_group", "course", "course");
frm.add_fetch("student_group", "program", "program");
frm.add_fetch("student_group", "academic_year", "academic_year");
frm.add_fetch("student_group", "academic_term", "academic_term");
frm.add_fetch("examiner", "instructor_name", "examiner_name");
frm.add_fetch("supervisor", "instructor_name", "supervisor_name");
frm.add_fetch("course", "default_grading_scale", "grading_scale");
},
onload: function(frm) {
frm.set_query("assessment_group", function(doc, cdt, cdn) {
return{
filters: {
'is_group': 0
}
};
});
frm.set_query('grading_scale', function(){
return {
filters: {
docstatus: 1
}
}
};
});
},
},
refresh: function(frm) {
if (frm.doc.docstatus == 1) {
frm.add_custom_button(__("Assessment Result"), function() {
frappe.route_options = {
assessment_plan: frm.doc.name,
student_group: frm.doc.student_group
}
frappe.set_route("Form", "Assessment Result Tool");
});
}
},
course: function(frm) {
if (frm.doc.course && frm.doc.maximum_assessment_score) {

View File

@@ -13,36 +13,6 @@
"editable_grid": 0,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "assessment_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Assessment Name",
"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,
@@ -80,19 +50,80 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "course",
"fieldtype": "Link",
"fieldname": "assessment_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Course",
"in_standard_filter": 0,
"label": "Assessment Name",
"length": 0,
"no_copy": 0,
"options": "Course",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "assessment_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Assessment Group",
"length": 0,
"no_copy": 0,
"options": "Assessment Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grading_scale",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Grading Scale",
"length": 0,
"no_copy": 0,
"options": "Grading Scale",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -140,19 +171,50 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "assessment_group",
"fieldname": "course",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Assessment Group",
"label": "Course",
"length": 0,
"no_copy": 0,
"options": "Assessment Group",
"options": "Course",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "program",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Program",
"length": 0,
"no_copy": 0,
"options": "Program",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -171,8 +233,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "maximum_assessment_score",
"fieldtype": "Float",
"fieldname": "academic_year",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -180,9 +242,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Maximum Assessment Score",
"label": "Academic Year",
"length": 0,
"no_copy": 0,
"options": "Academic Year",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -190,7 +253,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -201,7 +264,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grading_scale",
"fieldname": "academic_term",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -209,11 +272,11 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Grading Scale",
"in_standard_filter": 0,
"label": "Academic Term",
"length": 0,
"no_copy": 0,
"options": "Grading Scale",
"options": "Academic Term",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -221,7 +284,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -546,6 +609,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Evaluate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -560,6 +624,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "maximum_assessment_score",
"fieldtype": "Float",
"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": "Maximum Assessment Score",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -633,7 +727,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-11-28 17:23:36.657725",
"modified": "2018-01-08 17:53:39.340356",
"modified_by": "Administrator",
"module": "Education",
"name": "Assessment Plan",

View File

@@ -9,10 +9,22 @@ from frappe import _
class AssessmentPlan(Document):
def validate(self):
self.set_missing_field()
self.validate_overlap()
self.validate_max_score()
self.validate_assessment_criteria()
def set_missing_field(self):
if self.student_group:
academic_term, academic_year, program, course = frappe.get_value("Student Group", self.student_group,
["academic_term", "academic_year", "program", "course"])
self.academic_term = academic_term
self.academic_year = academic_year
if program:
self.program = program
if course and not self.course: #pylint: disable=E0203
self.course = course
def validate_overlap(self):
"""Validates overlap for Student Group, Instructor, Room"""

View File

@@ -1,11 +1,29 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
cur_frm.add_fetch("student", "title", "student_name");
cur_frm.add_fetch("assessment_plan", "grading_scale", "grading_scale");
cur_frm.add_fetch("assessment_plan", "maximum_assessment_score", "maximum_score");
frappe.ui.form.on("Assessment Result", {
setup: function(frm) {
frm.add_fetch("student", "title", "student_name");
frm.add_fetch("assessment_plan", "course", "course");
frm.add_fetch("assessment_plan", "program", "program");
frm.add_fetch("assessment_plan", "academic_year", "academic_year");
frm.add_fetch("assessment_plan", "academic_term", "academic_term");
frm.add_fetch("assessment_plan", "grading_scale", "grading_scale");
frm.add_fetch("assessment_plan", "student_group", "student_group");
frm.add_fetch("assessment_plan", "assessment_group", "assessment_group");
frm.add_fetch("assessment_plan", "maximum_assessment_score", "maximum_score");
},
onload: function(frm) {
frm.set_query('assessment_plan', function(){
return {
filters: {
docstatus: 1
}
};
});
},
assessment_plan: function(frm) {
if (frm.doc.assessment_plan) {
frappe.call({

View File

@@ -13,6 +13,190 @@
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "assessment_plan",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Assessment Plan",
"length": 0,
"no_copy": 0,
"options": "Assessment Plan",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "program",
"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": "Program",
"length": 0,
"no_copy": 0,
"options": "Program",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "course",
"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": "Course",
"length": 0,
"no_copy": 0,
"options": "Course",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "academic_year",
"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": "Academic Year",
"length": 0,
"no_copy": 0,
"options": "Academic Year",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "academic_term",
"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": "Academic Term",
"length": 0,
"no_copy": 0,
"options": "Academic Term",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "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,
"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,
@@ -80,8 +264,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"fieldname": "student_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -89,8 +273,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Student Group",
"length": 0,
"no_copy": 0,
"options": "Student Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -109,19 +295,19 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "assessment_plan",
"fieldname": "assessment_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Assessment Plan",
"label": "Assessment Group",
"length": 0,
"no_copy": 0,
"options": "Assessment Plan",
"options": "Assessment Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -129,7 +315,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -180,6 +366,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Result",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -285,6 +472,35 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_11",
"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,
@@ -315,35 +531,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_11",
"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,
@@ -389,6 +576,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Summary",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -474,7 +662,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-11-10 18:58:32.114529",
"modified": "2018-01-09 14:14:30.090317",
"modified_by": "Administrator",
"module": "Education",
"name": "Assessment Result",

View File

@@ -14,15 +14,25 @@ from frappe.utils.csvutils import getlink
class AssessmentResult(Document):
def validate(self):
if self.student and not self.student_name:
self.student_name = frappe.db.get_value("Student", self.student, "title")
self.grading_scale = frappe.db.get_value("Assessment Plan", self.assessment_plan, "grading_scale")
self.set_missing_values()
self.validate_maximum_score()
self.validate_grade()
self.validate_duplicate()
def set_missing_values(self):
if self.student and not self.student_name:
self.student_name = frappe.db.get_value("Student", self.student, "title")
assessment_plan_details = frappe.get_value("Assessment Plan", self.assessment_plan, ["academic_term",
"academic_year", "program", "course", "grading_scale", "assessment_group", "student_group",
"maximum_assessment_score"], as_dict=1)
for field in assessment_plan_details:
if field != "maximum_assessment_score":
setattr(self, field, assessment_plan_details[field])
else:
self.maximum_score = assessment_plan_details[field]
def validate_maximum_score(self):
self.maximum_score = frappe.db.get_value("Assessment Plan", self.assessment_plan, "maximum_assessment_score")
assessment_details = get_assessment_details(self.assessment_plan)
max_scores = {}
for d in assessment_details:

View File

@@ -10,6 +10,7 @@ from erpnext.education.api import enroll_student
class ProgramEnrollmentTool(Document):
def get_students(self):
students = []
if not self.get_students_from:
frappe.throw(_("Mandatory field - Get Students From"))
elif not self.program:

View File

@@ -6,9 +6,15 @@
{% } %}
<h4 class="text-center">{%= __("Assessment Report") %}</h4>
<hr>
<h5 class="text-center">{%= __("Academic Year: ") %} {%= filters.academic_year %} </h5>
{% if (filters.academic_term){ %}
<h5 class="text-center">{%= __("Academic Term: ") %} {%= filters.academic_term %} </h5>
{% } %}
<h5 class="text-center">{%= __("Course Code: ") %} {%= filters.course %}</h5>
<h5 class="text-center">{%= __("Assessment Group: ") %} {%= filters.assessment_group %}</h5>
<h5 class="text-center">{%= __("Assessment Plan: ") %} {%= data_to_be_printed[0]["assessment_plan"] %} </h5>
{% if (filters.student_group){ %}
<h5 class="text-center">{%= __("Student Group: ") %} {%= filters.student_group %} </h5>
{% } %}
<hr>
<table class="table table-bordered">

View File

@@ -4,18 +4,17 @@
frappe.query_reports["Course wise Assessment Report"] = {
"filters": [
{
"fieldname":"assessment_group",
"label": __("Assessment Group"),
"fieldname":"academic_year",
"label": __("Academic Year"),
"fieldtype": "Link",
"options": "Assessment Group",
"reqd": 1,
"get_query": function() {
return{
filters: {
'is_group': 0
}
};
}
"options": "Academic Year",
"reqd": 1
},
{
"fieldname":"academic_term",
"label": __("Academic Term"),
"fieldtype": "Link",
"options": "Academic Term"
},
{
"fieldname":"course",
@@ -29,6 +28,13 @@ frappe.query_reports["Course wise Assessment Report"] = {
"label": __("Student Group"),
"fieldtype": "Link",
"options": "Student Group"
},
{
"fieldname":"assessment_group",
"label": __("Assessment Group"),
"fieldtype": "Link",
"options": "Assessment Group",
"reqd": 1
}
]
};

View File

@@ -5,129 +5,189 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
from collections import defaultdict
from collections import defaultdict, OrderedDict
from erpnext.education.api import get_grade
def execute(filters=None):
data = []
data, chart, grades = [], [], []
args = frappe._dict()
grade_wise_analysis = defaultdict(dict)
args["academic_year"] = filters.get("academic_year")
args["course"] = filters.get("course")
args["assessment_group"] = filters.get("assessment_group")
args["academic_term"] = filters.get("academic_term")
args["student_group"] = filters.get("student_group")
if args["assessment_group"] == "All Assessment Groups":
frappe.throw(_("Please select the assessment group other than 'All Assessment Groups'"))
args["course"] = filters.get("course")
args["student_group"] = filters.get("student_group")
returned_values = get_formatted_result(args, get_assessment_criteria=True)
student_dict = returned_values["student_details"]
result_dict = returned_values["assessment_result"]
assessment_criteria_dict = returned_values["assessment_criteria"]
for student in result_dict:
student_row = {}
student_row["student"] = student
student_row["student_name"] = student_dict[student]
for criteria in assessment_criteria_dict:
scrub_criteria = frappe.scrub(criteria)
if criteria in result_dict[student][args.course][args.assessment_group]:
student_row[scrub_criteria] = result_dict[student][args.course][args.assessment_group][criteria]["grade"]
student_row[scrub_criteria + "_score"] = result_dict[student][args.course][args.assessment_group][criteria]["score"]
# create the list of possible grades
if student_row[scrub_criteria] not in grades:
grades.append(student_row[scrub_criteria])
# create the dict of for gradewise analysis
if student_row[scrub_criteria] not in grade_wise_analysis[criteria]:
grade_wise_analysis[criteria][student_row[scrub_criteria]] = 1
else:
grade_wise_analysis[criteria][student_row[scrub_criteria]] += 1
else:
student_row[frappe.scrub(criteria)] = ""
student_row[frappe.scrub(criteria)+ "_score"] = ""
data.append(student_row)
assessment_criteria_list = [d for d in assessment_criteria_dict]
columns = get_column(assessment_criteria_dict)
chart = get_chart_data(grades, assessment_criteria_list, grade_wise_analysis)
return columns, data, None, chart
# find all assessment plan and related details linked with the given filters
def get_assessment_details():
if args["student_group"]:
cond = "and ap.student_group=%(student_group)s"
def get_formatted_result(args, get_assessment_criteria=False, get_course=False):
cond, cond1, cond2, cond3, cond4 = " ", " ", " ", " ", " "
args_list = [args.academic_year]
if args.course:
cond = " and ar.course=%s"
args_list.append(args.course)
if args.academic_term:
cond1 = " and ar.academic_term=%s"
args_list.append(args.academic_term)
if args.student_group:
cond2 = " and ar.student_group=%s"
args_list.append(args.student_group)
create_total_dict = False
group_type = frappe.get_value("Assessment Group", args.assessment_group, "is_group")
if group_type:
from frappe.desk.treeview import get_children
assessment_groups = [d.get("value") for d in get_children("Assessment Group",
args.assessment_group) if d.get("value") and not d.get("expandable")]
cond3 = " and ar.assessment_group in (%s)"%(', '.join(['%s']*len(assessment_groups)))
else:
assessment_groups = [args.assessment_group]
cond3 = " and ar.assessment_group=%s"
args_list += assessment_groups
if args.students:
cond4 = " and ar.student in (%s)"%(', '.join(['%s']*len(args.students)))
args_list += args.students
assessment_result = frappe.db.sql('''
SELECT
ar.student, ar.student_name, ar.academic_year, ar.academic_term, ar.program, ar.course,
ar.assessment_plan, ar.grading_scale, ar.assessment_group, ar.student_group,
ard.assessment_criteria, ard.maximum_score, ard.grade, ard.score
FROM
`tabAssessment Result` ar, `tabAssessment Result Detail` ard
WHERE
ar.name=ard.parent and ar.docstatus=1 and ar.academic_year=%s {0} {1} {2} {3} {4}
ORDER BY
ard.assessment_criteria'''.format(cond, cond1, cond2, cond3, cond4),
tuple(args_list), as_dict=1)
# create the nested dictionary structure as given below:
# <variable_name>.<student_name>.<course>.<assessment_group>.<assessment_criteria>.<grade/score/max_score>
# "Total Score" -> assessment criteria used for totaling and args.assessment_group -> for totaling all the assesments
student_details = {}
formatted_assessment_result = defaultdict(dict)
assessment_criteria_dict = OrderedDict()
course_dict = OrderedDict()
total_maximum_score = None
if not (len(assessment_groups) == 1 and assessment_groups[0] == args.assessment_group):
create_total_dict = True
# add the score for a given score and recalculate the grades
def add_score_and_recalculate_grade(result, assessment_group, assessment_criteria):
formatted_assessment_result[result.student][result.course][assessment_group]\
[assessment_criteria]["maximum_score"] += result.maximum_score
formatted_assessment_result[result.student][result.course][assessment_group]\
[assessment_criteria]["score"] += result.score
tmp_grade = get_grade(result.grading_scale, ((formatted_assessment_result[result.student][result.course]
[assessment_group][assessment_criteria]["score"])/(formatted_assessment_result[result.student]
[result.course][assessment_group][assessment_criteria]["maximum_score"]))*100)
formatted_assessment_result[result.student][result.course][assessment_group]\
[assessment_criteria]["grade"] = tmp_grade
# create the assessment criteria "Total Score" with the sum of all the scores of the assessment criteria in a given assessment group
def add_total_score(result, assessment_group):
if "Total Score" not in formatted_assessment_result[result.student][result.course][assessment_group]:
formatted_assessment_result[result.student][result.course][assessment_group]["Total Score"] = frappe._dict({
"assessment_criteria": "Total Score", "maximum_score": result.maximum_score, "score": result.score, "grade": result.grade})
else:
cond = ''
add_score_and_recalculate_grade(result, assessment_group, "Total Score")
assessment_plan = frappe.db.sql('''
select
ap.name, ap.student_group, ap.grading_scale, apc.assessment_criteria, apc.maximum_score as max_score
from
`tabAssessment Plan` ap, `tabAssessment Plan Criteria` apc
where
ap.assessment_group=%(assessment_group)s and ap.course=%(course)s and
ap.name=apc.parent and ap.docstatus=1 {0}
order by
apc.assessment_criteria'''.format(cond), (args), as_dict=1)
for result in assessment_result:
if result.student not in student_details:
student_details[result.student] = result.student_name
assessment_plan_list = list(set([d["name"] for d in assessment_plan]))
if not assessment_plan_list:
frappe.throw(_("No assessment plan linked with this assessment group"))
assessment_criteria_details = frappe._dict({"assessment_criteria": result.assessment_criteria,
"maximum_score": result.maximum_score, "score": result.score, "grade": result.grade})
assessment_criteria_list = list(set([(d["assessment_criteria"],d["max_score"]) for d in assessment_plan]))
student_group_list = list(set([d["student_group"] for d in assessment_plan]))
total_maximum_score = flt(sum([flt(d[1]) for d in assessment_criteria_list]))
grading_scale = assessment_plan[0]["grading_scale"]
if not formatted_assessment_result[result.student]:
formatted_assessment_result[result.student] = defaultdict(dict)
if not formatted_assessment_result[result.student][result.course]:
formatted_assessment_result[result.student][result.course] = defaultdict(dict)
return assessment_plan_list, assessment_criteria_list, total_maximum_score, grading_scale, student_group_list
if not create_total_dict:
formatted_assessment_result[result.student][result.course][result.assessment_group]\
[result.assessment_criteria] = assessment_criteria_details
add_total_score(result, result.assessment_group)
# create the total of all the assessment groups criteria-wise
elif create_total_dict:
if not formatted_assessment_result[result.student][result.course][args.assessment_group]:
formatted_assessment_result[result.student][result.course][args.assessment_group] = defaultdict(dict)
formatted_assessment_result[result.student][result.course][args.assessment_group]\
[result.assessment_criteria] = assessment_criteria_details
elif result.assessment_criteria not in formatted_assessment_result[result.student][result.course][args.assessment_group]:
formatted_assessment_result[result.student][result.course][args.assessment_group]\
[result.assessment_criteria] = assessment_criteria_details
elif result.assessment_criteria in formatted_assessment_result[result.student][result.course][args.assessment_group]:
add_score_and_recalculate_grade(result, args.assessment_group, result.assessment_criteria)
add_total_score(result, args.assessment_group)
total_maximum_score = formatted_assessment_result[result.student][result.course][args.assessment_group]\
["Total Score"]["maximum_score"]
if get_assessment_criteria:
assessment_criteria_dict[result.assessment_criteria] = formatted_assessment_result[result.student][result.course]\
[args.assessment_group][result.assessment_criteria]["maximum_score"]
if get_course:
course_dict[result.course] = total_maximum_score
if get_assessment_criteria and total_maximum_score:
assessment_criteria_dict["Total Score"] = total_maximum_score
return {
"student_details": student_details,
"assessment_result": formatted_assessment_result,
"assessment_criteria": assessment_criteria_dict,
"course_dict": course_dict
}
# get all the result and make a dict map student as the key and value as dict of result
def get_result_map():
result_dict = defaultdict(dict)
kounter = defaultdict(dict)
assessment_result = frappe.db.sql('''select ar.student, ard.assessment_criteria, ard.grade, ard.score
from `tabAssessment Result` ar, `tabAssessment Result Detail` ard
where ar.assessment_plan in (%s) and ar.name=ard.parent and ar.docstatus=1
order by ard.assessment_criteria''' %', '.join(['%s']*len(assessment_plan_list)),
tuple(assessment_plan_list), as_dict=1)
for result in assessment_result:
if "total_score" in result_dict[result.student]:
total_score = result_dict[result.student]["total_score"] + result.score
else:
total_score = result.score
total = get_grade(grading_scale, (total_score/total_maximum_score)*100)
if result.grade in kounter[result.assessment_criteria]:
kounter[result.assessment_criteria][result.grade] += 1
else:
kounter[result.assessment_criteria].update({result.grade: 1})
if "Total" not in kounter:
kounter["Total"] = {}
if "total" in result_dict[result.student]:
prev_grade = result_dict[result.student]["total"]
prev_grade_count = kounter["Total"].get(prev_grade) - 1
kounter["Total"].update({prev_grade: prev_grade_count})
latest_grade_count = kounter["Total"].get(total)+1 if kounter["Total"].get(total) else 1
kounter["Total"].update({total: latest_grade_count})
result_dict[result.student].update({
frappe.scrub(result.assessment_criteria): result.grade,
frappe.scrub(result.assessment_criteria)+"_score": result.score,
"total_score": total_score,
"total": total
})
return result_dict, kounter
# make data from the result dict
def get_data():
student_list = frappe.db.sql('''select sgs.student, sgs.student_name
from `tabStudent Group` sg, `tabStudent Group Student` sgs
where sg.name = sgs.parent and sg.name in (%s)
order by sgs.group_roll_number asc''' %', '.join(['%s']*len(student_group_list)),
tuple(student_group_list), as_dict=1)
for student in student_list:
student.update(result_dict[student.student])
return student_list
# get chart data
def get_chart():
grading_scale = frappe.db.get_value("Assessment Plan", list(assessment_plan_list)[0], "grading_scale")
grades = frappe.db.sql_list('''select grade_code from `tabGrading Scale Interval` where parent=%s''',
(grading_scale))
criteria_list = [d[0] for d in assessment_criteria_list] + ["Total"]
return get_chart_data(grades, criteria_list, kounter)
assessment_plan_list, assessment_criteria_list, total_maximum_score, grading_scale,\
student_group_list = get_assessment_details()
result_dict, kounter = get_result_map()
data = get_data()
columns = get_column(assessment_criteria_list, total_maximum_score)
chart = get_chart()
data_to_be_printed = [{
"assessment_plan": ", ".join(assessment_plan_list)
}]
return columns, data, None, chart, data_to_be_printed
def get_column(assessment_criteria, total_maximum_score):
def get_column(assessment_criteria):
columns = [{
"fieldname": "student",
"label": _("Student ID"),
@@ -143,40 +203,28 @@ def get_column(assessment_criteria, total_maximum_score):
}]
for d in assessment_criteria:
columns.append({
"fieldname": frappe.scrub(d[0]),
"label": d[0],
"fieldname": frappe.scrub(d),
"label": d,
"fieldtype": "Data",
"width": 110
})
columns.append({
"fieldname": frappe.scrub(d[0]) +"_score",
"label": "Score(" + str(int(d[1])) + ")",
"fieldname": frappe.scrub(d) +"_score",
"label": "Score(" + str(int(assessment_criteria[d])) + ")",
"fieldtype": "Float",
"width": 100
})
columns += [{
"fieldname": "total",
"label": "Total",
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "total_score",
"label": "Total Score("+ str(int(total_maximum_score)) + ")",
"fieldtype": "Float",
"width": 110
}]
return columns
def get_chart_data(grades, assessment_criteria_list, kounter):
def get_chart_data(grades, criteria_list, kounter):
grades = sorted(grades)
datasets = []
for grade in grades:
tmp = frappe._dict({"values":[], "title": grade})
for criteria in assessment_criteria_list:
for criteria in criteria_list:
if grade in kounter[criteria]:
tmp["values"].append(kounter[criteria][grade])
else:
@@ -185,7 +233,7 @@ def get_chart_data(grades, assessment_criteria_list, kounter):
return {
"data": {
"labels": assessment_criteria_list,
"labels": criteria_list,
"datasets": datasets
},
"type": 'bar',

View File

@@ -0,0 +1,38 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Final Assessment Grades"] = {
"filters": [
{
"fieldname":"academic_year",
"label": __("Academic Year"),
"fieldtype": "Link",
"options": "Academic Year",
"reqd": 1
},
{
"fieldname":"student_group",
"label": __("Student Group"),
"fieldtype": "Link",
"options": "Student Group",
"reqd": 1,
"get_query": function() {
return{
filters: {
"group_based_on": "Batch",
"academic_year": frappe.query_report_filters_by_name.academic_year.value
}
};
}
},
{
"fieldname":"assessment_group",
"label": __("Assessment Group"),
"fieldtype": "Link",
"options": "Assessment Group",
"reqd": 1
}
]
}

View File

@@ -0,0 +1,20 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2018-01-22 17:04:43.412054",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Shishuvan Secondary School",
"modified": "2018-01-22 17:04:43.412054",
"modified_by": "Administrator",
"module": "Education",
"name": "Final Assessment Grades",
"owner": "Administrator",
"ref_doctype": "Assessment Result",
"report_name": "Final Assessment Grades",
"report_type": "Script Report",
"roles": []
}

View File

@@ -0,0 +1,85 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from collections import defaultdict
from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_formatted_result
from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_chart_data
def execute(filters=None):
columns, data, grades = [], [], []
args = frappe._dict()
course_wise_analysis = defaultdict(dict)
args["academic_year"] = filters.get("academic_year")
assessment_group = args["assessment_group"] = filters.get("assessment_group")
student_group = filters.get("student_group")
args.students = frappe.db.sql_list("select student from `tabStudent Group Student` where parent=%s", (student_group))
values = get_formatted_result(args, get_course=True)
student_details = values.get("student_details")
assessment_result = values.get("assessment_result")
course_dict = values.get("course_dict")
for student in args.students:
student_row = {}
student_row["student"] = student
student_row["student_name"] = student_details[student]
for course in course_dict:
scrub_course = frappe.scrub(course)
if assessment_group in assessment_result[student][course]:
student_row["grade_" + scrub_course] = assessment_result[student][course][assessment_group]["Total Score"]["grade"]
student_row["score_" + scrub_course] = assessment_result[student][course][assessment_group]["Total Score"]["score"]
# create the list of possible grades
if student_row["grade_" + scrub_course] not in grades:
grades.append(student_row["grade_" + scrub_course])
# create the dict of for gradewise analysis
if student_row["grade_" + scrub_course] not in course_wise_analysis[course]:
course_wise_analysis[course][student_row["grade_" + scrub_course]] = 1
else:
course_wise_analysis[course][student_row["grade_" + scrub_course]] += 1
data.append(student_row)
course_list = [d for d in course_dict]
columns = get_column(course_dict)
chart = get_chart_data(grades, course_list, course_wise_analysis)
return columns, data, None, chart
def get_column(course_dict):
columns = [{
"fieldname": "student",
"label": _("Student ID"),
"fieldtype": "Link",
"options": "Student",
"width": 90
},
{
"fieldname": "student_name",
"label": _("Student Name"),
"fieldtype": "Data",
"width": 160
}]
for course in course_dict:
columns.append({
"fieldname": "grade_" + frappe.scrub(course),
"label": course,
"fieldtype": "Data",
"width": 110
})
columns.append({
"fieldname": "score_" + frappe.scrub(course),
"label": "Score(" + str(course_dict[course]) + ")",
"fieldtype": "Float",
"width": 100
})
return columns

View File

@@ -462,7 +462,8 @@ class ProductionOrder(Document):
if reset_only_qty:
for d in self.get("required_items"):
d.required_qty = item_dict.get(d.item_code).get("qty")
if item_dict.get(d.item_code):
d.required_qty = item_dict.get(d.item_code).get("qty")
else:
for item in sorted(item_dict.values(), key=lambda d: d['idx']):
self.append('required_items', {

View File

@@ -310,6 +310,7 @@ class ProductionPlanningTool(Document):
}
"""
item_list = []
precision = frappe.get_precision("BOM Item", "stock_qty")
for bom, so_wise_qty in bom_dict.items():
bom_wise_item_details = {}
@@ -334,8 +335,9 @@ class ProductionPlanningTool(Document):
for item, item_details in bom_wise_item_details.items():
for so_qty in so_wise_qty:
item_list.append([item, flt(item_details.qty) * so_qty[1], item_details.description,
item_details.stock_uom, item_details.min_order_qty, so_qty[0]])
item_list.append([item, flt(flt(item_details.qty) * so_qty[1], precision),
item_details.description, item_details.stock_uom, item_details.min_order_qty,
so_qty[0]])
self.make_items_dict(item_list)

View File

@@ -35,4 +35,16 @@ def get_list_context(context):
context.title = 'All Chapters'
context.no_breadcrumbs = True
context.order_by = 'creation desc'
context.introduction = '<p>All Chapters</p>'
context.introduction = '<p>All Chapters</p>'
@frappe.whitelist()
def leave(title, user_id, leave_reason):
chapter = frappe.get_doc("Chapter", title)
for member in chapter.members:
if member.user == user_id:
member.enabled = 0
member.leave_reason = leave_reason
chapter.save(ignore_permissions=1)
frappe.db.commit()
return "Thank you for Feedback"

View File

@@ -5,34 +5,39 @@
<h3>Details</h3>
<p>{{ introduction }}</p>
{% if meetup_embed_html %}
{{ meetup_embed_html }}
{{ meetup_embed_html }}
{% endif %}
<h3>List of Members</h3>
{% if members %}
{% if members %}
<table class="table table-bordered small" style="max-width: 500px;">
<tr>
<th width="15%" ></th>
<th>Member Details</th>
</tr>
{% set index = [1] %}
{% for user in members %}
<tr>
<td>{{ loop.index }}</td>
<td>
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6">{{ frappe.db.get_value('User', user.user, 'full_name') }}</div>
<div class="col-lg-6 col-md-6 col-sm-6 text-right">
{% if user.website_url %}
<a href="{{ user.website_url }}">{{ user.website_url or '' }}</a>
{% if user.enabled == 1 %}
<tr>
<td>{{ index|length }}</td>
<td>
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6">{{ frappe.db.get_value('User', user.user, 'full_name') }}</div>
<div class="col-lg-6 col-md-6 col-sm-6 text-right">
{% if user.website_url %}
<a href="{{ user.website_url }}">{{ user.website_url or '' }}</a>
{% endif %}
</div>
<div class="col-lg-12">
{% if user.introduction %}
{{ user.introduction }}
{% endif %}
</div>
</div>
<div class="col-lg-12">
{% if user.introduction %}
{{ user.introduction }}
{% endif %}
</div>
</div>
</td>
</tr>
</td>
</tr>
{% set __ = index.append(1) %}
{% endif %}
{% endfor %}
</table>
{% else %}

View File

@@ -1,21 +1,30 @@
{% if doc.published %}
<div style="margin-bottom: 30px; max-width: 600px" class="with-border clickable">
<a href="/{{ doc.route }}">
<a href={{ route }}>
<h3>{{ doc.name }}</h3>
<p>
<span class="label">{{ frappe.db.get_value('User', chapter_head, 'full_name') }}</span>
<span class="label"> Chapter Head : {{ frappe.db.get_value('User', chapter_head, 'full_name') }} </span>
<span class="label">
{% if members %}
Members: {{ members|length }}
{% set index = [] %}
{% for user in members %}
{% if user.enabled == 1 %}
{% set __ = index.append(1) %}
{% endif %}
{% endfor %}
Members: {{ index|length }}
{% else %}
Members: 0
{% endif %}
</span>
</span>
<!-- Assignment of value to global variable not working in jinja -->
</p>
<p>{{ html2text(doc.introduction[:200]) }}{% if introduction|len > 200 %}...{% endif %}</p>
</a>
</div>
{% endif %}
<!-- this is a sample default list template -->
<style type="text/css">
.label {

View File

@@ -132,6 +132,36 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "leave_reason",
"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": "Leave Reason",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
@@ -144,7 +174,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-12-06 11:33:34.300252",
"modified": "2018-01-12 12:16:10.591039",
"modified_by": "Administrator",
"module": "Non Profit",
"name": "Chapter Member",

View File

@@ -2,7 +2,7 @@
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"allow_rename": 1,
"autoname": "field:email",
"beta": 0,
"creation": "2017-09-19 16:20:27.510196",
@@ -295,7 +295,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-05 07:02:06.690416",
"modified": "2018-01-22 15:53:35.059946",
"modified_by": "Administrator",
"module": "Non Profit",
"name": "Donor",
@@ -330,6 +330,7 @@
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "donor_name",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -2,7 +2,7 @@
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"allow_rename": 1,
"autoname": "field:email",
"beta": 0,
"creation": "2017-09-11 09:24:52.898356",
@@ -140,7 +140,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "email",
"fieldtype": "Data",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -151,6 +151,7 @@
"label": "Email",
"length": 0,
"no_copy": 0,
"options": "User",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -325,7 +326,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-05 07:03:21.606732",
"modified": "2018-01-22 15:58:46.507509",
"modified_by": "Administrator",
"module": "Non Profit",
"name": "Member",
@@ -380,6 +381,7 @@
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "member_name",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -2,7 +2,7 @@
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"allow_rename": 1,
"autoname": "field:email",
"beta": 0,
"creation": "2017-09-19 16:16:45.676019",
@@ -506,7 +506,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-06 12:03:08.624579",
"modified": "2018-01-22 15:53:46.480182",
"modified_by": "Administrator",
"module": "Non Profit",
"name": "Volunteer",
@@ -540,6 +540,7 @@
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "volunteer_name",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -183,7 +183,6 @@ erpnext.patches.v5_0.index_on_account_and_gl_entry
execute:frappe.db.sql("""delete from `tabProject Task`""")
erpnext.patches.v5_0.update_item_desc_in_invoice
erpnext.patches.v5_1.fix_against_account
erpnext.patches.v5_1.fix_credit_days_based_on
execute:frappe.rename_doc("DocType", "Salary Manager", "Process Payroll", force=True)
erpnext.patches.v5_1.rename_roles
erpnext.patches.v5_1.default_bom
@@ -484,4 +483,7 @@ erpnext.patches.v10_0.copy_projects_renamed_fields
erpnext.patches.v10_0.enabled_regional_print_format_based_on_country
erpnext.patches.v10_0.update_asset_calculate_depreciation
erpnext.patches.v10_0.add_guardian_role_for_parent_portal
erpnext.patches.v10_0.set_numeric_ranges_in_template_if_blank
erpnext.patches.v10_0.set_numeric_ranges_in_template_if_blank
erpnext.patches.v10_0.update_assessment_plan
erpnext.patches.v10_0.update_assessment_result
erpnext.patches.v10_0.set_default_payment_terms_based_on_company

View File

@@ -0,0 +1,37 @@
from __future__ import unicode_literals
import frappe
from erpnext.patches.v8_10.change_default_customer_credit_days import make_payment_term, make_template
def execute():
for dt in ("Company", "Customer Group"):
frappe.reload_doc("setup", "doctype", frappe.scrub(dt))
credit_records = frappe.db.sql("""
SELECT DISTINCT `credit_days`, `credit_days_based_on`, `name`
from `tab{0}`
where
((credit_days_based_on='Fixed Days' or credit_days_based_on is null) and credit_days is not null)
or credit_days_based_on='Last Day of the Next Month'
""".format(dt), as_dict=1)
for d in credit_records:
template = create_payment_terms_template(d)
frappe.db.sql("""
update `tab{0}`
set `payment_terms` = %s
where name = %s
""".format(dt), (template, d.name))
def create_payment_terms_template(data):
if data.credit_days_based_on == "Fixed Days":
pyt_template_name = 'Default Payment Term - N{0}'.format(data.credit_days)
else:
pyt_template_name = 'Default Payment Term - EO2M'
if not frappe.db.exists("Payment Terms Template", pyt_template_name):
payment_term = make_payment_term(data.credit_days, data.credit_days_based_on)
template = make_template(payment_term)
else:
template = frappe.get_doc("Payment Terms Template", pyt_template_name)
return template

View File

@@ -0,0 +1,17 @@
# Copyright (c) 2017, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doc('education', 'doctype', 'assessment_plan')
frappe.db.sql("""
UPDATE `tabAssessment Plan` as ap
INNER JOIN `tabStudent Group` as sg ON sg.name = ap.student_group
SET ap.academic_term = sg.academic_term,
ap.academic_year = sg.academic_year,
ap.program = sg.program
WHERE ap.docstatus = 1
""")

View File

@@ -0,0 +1,20 @@
# Copyright (c) 2017, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doc('education', 'doctype', 'assessment_result')
frappe.db.sql("""
UPDATE `tabAssessment Result` AS ar
INNER JOIN `tabAssessment Plan` AS ap ON ap.name = ar.assessment_plan
SET ar.academic_term = ap.academic_term,
ar.academic_year = ap.academic_year,
ar.program = ap.program,
ar.course = ap.course,
ar.assessment_group = ap.assessment_group,
ar.student_group = ap.student_group
WHERE ap.docstatus = 1
""")

View File

@@ -1,9 +0,0 @@
from __future__ import unicode_literals
import frappe
def execute():
for dt in ("Customer", "Customer Group", "Company"):
frappe.reload_doctype(dt, force=True)
frappe.db.sql("""update `tab{0}` set credit_days_based_on='Fixed Days'
where ifnull(credit_days, 0) > 0""".format(dt))

View File

@@ -16,7 +16,7 @@ def execute():
else:
company = frappe.db.get_single_value('Global Defaults', 'default_company')
time_sheet = make_timesheet(data.production_order)
time_sheet = make_timesheet(data.production_order, company)
args = get_timelog_data(data)
add_timesheet_detail(time_sheet, args)
if data.docstatus == 2:

View File

@@ -17,7 +17,8 @@ def execute():
SELECT DISTINCT `credit_days`, `credit_days_based_on`, `name`
from `tab{0}`
where
(credit_days_based_on='Fixed Days' and credit_days is not null)
((credit_days_based_on='Fixed Days' or credit_days_based_on is null)
and credit_days is not null)
or credit_days_based_on='Last Day of the Next Month'
""".format(doctype))

View File

@@ -169,5 +169,8 @@ input[type=number]::-webkit-outer-spin-button {
height: 60px;
}
.grand-total .grand-total-value {
font-size: 24px;
font-size: 18px;
}
.rounded-total-value {
font-size: 18px;
}

View File

@@ -434,7 +434,8 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
} else if (frappe.sys_defaults.disable_rounded_total) {
disable_rounded_total = frappe.sys_defaults.disable_rounded_total;
}
if(disable_rounded_total) {
if (cint(disable_rounded_total)) {
this.frm.doc.rounded_total = 0;
this.frm.doc.base_rounded_total = 0;
return;

View File

@@ -228,7 +228,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
erpnext.hide_company();
this.set_dynamic_labels();
this.setup_sms();
},
apply_default_taxes: function() {
@@ -245,10 +244,11 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
method: "erpnext.controllers.accounts_controller.get_default_taxes_and_charges",
args: {
"master_doctype": taxes_and_charges_field.options,
"tax_template": me.frm.doc.taxes_and_charges,
"company": me.frm.doc.company
},
callback: function(r) {
if(!r.exc) {
if(!r.exc && r.message) {
frappe.run_serially([
() => {
// directly set in doc, so as not to call triggers
@@ -523,7 +523,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
},
callback: function(r, rt) {
if(r.message) {
me.frm.set_value("due_date", r.message);
me.frm.doc.due_date = r.message;
refresh_field("due_date");
frappe.ui.form.trigger(me.frm.doc.doctype, "currency");
me.recalculate_terms();
}
@@ -535,6 +536,31 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
},
due_date: function() {
// due_date is to be changed, payment terms template and/or payment schedule must
// be removed as due_date is automatically changed based on payment terms
if (this.frm.doc.due_date && !this.frm.updating_party_details) {
if (this.frm.doc.payment_terms_template ||
(this.frm.doc.payment_schedule && this.frm.doc.payment_schedule.length)) {
var message1 = "";
var message2 = "";
var final_message = "Please clear the ";
if (this.frm.doc.payment_terms_template) {
message1 = "selected Payment Terms Template";
final_message = final_message + message1;
}
if ((this.frm.doc.payment_schedule || []).length) {
message2 = "Payment Schedule Table";
if (message1.length !== 0) message2 = " and " + message2;
final_message = final_message + message2;
}
frappe.msgprint(final_message);
}
}
},
recalculate_terms: function() {
const doc = this.frm.doc;
@@ -542,7 +568,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.payment_terms_template();
} else if (doc.payment_schedule) {
const me = this;
doc.payment_schedule.forEach(
function(term) {
if (term.payment_term) {
@@ -623,6 +648,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
}).fail(() => this.frm.set_value('shipping_rule', ''));
}
else {
me.calculate_taxes_and_totals();
}
},
set_actual_charges_based_on_currency: function() {
@@ -1236,11 +1264,14 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
payment_terms_template: function() {
var me = this;
if(this.frm.doc.payment_terms_template) {
var posting_date = this.frm.doc.bill_date ||
this.frm.doc.posting_date || this.frm.doc.transaction_date;
frappe.call({
method: "erpnext.controllers.accounts_controller.get_payment_terms",
args: {
terms_template: this.frm.doc.payment_terms_template,
posting_date: this.frm.doc.posting_date || this.frm.doc.transaction_date,
posting_date: posting_date,
grand_total: this.frm.doc.rounded_total || this.frm.doc.grand_total
},
callback: function(r) {

View File

@@ -216,6 +216,10 @@ input[type=number]::-webkit-outer-spin-button {
}
.grand-total-value {
font-size: 24px;
font-size: 18px;
}
}
.rounded-total-value {
font-size: 18px;
}

View File

@@ -43,7 +43,7 @@ frappe.ui.form.on("Customer", {
frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Customer'}
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
frm.toggle_display(['address_html','contact_html','primary_contact_detail'], !frm.doc.__islocal);
if(!frm.doc.__islocal) {
frappe.contacts.render_address_and_contact(frm);

View File

@@ -66,7 +66,7 @@ class Customer(TransactionBase):
self.create_lead_address_contact()
def create_primary_contact(self):
if not self.customer_primary_contact:
if not self.customer_primary_contact and not self.lead_name:
if self.mobile_no or self.email_id:
contact = make_contact(self)
self.db_set('customer_primary_contact', contact.name)
@@ -146,7 +146,8 @@ class Customer(TransactionBase):
frappe.throw(_("A Customer Group exists with same name please change the Customer name or rename the Customer Group"), frappe.NameError)
def validate_credit_limit_on_change(self):
if self.get("__islocal") or self.credit_limit == frappe.db.get_value("Customer", self.name, "credit_limit"):
if self.get("__islocal") or not self.credit_limit \
or self.credit_limit == frappe.db.get_value("Customer", self.name, "credit_limit"):
return
for company in frappe.get_all("Company"):

View File

@@ -82,8 +82,8 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
get_query_filters: {
status: ["not in", ["Lost", "Closed"]],
company: me.frm.doc.company,
// cannot set enquiry_type as setter, as the fieldname is order_type
enquiry_type: me.frm.doc.order_type,
// cannot set opportunity_type as setter, as the fieldname is order_type
opportunity_type: me.frm.doc.order_type,
}
})
}, __("Get items from"), "btn-default");

View File

@@ -320,7 +320,7 @@ erpnext.pos.PointOfSale = class PointOfSale {
return new Promise((resolve) => {
const on_submit = ({ pos_profile, set_as_default }) => {
if (pos_profile) {
this.frm.doc.pos_profile = pos_profile;
this.pos_profile = pos_profile;
}
if (set_as_default) {
@@ -346,13 +346,19 @@ erpnext.pos.PointOfSale = class PointOfSale {
}
on_change_pos_profile() {
this.set_pos_profile_data()
.then(() => {
this.reset_cart();
if (this.items) {
this.items.reset_items();
}
});
return frappe.run_serially([
() => this.make_sales_invoice_frm(),
() => {
this.frm.doc.pos_profile = this.pos_profile;
this.set_pos_profile_data()
.then(() => {
this.reset_cart();
if (this.items) {
this.items.reset_items();
}
});
}
]);
}
get_promopt_fields() {
@@ -579,16 +585,28 @@ class POSCart {
this.wrapper.find('.grand-total-value').text(
format_currency(this.frm.doc.grand_total, this.frm.currency));
this.wrapper.find('.rounded-total-value').text(
format_currency(this.frm.doc.rounded_total, this.frm.currency));
const customer = this.frm.doc.customer;
this.customer_field.set_value(customer);
}
get_grand_total() {
let total = this.get_total_template('Grand Total', 'grand-total-value');
if (!cint(frappe.sys_defaults.disable_rounded_total)) {
total += this.get_total_template('Rounded Total', 'rounded-total-value');
}
return total;
}
get_total_template(label, class_name) {
return `
<div class="list-item">
<div class="list-item__content text-muted">${__('Grand Total')}</div>
<div class="list-item__content list-item__content--flex-2 grand-total-value">0.00</div>
<div class="list-item__content text-muted">${__(label)}</div>
<div class="list-item__content list-item__content--flex-2 ${class_name}">0.00</div>
</div>
`;
}
@@ -665,6 +683,10 @@ class POSCart {
this.$grand_total.find('.grand-total-value').text(
format_currency(this.frm.doc.grand_total, this.frm.currency)
);
this.$grand_total.find('.rounded-total-value').text(
format_currency(this.frm.doc.rounded_total, this.frm.currency)
);
}
make_customer_field() {
@@ -1375,7 +1397,8 @@ class Payment {
set_title() {
let title = __('Total Amount {0}',
[format_currency(this.frm.doc.grand_total, this.frm.doc.currency)]);
[format_currency(this.frm.doc.rounded_total || this.frm.doc.grand_total,
this.frm.doc.currency)]);
this.dialog.set_title(title);
}

View File

@@ -41,8 +41,9 @@ def get_columns():
def get_product_bundle_items():
sbom_item_map = {}
for sbom in frappe.db.sql("""select parent, item_code, qty from `tabProduct Bundle Item`
where docstatus < 2""", as_dict=1):
for sbom in frappe.db.sql("""select pb.new_item_code as parent, pbi.item_code, pbi.qty
from `tabProduct Bundle Item` as pbi, `tabProduct Bundle` as pb
where pb.docstatus < 2 and pb.name = pbi.parent""", as_dict=1):
sbom_item_map.setdefault(sbom.parent, {}).setdefault(sbom.item_code, sbom.qty)
return sbom_item_map

View File

@@ -340,7 +340,8 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
this._super(doc, cdt, cdn, dont_fetch_price_list_rate);
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn) &&
in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
this.set_batch_number(cdt, cdn);
}
},

View File

@@ -32,6 +32,10 @@ frappe.ui.form.on("Company", {
frm.toggle_enable("default_currency", (frm.doc.__onload &&
!frm.doc.__onload.transactions_exist));
frm.add_custom_button(__('Make Tax Template'), function() {
frm.trigger("make_default_tax_template");
});
frm.add_custom_button(__('Cost Centers'), function() {
frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name})
}, __("View"));
@@ -47,13 +51,6 @@ frappe.ui.form.on("Company", {
frm.add_custom_button(__('Purchase Tax Template'), function() {
frappe.set_route('List', 'Purchase Taxes and Charges Template', {'company': frm.doc.name});
}, __("View"));
frm.add_custom_button(__('Default Tax Template'), function() {
frm.trigger("make_default_tax_template");
}, __("Make"));
frm.page.set_inner_btn_group_as_primary(__("View"));
frm.page.set_inner_btn_group_as_primary(__("Make"));
}
erpnext.company.set_chart_of_accounts_options(frm.doc);

View File

@@ -1180,6 +1180,35 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_26",
"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,
@@ -1219,8 +1248,9 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_26",
"fieldtype": "Column Break",
"depends_on": "",
"fieldname": "payment_terms",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -1228,8 +1258,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Payment Terms Template",
"length": 0,
"no_copy": 0,
"options": "Payment Terms Template",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -1242,69 +1274,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "credit_days_based_on",
"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": "Credit Days Based On",
"length": 0,
"no_copy": 0,
"options": "\nFixed Days\nLast Day of the Next Month",
"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.__islocal && doc.credit_days_based_on=='Fixed Days')",
"fieldname": "credit_days",
"fieldtype": "Int",
"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": "Credit Days",
"length": 0,
"no_copy": 0,
"oldfieldname": "credit_days",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -2052,7 +2021,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-12-07 18:40:24.646920",
"modified": "2018-01-29 12:40:24.646920",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",

View File

@@ -34,6 +34,7 @@ class Company(Document):
self.validate_currency()
self.validate_coa_input()
self.validate_perpetual_inventory()
self.check_country_change()
def validate_abbr(self):
if not self.abbr:
@@ -80,9 +81,12 @@ class Company(Document):
if not frappe.db.sql("""select name from tabAccount
where company=%s and docstatus<2 limit 1""", self.name):
if not frappe.local.flags.ignore_chart_of_accounts:
frappe.flags.country_change = True
self.create_default_accounts()
self.create_default_warehouses()
install_country_fixtures(self.name)
if frappe.flags.country_change:
install_country_fixtures(self.name)
if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": self.name}):
self.create_default_cost_center()
@@ -147,6 +151,13 @@ class Company(Document):
frappe.msgprint(_("Set default inventory account for perpetual inventory"),
alert=True, indicator='orange')
def check_country_change(self):
frappe.flags.country_change = False
if not self.get('__islocal') and \
self.country != frappe.db.get_value('Company', self.name, 'country'):
frappe.flags.country_change = True
def set_default_accounts(self):
self._set_default_account("default_cash_account", "Cash")
self._set_default_account("default_bank_account", "Bank")
@@ -162,8 +173,14 @@ class Company(Document):
self._set_default_account("default_expense_account", "Cost of Goods Sold")
if not self.default_income_account:
self.db_set("default_income_account", frappe.db.get_value("Account",
{"account_name": _("Sales"), "company": self.name}))
income_account = frappe.db.get_value("Account",
{"account_name": _("Sales"), "company": self.name, "is_group": 0})
if not income_account:
income_account = frappe.db.get_value("Account",
{"account_name": _("Sales Account"), "company": self.name})
self.db_set("default_income_account", income_account)
if not self.default_payable_account:
self.db_set("default_payable_account", self.default_payable_account)
@@ -281,6 +298,15 @@ class Company(Document):
# delete mode of payment account
frappe.db.sql("delete from `tabMode of Payment Account` where company=%s", self.name)
# delete BOMs
boms = frappe.db.sql_list("select name from tabBOM where company=%s", self.name)
if boms:
frappe.db.sql("delete from tabBOM where company=%s", self.name)
for dt in ("BOM Operation", "BOM Item", "BOM Scrap Item", "BOM Explosion Item"):
frappe.db.sql("delete from `tab%s` where parent in (%s)"""
% (dt, ', '.join(['%s']*len(boms))), tuple(boms))
frappe.db.sql("delete from tabEmployee where company=%s", self.name)
@frappe.whitelist()
def enqueue_replace_abbr(company, old, new):
@@ -349,7 +375,6 @@ def update_company_current_month_sales(company):
monthly_total = results[0]['total'] if len(results) > 0 else 0
frappe.db.set_value("Company", company, "total_monthly_sales", monthly_total)
frappe.db.commit()
def update_company_monthly_sales(company):
'''Cache past year monthly sales of every company based on sales invoices'''
@@ -360,7 +385,6 @@ def update_company_monthly_sales(company):
"posting_date", filter_str, "sum")
frappe.db.set_value("Company", company, "sales_monthly_history", json.dumps(month_to_value_dict))
frappe.db.commit()
def cache_companies_monthly_sales_history():
companies = [d['name'] for d in frappe.get_list("Company")]

View File

@@ -162,12 +162,14 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "credit_days_based_on",
"fieldtype": "Select",
"depends_on": "",
"fieldname": "payment_terms",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -175,10 +177,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Credit Days Based On",
"label": "Default Payment Terms Template",
"length": 0,
"no_copy": 0,
"options": "\nFixed Days\nLast Day of the Next Month",
"options": "Payment Terms Template",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -191,35 +193,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.credit_days_based_on=='Fixed Days'",
"fieldname": "credit_days",
"fieldtype": "Int",
"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": "Credit Days",
"length": 0,
"no_copy": 0,
"permlevel": 1,
"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_on_submit": 0,
"bold": 0,
@@ -411,7 +384,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-20 13:25:31.549874",
"modified": "2018-01-29 13:25:31.549874",
"modified_by": "Administrator",
"module": "Setup",
"name": "Customer Group",

View File

@@ -204,7 +204,6 @@ def _get_cart_quotation(party=None):
"status": "Draft",
"docstatus": 0,
"__islocal": 1,
"payment_terms_template": "_Test Payment Term Template",
(party.doctype.lower()): party.name
})

View File

@@ -9,7 +9,7 @@ from erpnext.shopping_cart.cart import _get_cart_quotation, update_cart, get_par
from erpnext.tests.utils import create_test_contact_and_address
test_dependencies = ['Payment Terms Template']
# test_dependencies = ['Payment Terms Template']
class TestShoppingCart(unittest.TestCase):
"""

View File

@@ -75,7 +75,7 @@ erpnext.stock.ItemDashboard = Class.extend({
this.content.find('.more').addClass('hidden');
}
// If not any stock in any warehouses provide a message to end user
// If not any stock in any warehouses provide a message to end user
if (context.data.length > 0) {
$(frappe.render_template('item_dashboard_list', context)).appendTo(this.result);
} else {
@@ -86,6 +86,7 @@ erpnext.stock.ItemDashboard = Class.extend({
get_item_dashboard_data: function(data, max_count, show_item) {
if(!max_count) max_count = 0;
if(!data) data = [];
data.forEach(function(d) {
d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production;
d.pending_qty = 0;
@@ -97,9 +98,16 @@ erpnext.stock.ItemDashboard = Class.extend({
max_count = Math.max(d.actual_or_pending, d.actual_qty,
d.total_reserved, max_count);
});
var can_write = 0;
if(frappe.boot.user.can_write.indexOf("Stock Entry")>=0){
can_write = 1;
}
return {
data: data,
max_count: max_count,
can_write:can_write,
show_item: show_item || false
}
}
@@ -187,4 +195,4 @@ erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callb
frappe.set_route('Form', doc.doctype, doc.name);
})
});
}
}

View File

@@ -39,6 +39,7 @@
</span>
</span>
</div>
{% if can_write %}
<div class="col-sm-2 text-right" style="margin-top: 8px;">
{% if d.actual_qty %}
<button class="btn btn-default btn-xs btn-move"
@@ -52,6 +53,7 @@
data-item="{{ d.item_code }}"
data-rate="{{ d.valuation_rate }}">{{ __("Add") }}</a>
</div>
{% endif %}
</div>
</div>
{% endfor %}

View File

@@ -1,7 +1,7 @@
frappe.listview_settings['Batch'] = {
add_fields: ["item", "expiry_date"],
get_indicator: function(doc) {
if(doc.expiry_date && frappe.datetime.get_diff(doc.expiry_date) <= 0) {
if(doc.expiry_date && frappe.datetime.get_diff(doc.expiry_date, frappe.datetime.nowdate()) <= 0) {
return [__("Expired"), "red", "expiry_date,>=,Today"]
} else if(doc.expiry_date) {
return [__("Not Expired"), "green", "expiry_date,<,Today"]

View File

@@ -106,6 +106,13 @@ frappe.ui.form.on("Item", {
frappe.set_route("Form", "Item Variant Settings");
}, __("View"));
}
const stock_exists = (frm.doc.__onload
&& frm.doc.__onload.stock_exists) ? 1 : 0;
['has_serial_no', 'has_batch_no'].forEach((fieldname) => {
frm.set_df_property(fieldname, 'read_only', stock_exists);
});
},
validate: function(frm){

View File

@@ -1180,7 +1180,7 @@
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 1,
"set_only_once": 0,
"unique": 0
},
{
@@ -1370,7 +1370,7 @@
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 1,
"set_only_once": 0,
"unique": 0
},
{
@@ -3453,7 +3453,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
"modified": "2017-12-27 15:47:17.039337",
"modified": "2018-01-23 12:21:16.641517",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@@ -170,6 +170,8 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten
d.description = item.description;
d.warehouse = values.warehouse;
d.uom = item.stock_uom;
d.stock_uom = item.stock_uom;
d.conversion_factor = 1;
d.qty = item.qty;
});
}
@@ -282,4 +284,4 @@ function set_schedule_date(frm) {
if(frm.doc.schedule_date){
erpnext.utils.copy_value_in_all_row(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date");
}
}
}

View File

@@ -48,7 +48,7 @@ cur_frm.cscript.validate = function(doc, cdt, cdn) {
cur_frm.cscript.validate_case_nos = function(doc) {
doc = locals[doc.doctype][doc.name];
if(cint(doc.from_case_no)==0) {
frappe.msgprint(__("Case No. cannot be 0"))
frappe.msgprint(__("The 'From Package No.' field must neither be empty nor it's value less than 1."));
frappe.validated = false;
} else if(!cint(doc.to_case_no)) {
doc.to_case_no = doc.from_case_no;
@@ -124,3 +124,5 @@ cur_frm.pformat.net_weight_pkg= function(doc){
cur_frm.pformat.gross_weight_pkg= function(doc){
return '<table style="width:100%">' + make_row('Gross Weight', doc.gross_weight_pkg) + '</table>'
}
// TODO: validate gross weight field

View File

@@ -72,6 +72,7 @@ frappe.ui.form.on('Stock Entry', {
mr_item.item_code = item.item_code;
mr_item.item_name = item.item_name;
mr_item.uom = item.uom;
mr_item.conversion_factor = item.conversion_factor;
mr_item.item_group = item.item_group;
mr_item.description = item.description;
mr_item.image = item.image;

View File

@@ -288,7 +288,7 @@ class StockEntry(StockController):
# get basic rate
if not d.bom_no:
if not flt(d.basic_rate) or d.s_warehouse or force:
if (not flt(d.basic_rate) and not d.allow_zero_valuation_rate) or d.s_warehouse or force:
basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
if basic_rate > 0:
d.basic_rate = basic_rate
@@ -299,7 +299,8 @@ class StockEntry(StockController):
# get scrap items basic rate
if d.bom_no:
if not flt(d.basic_rate) and getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
if not flt(d.basic_rate) and not d.allow_zero_valuation_rate and \
getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
if basic_rate > 0:
d.basic_rate = basic_rate

View File

@@ -23,7 +23,7 @@ def make_stock_entry(**args):
def process_serial_numbers(serial_nos_list):
serial_nos_list = [
'\n'.join(serial_num['serial_no'] for serial_num in serial_nos_list)
'\n'.join(serial_num['serial_no'] for serial_num in serial_nos_list if serial_num.serial_no)
]
uniques = list(set(serial_nos_list[0].split('\n')))

View File

@@ -55,7 +55,9 @@ class StockReconciliation(StockController):
item.current_qty = qty
item.current_valuation_rate = rate
self.difference_amount += (flt(item.qty) * flt(item.valuation_rate or rate) - (flt(qty) * flt(rate)))
self.difference_amount += (flt(item.qty, item.precision("qty")) * \
flt(item.valuation_rate or rate, item.precision("valuation_rate")) \
- flt(qty) * flt(rate))
return True
items = filter(lambda d: _changed(d), self.items)
@@ -197,8 +199,8 @@ class StockReconciliation(StockController):
"company": self.company,
"stock_uom": frappe.db.get_value("Item", row.item_code, "stock_uom"),
"is_cancelled": "No",
"qty_after_transaction": row.qty,
"valuation_rate": row.valuation_rate
"qty_after_transaction": flt(row.qty, row.precision("qty")),
"valuation_rate": flt(row.valuation_rate, row.precision("valuation_rate"))
})
self.make_sl_entries([args])
@@ -242,7 +244,7 @@ class StockReconciliation(StockController):
def set_total_qty_and_amount(self):
for d in self.get("items"):
d.amount = flt(d.qty) * flt(d.valuation_rate)
d.amount = flt(d.qty, d.precision("qty")) * flt(d.valuation_rate, d.precision("valuation_rate"))
d.current_amount = flt(d.current_qty) * flt(d.current_valuation_rate)
d.quantity_difference = flt(d.qty) - flt(d.current_qty)
d.amount_difference = flt(d.amount) - flt(d.current_amount)

View File

@@ -150,7 +150,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Disabled",
"length": 0,
@@ -699,7 +699,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-08-21 02:12:33.652689",
"modified": "2018-01-23 16:45:45.546649",
"modified_by": "Administrator",
"module": "Stock",
"name": "Warehouse",

View File

@@ -246,6 +246,7 @@ def get_basic_details(args, item):
"is_fixed_asset": item.is_fixed_asset,
"weight_per_unit":item.weight_per_unit,
"weight_uom":item.weight_uom,
"last_purchase_rate": item.last_purchase_rate if args.get("doctype") in ["Purchase Order"] else 0
})
# calculate conversion factor
@@ -258,6 +259,10 @@ def get_basic_details(args, item):
args.conversion_factor = out.conversion_factor
out.stock_qty = out.qty * out.conversion_factor
# calculate last purchase rate
from erpnext.buying.doctype.purchase_order.purchase_order import item_last_purchase_rate
out.last_purchase_rate = item_last_purchase_rate(args.name, args.conversion_rate, item.item_code, out.conversion_factor)
# if default specified in item is for another company, fetch from company
for d in [
["Account", "income_account", "default_income_account"],

View File

@@ -85,18 +85,22 @@ def get_item_warehouse_projected_qty(items_to_consider):
from tabBin where item_code in ({0})
and (warehouse != "" and warehouse is not null)"""\
.format(", ".join(["%s"] * len(items_to_consider))), items_to_consider):
item_warehouse_projected_qty.setdefault(item_code, {})[warehouse] = flt(projected_qty)
if item_code not in item_warehouse_projected_qty:
item_warehouse_projected_qty.setdefault(item_code, {})
if warehouse not in item_warehouse_projected_qty.get(item_code):
item_warehouse_projected_qty[item_code][warehouse] = flt(projected_qty)
warehouse_doc = frappe.get_doc("Warehouse", warehouse)
while warehouse_doc.parent_warehouse:
if not item_warehouse_projected_qty.get(item_code, {}).get(warehouse_doc.parent_warehouse):
item_warehouse_projected_qty.setdefault(item_code, {})[warehouse_doc.parent_warehouse] = flt(projected_qty)
else:
item_warehouse_projected_qty[item_code][warehouse_doc.parent_warehouse] += flt(projected_qty)
warehouse_doc = frappe.get_doc("Warehouse", warehouse_doc.parent_warehouse)
return item_warehouse_projected_qty
def create_material_request(material_requests):

View File

@@ -12,13 +12,52 @@ def execute(filters=None):
def get_columns():
return [
_("Item Name") + ":Link/Item:150",
_("Warehouse") + ":Link/Warehouse:130",
_("Stock Available") + ":Float:120",
_("Buying Price List") + ":Data:130",
_("Buying Rate") + ":Currency:110",
_("Selling Price List") + ":Data:130",
_("Selling Rate") + ":Currency:110"
{
"label": _("Item Name"),
"fieldname": "item_name",
"fieldtype": "Link",
"options": "Item",
"width": 120
},
{
"label": _("Warehouse"),
"fieldname": "warehouse",
"fieldtype": "Link",
"options": "Warehouse",
"width": 120
},
{
"label": _("Stock Available"),
"fieldname": "stock_available",
"fieldtype": "Float",
"width": 120
},
{
"label": _("Buying Price List"),
"fieldname": "buying_price_list",
"fieldtype": "Link",
"options": "Price List",
"width": 120
},
{
"label": _("Buying Rate"),
"fieldname": "buying_rate",
"fieldtype": "Currency",
"width": 120
},
{
"label": _("Selling Price List"),
"fieldname": "selling_price_list",
"fieldtype": "Link",
"options": "Price List",
"width": 120
},
{
"label": _("Selling Rate"),
"fieldname": "selling_rate",
"fieldtype": "Currency",
"width": 120
}
]
def get_data(filters, columns):
@@ -27,72 +66,72 @@ def get_data(filters, columns):
return item_price_qty_data
def get_item_price_qty_data(filters):
item_dicts = []
conditions = ""
if filters.get("item_code"):
conditions += "where a.item_code=%(item_code)s"
item_results = frappe.db.sql("""select a.item_code as name,a.name as price_list_name,
b.warehouse as warehouse,b.actual_qty as actual_qty
item_results = frappe.db.sql("""select a.item_code as item_name, a.name as price_list_name,
b.warehouse as warehouse, b.actual_qty as actual_qty
from `tabItem Price` a left join `tabBin` b
ON a.item_code = b.item_code
{conditions}"""
.format(conditions=conditions), filters, as_dict=1)
price_list_names = ",".join(['"' + frappe.db.escape(item['price_list_name']) + '"'
for item in item_results])
price_list_names = list(set([frappe.db.escape(item.price_list_name) for item in item_results]))
buying_price_map = get_buying_price_map(price_list_names)
selling_price_map = get_selling_price_map(price_list_names)
buying_price_map = get_price_map(price_list_names, buying=1)
selling_price_map = get_price_map(price_list_names, selling=1)
item_dicts = [{"Item Name": d['name'],"Item Price List": d['price_list_name'],"Warehouse": d['warehouse'],
"Stock Available": d['actual_qty']} for d in item_results]
for item_dict in item_dicts:
price_list = item_dict["Item Price List"]
item_dict["Warehouse"] = item_dict["Warehouse"] or ""
item_dict["Stock Available"] = item_dict["Stock Available"] or 0
if buying_price_map.get(price_list):
item_dict["Buying Price List"] = buying_price_map.get(price_list)["Buying Price List"] or ""
item_dict["Buying Rate"] = buying_price_map.get(price_list)["Buying Rate"] or 0
if selling_price_map.get(price_list):
item_dict["Selling Price List"] = selling_price_map.get(price_list)["Selling Price List"] or ""
item_dict["Selling Rate"] = selling_price_map.get(price_list)["Selling Rate"] or 0
return item_dicts
result = []
if item_results:
for item_dict in item_results:
data = {
'item_name': item_dict.item_name,
'warehouse': item_dict.warehouse,
'stock_available': item_dict.actual_qty or 0,
'buying_price_list': "",
'buying_rate': 0.0,
'selling_price_list': "",
'selling_rate': 0.0
}
def get_buying_price_map(price_list_names):
buying_price = frappe.db.sql("""
price_list = item_dict["price_list_name"]
if buying_price_map.get(price_list):
data["buying_price_list"] = buying_price_map.get(price_list)["Buying Price List"] or ""
data["buying_rate"] = buying_price_map.get(price_list)["Buying Rate"] or 0
if selling_price_map.get(price_list):
data["selling_price_list"] = selling_price_map.get(price_list)["Selling Price List"] or ""
data["selling_rate"] = selling_price_map.get(price_list)["Selling Rate"] or 0
result.append(data)
return result
def get_price_map(price_list_names, buying=0, selling=0):
price_map = {}
if not price_list_names:
return price_map
rate_key = "Buying Rate" if buying else "Selling Rate"
price_list_key = "Buying Price List" if buying else "Selling Price List"
price_list_condition = " and buying=1" if buying else " and selling=1"
pricing_details = frappe.db.sql("""
select
name,price_list,price_list_rate
from
`tabItem Price`
where
name in ({price_list_names}) and buying=1
""".format(price_list_names=price_list_names), as_dict=1)
name in ({price_list_names}) {price_list_condition}
""".format(price_list_names=', '.join(['%s']*len(price_list_names)),
price_list_condition=price_list_condition), price_list_names, as_dict=1)
buying_price_map = {}
for d in buying_price:
for d in pricing_details:
name = d["name"]
buying_price_map[name] = {
"Buying Price List" :d["price_list"],
"Buying Rate" :d["price_list_rate"]
price_map[name] = {
price_list_key :d["price_list"],
rate_key :d["price_list_rate"]
}
return buying_price_map
def get_selling_price_map(price_list_names):
selling_price = frappe.db.sql("""
select
name,price_list,price_list_rate
from
`tabItem Price`
where
name in ({price_list_names}) and selling=1
""".format(price_list_names=price_list_names), as_dict=1)
selling_price_map = {}
for d in selling_price:
name = d["name"]
selling_price_map[name] = {
"Selling Price List" :d["price_list"],
"Selling Rate" :d["price_list_rate"]
}
return selling_price_map
return price_map

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