Compare commits

...

65 Commits

Author SHA1 Message Date
Nabin Hait
ca89b6f59c Merge branch 'hotfix' 2017-05-24 18:38:33 +05:30
Nabin Hait
12ec71781d bumped to version 8.0.38 2017-05-24 19:08:33 +06:00
Manas Solanki
659a225f24 allow multiple items in purchase receipt (#8997) 2017-05-24 17:49:52 +05:30
CH
d0ebd7f7c2 POS translatable fields correction 2017-05-24 17:45:46 +05:30
Nabin Hait
adfe84b04f Revert "Website Specification Labls should not be capitalised by default (#8798)"
This reverts commit 331566d612.
2017-05-24 17:33:07 +05:30
Nabin Hait
7916590528 Revert "Update lead.py (#8789)"
This reverts commit 9283377f87.
2017-05-24 17:33:07 +05:30
Nabin Hait
fdce7a0dc3 Revert "link the different doctype in the school module (#8844)"
This reverts commit c320537e4c.
2017-05-24 17:33:07 +05:30
Nabin Hait
b3d4326dcc Revert "Prompt for mandatory batch number in POS (#8928)"
This reverts commit ce9ac7885e.
2017-05-24 17:33:07 +05:30
Nabin Hait
54fcf85317 Revert "Documentation for Allow Login using Mobile Number (#8918)"
This reverts commit 818ad397c8.
2017-05-24 17:33:07 +05:30
Nabin Hait
689da20e7b Revert "View Attachments in portal (#8830)"
This reverts commit 7e661437b1.
2017-05-24 17:33:07 +05:30
Nabin Hait
eb92d907bc Revert "Added flt to convert string to float"
This reverts commit bf4915b285.
2017-05-24 17:33:07 +05:30
Nabin Hait
0cd792ebb2 Revert "Update taxes_and_totals.py"
This reverts commit e4afab7fb0.
2017-05-24 17:33:07 +05:30
Rushabh Mehta
e4afab7fb0 Update taxes_and_totals.py 2017-05-24 17:29:23 +05:30
Ayush AS
bf4915b285 Added flt to convert string to float 2017-05-24 17:29:23 +05:30
Charles-Henri Decultot
7e661437b1 View Attachments in portal (#8830)
* View Attachments in portal

* HTML beautify correction

* Move option to shopping cart settings

* new field in shopping cart settings for public attachments display in portal
2017-05-24 17:29:23 +05:30
Gaurav Naik
818ad397c8 Documentation for Allow Login using Mobile Number (#8918) 2017-05-24 17:29:23 +05:30
Charles-Henri Decultot
ce9ac7885e Prompt for mandatory batch number in POS (#8928)
* Prompt for mandatory batch number in POS

* Whitespaces correction
2017-05-24 17:29:23 +05:30
Manas Solanki
c320537e4c link the different doctype in the school module (#8844) 2017-05-24 17:29:23 +05:30
Abdulla P I
9283377f87 Update lead.py (#8789)
* Update lead.py

Import datetime to compare next contact date with now()

* Update lead.py

* Update lead.py

As per the suggestion from Nabin,instead of Datetime,getdate and nowdate from frappe.utils imported
2017-05-24 17:29:23 +05:30
KanchanChauhan
331566d612 Website Specification Labls should not be capitalised by default (#8798) 2017-05-24 17:29:23 +05:30
mbauskar
ff70f38eac [minor] patch to delete the schools deprecated doctypes 2017-05-24 17:13:16 +05:30
mbauskar
d1552f97e4 [minor] moved a comment in item.js 2017-05-24 17:13:16 +05:30
mbauskar
baa4afd67b [minor] removed the Grade Interval and Grading Structure doctype 2017-05-24 17:13:16 +05:30
Nabin Hait
2f0c34385b Check if doctype exists before renaming 2017-05-24 17:12:07 +05:30
Nabin Hait
258f7da778 Paid amount + Write Off Amount can not be greater than Grand Total in return POS 2017-05-24 17:12:07 +05:30
Nabin Hait
799a9cabe7 Can't change valuation method in stock settings, if there are transactions against some items which does not have it's own valuation method 2017-05-24 17:11:48 +05:30
Nabin Hait
24f0b13b22 Total unpaid amount in party is based on GLE 2017-05-24 16:46:56 +05:30
Nabin Hait
2d79a641c2 Annual billing amount in party dashboard based on grand total 2017-05-24 16:46:56 +05:30
Nabin Hait
7a9bd41a72 Improved currency exchange rate message 2017-05-24 16:18:36 +05:30
Nabin Hait
cf1e0508af Merge branch 'hotfix' 2017-05-24 09:07:26 +05:30
Nabin Hait
88906cfc63 bumped to version 8.0.37 2017-05-24 09:37:26 +06:00
Nabin Hait
e72c98dafb On change of item rate, set margin amount on price list rate, instead of margin percentage (#8988) 2017-05-24 09:01:44 +05:30
Nabin Hait
f8b412ba98 Merge branch 'hotfix' 2017-05-23 17:48:42 +05:30
Nabin Hait
c8a25b6dac bumped to version 8.0.36 2017-05-23 18:18:42 +06:00
Makarand Bauskar
724cc35421 [minor] added columns to pos print_template (#8978) 2017-05-23 17:43:42 +05:30
Nabin Hait
67ae3a7f22 Merge branch 'hotfix' 2017-05-23 17:16:19 +05:30
Nabin Hait
8854f8bd50 bumped to version 8.0.35 2017-05-23 17:46:19 +06:00
Manas Solanki
fe05645051 fix issue when image not saved after attaching (#8957) 2017-05-23 17:13:26 +05:30
Faris Ansari
29d64cae34 POS print format fix (#8973) 2017-05-23 17:12:51 +05:30
Nabin Hait
84e50fe371 Merge branch 'hotfix' 2017-05-23 12:04:06 +05:30
Nabin Hait
2ef20a968c bumped to version 8.0.34 2017-05-23 12:34:05 +06:00
Nabin Hait
fdc7d7f3de Check for active quotations before declaring it as lost (#8969) 2017-05-23 12:02:34 +05:30
Manas Solanki
a68fff470c minor fix in student group (#8959) 2017-05-23 11:39:53 +05:30
Manas Solanki
552f7ab678 fix in the patch for merging the student batch and student group (#8961) 2017-05-23 11:38:57 +05:30
Faris Ansari
2424aa73d7 Fix translated string in jinja (#8956) 2017-05-22 13:09:36 +05:30
Rushabh Mehta
50835cbaa0 Merge branch 'hotfix' 2017-05-19 19:24:42 +05:30
Rushabh Mehta
f3a318921f bumped to version 8.0.33 2017-05-19 19:54:42 +06:00
rohitwaghchaure
529f5ce503 [fix] Not able to change the status as Lost in opportunity (#8938) 2017-05-19 18:56:54 +05:30
rohitwaghchaure
177a26849d [fix] Trial balance not working (#8937) 2017-05-19 18:56:25 +05:30
Rushabh Mehta
d144a4c621 Merge branch 'hotfix' 2017-05-19 18:33:55 +05:30
Rushabh Mehta
d2484ece24 bumped to version 8.0.32 2017-05-19 19:03:54 +06:00
Rushabh Mehta
04ea4910f0 [rename] zh-tw -> zh-TW 2017-05-19 18:27:53 +05:30
Rushabh Mehta
65a27395fe [minor] remove student batch name from activation.py 2017-05-19 14:53:32 +05:30
Nabin Hait
91dcd8d952 Merge branch 'hotfix' 2017-05-19 14:12:28 +05:30
Nabin Hait
4d2d996782 bumped to version 8.0.31 2017-05-19 14:42:28 +06:00
Nabin Hait
47afc55939 Merge branch 'master' of github.com:frappe/erpnext into hotfix 2017-05-19 14:10:53 +05:30
rohitwaghchaure
81fcbbefe5 Merge pull request #8929 from rohitwaghchaure/pos_transalate_issue
[fix] _ is not defined while accessing the POS
2017-05-19 13:23:27 +05:30
Rohit Waghchaure
8a1c58c3c3 [fix] _ is not defined while accessing the POS 2017-05-19 13:01:32 +05:30
Prateeksha Singh
89cec18467 set variant name based on template name (frappe/erpnext#6367) (#8920) 2017-05-19 12:35:36 +05:30
Rushabh Mehta
4bcc2316a9 Don't update variant when template is updated (#8922)
* [fix] allow editing of variant properties, reverting earlier fix

* [minor] dont automatically update variants when the template is saved
2017-05-19 12:33:00 +05:30
Nabin Hait
012c9a0916 Set default account in mode-of-payment Cash, only if default cash account exists (#8909) 2017-05-19 12:30:58 +05:30
Rushabh Mehta
c6d75eb942 [fix] allow editing of variant properties, reverting earlier fix (#8905) 2017-05-18 16:21:01 +05:30
Nabin Hait
83f8344e62 Merge branch 'master' of github.com:frappe/erpnext into hotfix 2017-05-18 14:06:37 +05:30
Nabin Hait
ee59ecd396 Merge branch 'hotfix' of github.com:frappe/erpnext into hotfix 2017-05-18 14:06:06 +05:30
Nabin Hait
c9b6a07732 [fix] Remove recurring id on amendment only if it is same as amended_from 2016-11-16 18:43:44 +05:30
37 changed files with 176 additions and 533 deletions

View File

@@ -2,7 +2,7 @@
from __future__ import unicode_literals
import frappe
__version__ = '8.0.30'
__version__ = '8.0.38'
def get_default_company(user=None):

View File

@@ -411,10 +411,10 @@ class SalesInvoice(SellingController):
throw(_("Customer {0} does not belong to project {1}").format(self.customer,self.project))
def validate_pos(self):
if flt(self.paid_amount) + flt(self.write_off_amount) \
- flt(self.grand_total) > 1/(10**(self.precision("grand_total") + 1)) and self.is_return:
frappe.throw(_("""Paid amount + Write Off Amount can not be greater than Grand Total"""))
if self.is_return:
if flt(self.paid_amount) + flt(self.write_off_amount) - flt(self.grand_total) < \
1/(10**(self.precision("grand_total") + 1)):
frappe.throw(_("Paid amount + Write Off Amount can not be greater than Grand Total"))
def validate_item_code(self):
for d in self.get('items'):

View File

@@ -355,8 +355,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.print_template_data = frappe.render_template("print_template", {
content: this.print_template,
title: "POS", base_url: frappe.urllib.get_base_url(), print_css: frappe.boot.print_css,
print_settings: this.print_settings, header: this.letter_head.header, footer: this.letter_head.footer
title: "POS",
base_url: frappe.urllib.get_base_url(),
print_css: frappe.boot.print_css,
print_settings: this.print_settings,
header: this.letter_head.header,
footer: this.letter_head.footer,
landscape: false,
columns: []
})
},

View File

@@ -7,10 +7,13 @@ import frappe
import datetime
from frappe import _, msgprint, scrub
from frappe.defaults import get_user_permissions
from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, add_years, get_timestamp
from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, \
add_years, get_timestamp, nowdate
from frappe.geo.doctype.address.address import get_address_display, get_default_address
from frappe.email.doctype.contact.contact import get_contact_details, get_default_contact
from erpnext.exceptions import PartyFrozen, InvalidCurrency, PartyDisabled, InvalidAccountCurrency
from erpnext.accounts.utils import get_fiscal_year
from erpnext import get_default_currency
class DuplicatePartyAccountError(frappe.ValidationError): pass
@@ -359,4 +362,37 @@ def get_timeline_data(doctype, name):
timestamp = get_timestamp(date)
out.update({ timestamp: count })
return out
return out
def get_dashboard_info(party_type, party):
current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True)
party_account_currency = get_party_account_currency(party_type, party, frappe.db.get_default("company"))
company_default_currency = get_default_currency()
if party_account_currency==company_default_currency:
total_field = "base_grand_total"
else:
total_field = "grand_total"
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
billing_this_year = frappe.db.sql("""
select sum({0})
from `tab{1}`
where {2}=%s and docstatus=1 and posting_date between %s and %s
""".format(total_field, doctype, party_type.lower()),
(party, current_fiscal_year.year_start_date, current_fiscal_year.year_end_date))
total_unpaid = frappe.db.sql("""
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabGL Entry`
where party_type = %s and party=%s""", (party_type, party))
info = {}
info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0
info["currency"] = party_account_currency
info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0
if party_type == "Supplier":
info["total_unpaid"] = -1 * info["total_unpaid"]
return info

View File

@@ -278,7 +278,7 @@ def sort_root_accounts(roots):
"""Sort root types as Asset, Liability, Equity, Income, Expense"""
def compare_roots(a, b):
if re.split('\W+', a.value)[0].isdigit():
if a.value and re.split('\W+', a.value)[0].isdigit():
# if chart of accounts is numbered, then sort by number
return cmp(a.value, b.value)
if a.report_type != b.report_type and a.report_type == "Balance Sheet":

View File

@@ -6,11 +6,9 @@ import frappe
import frappe.defaults
from frappe import msgprint, _
from frappe.model.naming import make_autoname
from frappe.geo.address_and_contact import (load_address_and_contact,
delete_contact_and_address)
from frappe.geo.address_and_contact import load_address_and_contact, delete_contact_and_address
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
class Supplier(TransactionBase):
def get_feed(self):
@@ -22,22 +20,7 @@ class Supplier(TransactionBase):
self.load_dashboard_info()
def load_dashboard_info(self):
billing_this_year = frappe.db.sql("""
select sum(credit_in_account_currency) - sum(debit_in_account_currency)
from `tabGL Entry`
where voucher_type='Purchase Invoice' and party_type = 'Supplier'
and party=%s and fiscal_year = %s""",
(self.name, frappe.db.get_default("fiscal_year")))
total_unpaid = frappe.db.sql("""select sum(outstanding_amount)
from `tabPurchase Invoice`
where supplier=%s and docstatus = 1""", self.name)
info = {}
info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0
info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0
info = get_dashboard_info(self.doctype, self.name)
self.set_onload('dashboard_info', info)
def autoname(self):

View File

@@ -54,7 +54,7 @@ class AccountsController(TransactionBase):
self.validate_currency()
if self.meta.get_field("is_recurring"):
if self.amended_from and self.recurring_id:
if self.amended_from and self.recurring_id == self.amended_from:
self.recurring_id = None
if not self.get("__islocal"):
validate_recurring_document(self)

View File

@@ -165,7 +165,7 @@ def create_variant(item, args):
variant.set("attributes", variant_attributes)
copy_attributes_to_variant(template, variant)
make_variant_item_code(template.item_code, variant)
make_variant_item_code(template.item_code, template.item_name, variant)
return variant
@@ -194,7 +194,7 @@ def copy_attributes_to_variant(item, variant):
for d in variant.attributes:
variant.description += "<p>" + d.attribute + ": " + cstr(d.attribute_value) + "</p>"
def make_variant_item_code(template_item_code, variant):
def make_variant_item_code(template_item_code, template_item_name, variant):
"""Uses template's item code and abbreviations to make variant's item code"""
if variant.item_code:
return
@@ -220,6 +220,4 @@ def make_variant_item_code(template_item_code, variant):
if abbreviations:
variant.item_code = "{0}-{1}".format(template_item_code, "-".join(abbreviations))
if variant.item_code:
variant.item_name = variant.item_code
variant.item_name = "{0}-{1}".format(template_item_name, "-".join(abbreviations))

View File

@@ -43,7 +43,8 @@ class Lead(SellingController):
if self.email_id == self.contact_by:
frappe.throw(_("Next Contact By cannot be same as the Lead Email Address"))
self.image = has_gravatar(self.email_id)
if self.is_new() or not self.image:
self.image = has_gravatar(self.email_id)
if self.contact_date and self.contact_date < now():
frappe.throw(_("Next Contact Date cannot be in the past"))

View File

@@ -75,7 +75,7 @@ class Opportunity(TransactionBase):
self.lead = lead_name
def declare_enquiry_lost(self,arg):
if not self.has_quotation():
if not self.has_active_quotation():
frappe.db.set(self, 'status', 'Lost')
frappe.db.set(self, 'order_lost_reason', arg)
else:

View File

@@ -396,3 +396,4 @@ erpnext.patches.v8_0.merge_student_batch_and_student_group
erpnext.patches.v8_0.rename_total_margin_to_rate_with_margin # 11-05-2017
erpnext.patches.v8_0.fix_status_for_invoices_with_negative_outstanding
erpnext.patches.v8_0.make_payments_table_blank_for_non_pos_invoice
erpnext.patches.v8_0.delete_schools_depricated_doctypes

View File

@@ -3,26 +3,32 @@ from frappe.model.utils.rename_field import rename_field
def execute():
#Rename Grading Structure to Grading Scale
frappe.rename_doc("DocType", "Grading Structure", "Grading Scale", force=True)
frappe.rename_doc("DocType", "Grade Interval", "Grading Scale Interval", force=True)
if not frappe.db.exists("DocType", "Grading Scale"):
frappe.rename_doc("DocType", "Grading Structure", "Grading Scale", force=True)
if not frappe.db.exists("DocType", "Grading Scale Interval"):
frappe.rename_doc("DocType", "Grade Interval", "Grading Scale Interval", force=True)
frappe.reload_doc("schools", "doctype", "grading_scale_interval")
rename_field("Grading Scale Interval", "to_score", "threshold")
if "to_score" in frappe.db.get_table_columns("Grading Scale Interval"):
rename_field("Grading Scale Interval", "to_score", "threshold")
frappe.rename_doc("DocType", "Assessment", "Assessment Plan", force=True)
if not frappe.db.exists("DocType", "Assessment Plan"):
frappe.rename_doc("DocType", "Assessment", "Assessment Plan", force=True)
#Rename Assessment Results
frappe.reload_doc("schools", "doctype", "assessment_plan")
rename_field("Assessment Plan", "grading_structure", "grading_scale")
if "grading_structure" in frappe.db.get_table_columns("Assessment Plan"):
rename_field("Assessment Plan", "grading_structure", "grading_scale")
frappe.reload_doc("schools", "doctype", "assessment_result")
frappe.reload_doc("schools", "doctype", "assessment_result_detail")
frappe.reload_doc("schools", "doctype", "assessment_criteria")
for assessment in frappe.get_all("Assessment Plan", fields=["name", "grading_scale"], filters = [["docstatus", "!=", 2 ]]):
print assessment
for stud_result in frappe.db.sql("select * from `tabAssessment Result` where parent= %s", assessment.name, as_dict=True):
for assessment in frappe.get_all("Assessment Plan",
fields=["name", "grading_scale"], filters = [["docstatus", "!=", 2 ]]):
for stud_result in frappe.db.sql("select * from `tabAssessment Result` where parent= %s",
assessment.name, as_dict=True):
if stud_result.result:
assessment_result = frappe.new_doc("Assessment Result")
assessment_result.student = stud_result.student

View File

@@ -0,0 +1,14 @@
# Copyright (c) 2017, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
""" delete doctypes """
if frappe.db.exists("DocType", "Grading Structure"):
frappe.delete_doc("DocType", "Grading Structure", force=1)
if frappe.db.exists("DocType", "Grade Interval"):
frappe.delete_doc("DocType", "Grade Interval", force=1)

View File

@@ -11,43 +11,55 @@ def execute():
# for converting student batch into student group
frappe.reload_doctype("Student Group")
student_batches = frappe.db.sql('''select name as student_group_name, student_batch_name as batch,
program, academic_year, academic_term from `tabStudent Batch`''', as_dict=1)
for student_batch in student_batches:
# create student batch name if does not exists !!
if student_batch.get("batch") and not frappe.db.exists("Student Batch Name", student_batch.get("batch")):
frappe.get_doc({
"doctype": "Student Batch Name",
"batch_name": student_batch.get("batch")
}).insert(ignore_permissions=True)
if frappe.db.table_exists("Student Batch"):
student_batches = frappe.db.sql('''select name as student_group_name, student_batch_name as batch,
program, academic_year, academic_term from `tabStudent Batch`''', as_dict=1)
student_batch.update({"doctype":"Student Group", "group_based_on": "Batch"})
doc = frappe.get_doc(student_batch)
student_list = frappe.db.sql('''select student, student_name, active from `tabStudent Batch Student`
where parent=%s''', (doc.name), as_dict=1)
for i, student in enumerate(student_list):
student.update({"group_roll_number": i+1})
for student_batch in student_batches:
# create student batch name if does not exists !!
if student_batch.get("batch") and not frappe.db.exists("Student Batch Name", student_batch.get("batch")):
frappe.get_doc({
"doctype": "Student Batch Name",
"batch_name": student_batch.get("batch")
}).insert(ignore_permissions=True)
if student_list:
doc.extend("students", student_list)
student_batch.update({"doctype":"Student Group", "group_based_on": "Batch"})
doc = frappe.get_doc(student_batch)
instructor_list = frappe.db.sql('''select instructor, instructor_name from `tabStudent Batch Instructor`
where parent=%s''', (doc.name), as_dict=1)
if instructor_list:
doc.extend("instructors", instructor_list)
doc.save()
if frappe.db.sql("SHOW COLUMNS FROM `tabStudent Batch Student` LIKE 'active'"):
cond = ", active"
else:
cond = " "
student_list = frappe.db.sql('''select student, student_name {cond} from `tabStudent Batch Student`
where parent=%s'''.format(cond=cond), (doc.name), as_dict=1)
if student_list:
for i, student in enumerate(student_list):
student.update({"group_roll_number": i+1})
doc.extend("students", student_list)
instructor_list = frappe.db.sql('''select instructor, instructor_name from `tabStudent Batch Instructor`
where parent=%s''', (doc.name), as_dict=1)
if instructor_list:
doc.extend("instructors", instructor_list)
doc.save()
# delete the student batch and child-table
frappe.delete_doc("DocType", "Student Batch", force=1)
frappe.delete_doc("DocType", "Student Batch Student", force=1)
frappe.delete_doc("DocType", "Student Batch Instructor", force=1)
if frappe.db.table_exists("Student Batch"):
frappe.delete_doc("DocType", "Student Batch", force=1)
if frappe.db.table_exists("Student Batch Student"):
frappe.delete_doc("DocType", "Student Batch Student", force=1)
if frappe.db.table_exists("Student Batch Instructor"):
frappe.delete_doc("DocType", "Student Batch Instructor", force=1)
# delete the student batch creation tool
frappe.delete_doc("DocType", "Student Batch Creation Tool", force=1)
if frappe.db.table_exists("Student Batch Creation Tool"):
frappe.delete_doc("DocType", "Student Batch Creation Tool", force=1)
# delete the student batch creation tool
frappe.delete_doc("DocType", "Attendance Tool Student", force=1)
if frappe.db.table_exists("Attendance Tool Student"):
frappe.delete_doc("DocType", "Attendance Tool Student", force=1)
# change the student batch to student group in the student attendance
frappe.reload_doctype("Student Attendance")

View File

@@ -15,10 +15,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
// if rate is greater than price_list_rate, set margin
// or set discount
item.discount_percentage = 0;
item.margin_type = 'Percentage';
item.margin_rate_or_amount = flt(Math.abs(1 - item.rate / item.price_list_rate) * 100.0,
precision("discount_percentage", item));
item.rate_with_margin = item.rate;
item.margin_type = 'Amount';
item.margin_rate_or_amount = flt(item.rate - item.price_list_rate,
precision("margin_rate_or_amount", item));
item.rate_with_margin = item.rate;
} else {
item.discount_percentage = flt((1 - item.rate / item.price_list_rate) * 100.0,
precision("discount_percentage", item));

View File

@@ -68,12 +68,12 @@
</div>
<div class="col-xs-6 numeric_keypad hidden-xs" style="display:none">
{% var chartData = [__("Qty"), __("Disc"), __("Price")] %} {% for(var i=0; i
{% var chartData = ["Qty", "Disc", "Price"] %} {% for(var i=0; i
<3; i++) { %} <div class="row text-right">
{% for(var j=i*3; j
<(i+1)*3; j++) { %} <button type="button" class="btn btn-default numeric-keypad" val="{{j+1}}">{{j+1}}</button>
{% } %}
<button type="button" id="pos-item-{{ chartData[i].toLowerCase() }}" class="btn text-center btn-default numeric-keypad pos-operation">{{ chartData[i] }}</button>
<button type="button" id="pos-item-{{ chartData[i].toLowerCase() }}" class="btn text-center btn-default numeric-keypad pos-operation">{{ __(chartData[i]) }}</button>
</div>
{% } %}
<div class="row text-right">
@@ -120,8 +120,8 @@
<div class="cell search-item"></div>
</div>
<div class="app-listing item-list image-view-container">
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,7 +1,7 @@
<div class="pos-item-wrapper image-view-item" data-item-code="{{item_code}}">
<div class="image-view-header doclist-row">
<div class="list-value">
<a class="grey list-id" data-name="{{item_code}}" title="{{ item_name || item_code}}">{{item_name || item_code}}<br>({{ _(item_stock) }})</a>
<a class="grey list-id" data-name="{{item_code}}" title="{{ item_name || item_code}}">{{item_name || item_code}}<br>({{ __(item_stock) }})</a>
</div>
</div>
<div class="image-view-body">

View File

@@ -1,122 +0,0 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-08-26 03:11:09.591049",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grade_code",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Grade Code",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "min_score",
"fieldtype": "Percent",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Min Score",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "1",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grade_description",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Grade Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-12-14 12:54:56.902465",
"modified_by": "Administrator",
"module": "Schools",
"name": "Grade Interval",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

View File

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

View File

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

View File

@@ -1,202 +0,0 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 1,
"autoname": "field:grading_system_name",
"beta": 0,
"creation": "2016-08-26 03:06:53.922972",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grading_system_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Grading System 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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grading_intervals_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Grading Intervals",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "grade_intervals",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Grade Intervals",
"length": 0,
"no_copy": 0,
"options": "Grade Interval",
"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
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-12-14 12:35:39.690256",
"modified_by": "Administrator",
"module": "Schools",
"name": "Grading Structure",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Academics User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "grading_system_name",
"track_seen": 0
}

View File

@@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
from frappe.utils import cstr
class GradingStructure(Document):
def validate(self):
grade_intervals = self.get("grade_intervals")
check_overlap(grade_intervals, self)
#Check if any of the grade intervals for this grading structure overlap
def check_overlap(grade_intervals, parent_doc):
for interval1 in grade_intervals:
for interval2 in grade_intervals:
if interval1.name == interval2.name:
pass
else:
if (interval1.from_score <= interval2.from_score and interval1.to_score >= interval2.from_score) or (interval1.from_score <= interval2.to_score and interval1.to_score >= interval2.to_score):
frappe.throw(_("""The intervals for Grade Code {0} overlaps with the grade intervals for other grades.
Please check intervals {0} and {1} and try again""".format(interval1.grade_code, interval2.grade_code)))

View File

@@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
# test_records = frappe.get_test_records('Grading Structure')
class TestGradingStructure(unittest.TestCase):
pass

View File

@@ -33,7 +33,7 @@ class StudentGroup(Document):
program_enrollment = get_program_enrollment(self.academic_year, self.academic_term, self.program, self.batch, self.course)
students = [d.student for d in program_enrollment] if program_enrollment else None
for d in self.students:
if self.group_based_on != "Activity" and d.student not in students and d.active == 1:
if self.group_based_on != "Activity" and students and d.student not in students and d.active == 1:
frappe.throw(_("{0} - {1} is not enrolled in the given {2}".format(d.group_roll_number, d.student_name, self.group_based_on)))
if not frappe.db.get_value("Student", d.student, "enabled") and d.active:
frappe.throw(_("{0} - {1} is inactive student".format(d.group_roll_number, d.student_name)))

View File

@@ -10,8 +10,7 @@ from frappe.utils import flt, cint, cstr
from frappe.desk.reportview import build_match_conditions
from erpnext.utilities.transaction_base import TransactionBase
from frappe.geo.address_and_contact import load_address_and_contact, delete_contact_and_address
from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this
from erpnext import get_default_currency
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
class Customer(TransactionBase):
def get_feed(self):
@@ -23,25 +22,9 @@ class Customer(TransactionBase):
self.load_dashboard_info()
def load_dashboard_info(self):
billing_this_year = frappe.db.sql("""
select sum(debit_in_account_currency) - sum(credit_in_account_currency), account_currency
from `tabGL Entry`
where voucher_type='Sales Invoice' and party_type = 'Customer'
and party=%s and fiscal_year = %s""",
(self.name, frappe.db.get_default("fiscal_year")))
total_unpaid = frappe.db.sql("""select sum(outstanding_amount)
from `tabSales Invoice`
where customer=%s and docstatus = 1""", self.name)
info = {}
info["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0
info["currency"] = billing_this_year[0][1] if billing_this_year else get_default_currency()
info["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0
info = get_dashboard_info(self.doctype, self.name)
self.set_onload('dashboard_info', info)
def autoname(self):
cust_master_name = frappe.defaults.get_global_default('cust_master_name')
if cust_master_name == 'Customer Name':

View File

@@ -348,9 +348,13 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
margin_type: function(doc, cdt, cdn){
// calculate the revised total margin and rate on margin type changes
item = locals[cdt][cdn];
this.apply_pricing_rule_on_item(item, doc,cdt, cdn)
this.calculate_taxes_and_totals();
cur_frm.refresh_fields();
if(!item.margin_type) {
frappe.model.set_value(cdt, cdn, "margin_rate_or_amount", 0);
} else {
this.apply_pricing_rule_on_item(item, doc,cdt, cdn)
this.calculate_taxes_and_totals();
cur_frm.refresh_fields();
}
}
});

View File

@@ -170,7 +170,8 @@ class Company(Document):
def set_mode_of_payment_account(self):
cash = frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name')
if cash and not frappe.db.get_value('Mode of Payment Account', {'company': self.name}):
if cash and self.default_cash_account \
and not frappe.db.get_value('Mode of Payment Account', {'company': self.name}):
mode_of_payment = frappe.get_doc('Mode of Payment', cash)
mode_of_payment.append('accounts', {
'company': self.name,

View File

@@ -91,8 +91,7 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None):
response.raise_for_status()
value = response.json()["rates"][to_currency]
cache.setex(key, value, 6 * 60 * 60)
return flt(value)
except:
frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}").format(from_currency, to_currency, transaction_date))
frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually").format(from_currency, to_currency, transaction_date))
return 0.0

View File

@@ -44,8 +44,6 @@ frappe.ui.form.on("Item", {
}, __("View"));
}
// make sensitive fields(has_serial_no, is_stock_item, valuation_method)
// read only if any stock ledger entry exists
if(!frm.doc.is_fixed_asset) {
erpnext.item.make_dashboard(frm);
}
@@ -65,7 +63,7 @@ frappe.ui.form.on("Item", {
frm.page.set_inner_btn_group_as_primary(__("Make"));
}
if (frm.doc.variant_of) {
frm.set_intro(__("This Item is a Variant of {0} (Template). Attributes will be copied over from the template unless 'No Copy' is set",
frm.set_intro(__("This Item is a Variant of {0} (Template).",
[frm.doc.variant_of]), true);
}
@@ -77,6 +75,8 @@ frappe.ui.form.on("Item", {
erpnext.item.edit_prices_button(frm);
// make sensitive fields(has_serial_no, is_stock_item, valuation_method, has_batch_no)
// read only if any stock ledger entry exists
if (!frm.doc.__islocal && frm.doc.is_stock_item) {
frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method', 'has_batch_no'],
(frm.doc.__onload && frm.doc.__onload.sle_exists=="exists") ? false : true);
@@ -97,8 +97,6 @@ frappe.ui.form.on("Item", {
}
frappe.set_route('Form', 'Item', new_item.name);
});
frm.trigger('make_variant_fields_read_only');
},
validate: function(frm){
@@ -109,16 +107,6 @@ frappe.ui.form.on("Item", {
refresh_field("image_view");
},
make_variant_fields_read_only: function(frm) {
if(frm.doc.variant_of) {
frm.meta.fields.forEach(function(df) {
if (!df.no_copy) {
frm.toggle_enable(df.fieldname, false);
}
});
}
},
is_fixed_asset: function(frm) {
if (frm.doc.is_fixed_asset) {
frm.set_value("is_stock_item", 0);

View File

@@ -86,7 +86,6 @@ class Item(WebsiteGenerator):
self.validate_has_variants()
self.validate_attributes()
self.validate_variant_attributes()
self.copy_variant_attributes()
self.validate_website_image()
self.make_thumbnail()
self.validate_fixed_asset()
@@ -101,7 +100,6 @@ class Item(WebsiteGenerator):
invalidate_cache_for_item(self)
self.validate_name_with_item_group()
self.update_item_price()
self.update_variants()
self.update_template_item()
def add_price(self, price_list=None):
@@ -613,23 +611,8 @@ class Item(WebsiteGenerator):
if not template_item.show_in_website:
template_item.show_in_website = 1
template_item.flags.ignore_permissions = True
template_item.flags.dont_update_variants = True
template_item.save()
def update_variants(self):
if self.flags.dont_update_variants:
return
if self.has_variants:
updated = []
variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name })
for d in variants:
variant = frappe.get_doc("Item", d)
copy_attributes_to_variant(self, variant)
variant.save()
updated.append(d.item_code)
if updated:
frappe.msgprint(_("Item Variants {0} updated").format(", ".join(updated)))
def validate_has_variants(self):
if not self.has_variants and frappe.db.get_value("Item", self.name, "has_variants"):
if frappe.db.exists("Item", {"variant_of": self.name}):
@@ -673,12 +656,6 @@ class Item(WebsiteGenerator):
validate_item_variant_attributes(self, args)
def copy_variant_attributes(self):
'''Copy attributes from template (if they have been changed before saving)'''
if self.variant_of:
template = frappe.get_doc('Item', self.variant_of)
copy_attributes_to_variant(template, self)
def get_timeline_data(doctype, name):
'''returns timeline data based on stock ledger entry'''
out = {}

View File

@@ -74,7 +74,8 @@ class PurchaseReceipt(BuyingController):
"Purchase Order Item": {
"ref_dn_field": "purchase_order_item",
"compare_fields": [["project", "="], ["uom", "="], ["item_code", "="]],
"is_child_table": True
"is_child_table": True,
"allow_duplicate_prev_row_id": True
}
})

View File

@@ -26,3 +26,19 @@ class StockSettings(Document):
# show/hide barcode field
frappe.make_property_setter({'fieldname': 'barcode', 'property': 'hidden',
'value': 0 if self.show_barcode_field else 1})
self.cant_change_valuation_method()
def cant_change_valuation_method(self):
db_valuation_method = frappe.db.get_single_value("Stock Settings", "valuation_method")
if db_valuation_method and db_valuation_method != self.valuation_method:
# check if there are any stock ledger entries against items
# which does not have it's own valuation method
sle = frappe.db.sql("""select name from `tabStock Ledger Entry` sle
where exists(select name from tabItem
where name=sle.item_code and (valuation_method is null or valuation_method=''))
""")
if sle:
frappe.throw(_("Can't change valuation method, as there are transactions against some items which does not have it's own valuation method"))

View File

@@ -33,14 +33,14 @@
</div>
<div class="text-center item-group-nav-buttons">
{% if frappe.form_dict.start|int > 0 %}
<a class="btn btn-default" href="/{{ pathname }}?start={{ frappe.form_dict.start|int - page_length }}">{{ __("Prev") }}</a>
<a class="btn btn-default" href="/{{ pathname }}?start={{ frappe.form_dict.start|int - page_length }}">{{ _("Prev") }}</a>
{% endif %}
{% if items|length > page_length %}
<a class="btn btn-default" href="/{{ pathname }}?start={{ frappe.form_dict.start|int + page_length }}">{{ __("Next") }}</a>
<a class="btn btn-default" href="/{{ pathname }}?start={{ frappe.form_dict.start|int + page_length }}">{{ _("Next") }}</a>
{% endif %}
</div>
{% else %}
<div class="text-muted">{{ __("No items listed") }}.</div>
<div class="text-muted">{{ _("No items listed") }}.</div>
{% endif %}
</div>
</div>

View File

@@ -37,9 +37,6 @@ def get_level():
if frappe.db.count('Student') > 5:
activation_level += 1
if frappe.db.count('Student Batch Name') > 5:
activation_level += 1
if frappe.db.count('Instructor') > 5:
activation_level += 1