mirror of
https://github.com/frappe/erpnext.git
synced 2026-07-25 21:55:04 +00:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ad556cd4c | ||
|
|
475729cefe | ||
|
|
f7713ebfa7 | ||
|
|
92640cc899 | ||
|
|
826f020862 | ||
|
|
93a186aa11 | ||
|
|
742d3e5549 | ||
|
|
bcbe32ce7c | ||
|
|
b434f2687e | ||
|
|
a752eca82c | ||
|
|
37da7d7d05 | ||
|
|
b5d9b38dee | ||
|
|
11e2a9ac90 | ||
|
|
1275ea5123 | ||
|
|
812224e56e | ||
|
|
8f17281011 | ||
|
|
8233cb11ed | ||
|
|
984a7a7e61 | ||
|
|
b5cc946771 | ||
|
|
65dd1f6b4c | ||
|
|
7c9a6eba3f | ||
|
|
f2ccde0454 | ||
|
|
b81ece9ddf | ||
|
|
2f822476dd | ||
|
|
dcfe19d868 | ||
|
|
4f40b2dca5 | ||
|
|
1b48fde986 | ||
|
|
33db332eca | ||
|
|
257e18b640 | ||
|
|
292f46fec0 | ||
|
|
78a0be666f | ||
|
|
ce4f520908 | ||
|
|
29160441bb | ||
|
|
1b18bba04a | ||
|
|
f8c26bb778 | ||
|
|
ccd0617e19 | ||
|
|
bf10d0f98b | ||
|
|
dbb67fb4fd | ||
|
|
404f39d373 | ||
|
|
bbee9b6cc4 | ||
|
|
69b0535e10 | ||
|
|
7f63c1ad7c | ||
|
|
ebe1ebead2 | ||
|
|
f2b3307136 | ||
|
|
9d215c2d9b | ||
|
|
3cf0d51e65 | ||
|
|
9fc5ddc26e | ||
|
|
0ff31f0ebf | ||
|
|
40349f4b00 | ||
|
|
b36517158b | ||
|
|
3b9720f0be | ||
|
|
cf26b2ca1c |
@@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '10.1.30'
|
||||
__version__ = '10.1.35'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
||||
@@ -27,10 +27,20 @@ def create_or_update_cheque_print_format(template_name):
|
||||
doc = frappe.get_doc("Cheque Print Template", template_name)
|
||||
|
||||
cheque_print.html = """
|
||||
<style>
|
||||
.print-format {
|
||||
padding: 0px;
|
||||
}
|
||||
@media screen {
|
||||
.print-format {
|
||||
padding: 0in;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div style="position: relative; top:%(starting_position_from_top_edge)scm">
|
||||
<div style="width:%(cheque_width)scm;height:%(cheque_height)scm;">
|
||||
<span style="top:%(acc_pay_dist_from_top_edge)scm; left:%(acc_pay_dist_from_left_edge)scm;
|
||||
border-bottom: solid 1px;border-top:solid 1px; position: absolute;">
|
||||
border-bottom: solid 1px;border-top:solid 1px; width:2cm;text-align: center; position: absolute;">
|
||||
%(message_to_show)s
|
||||
</span>
|
||||
<span style="top:%(date_dist_from_top_edge)scm; left:%(date_dist_from_left_edge)scm;
|
||||
@@ -38,11 +48,11 @@ def create_or_update_cheque_print_format(template_name):
|
||||
{{ frappe.utils.formatdate(doc.reference_date) or '' }}
|
||||
</span>
|
||||
<span style="top:%(acc_no_dist_from_top_edge)scm;left:%(acc_no_dist_from_left_edge)scm;
|
||||
position: absolute;">
|
||||
position: absolute; min-width: 6cm;">
|
||||
{{ doc.account_no or '' }}
|
||||
</span>
|
||||
<span style="top:%(payer_name_from_top_edge)scm;left: %(payer_name_from_left_edge)scm;
|
||||
position: absolute;">
|
||||
position: absolute; min-width: 6cm;">
|
||||
{{doc.party_name}}
|
||||
</span>
|
||||
<span style="top:%(amt_in_words_from_top_edge)scm; left:%(amt_in_words_from_left_edge)scm;
|
||||
@@ -51,11 +61,11 @@ def create_or_update_cheque_print_format(template_name):
|
||||
{{frappe.utils.money_in_words(doc.base_paid_amount or doc.base_received_amount)}}
|
||||
</span>
|
||||
<span style="top:%(amt_in_figures_from_top_edge)scm;left: %(amt_in_figures_from_left_edge)scm;
|
||||
position: absolute;">
|
||||
position: absolute; min-width: 4cm;">
|
||||
{{doc.get_formatted("base_paid_amount") or doc.get_formatted("base_received_amount")}}
|
||||
</span>
|
||||
<span style="top:%(signatory_from_top_edge)scm;left: %(signatory_from_left_edge)scm;
|
||||
position: absolute;">
|
||||
position: absolute; min-width: 6cm;">
|
||||
{{doc.company}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -111,8 +111,8 @@ def apply_pricing_rule(args):
|
||||
|
||||
item_list = args.get("items")
|
||||
args.pop("items")
|
||||
|
||||
set_serial_nos_based_on_fifo = frappe.db.get_single_value("Stock Settings",
|
||||
|
||||
set_serial_nos_based_on_fifo = frappe.db.get_single_value("Stock Settings",
|
||||
"automatically_set_serial_nos_based_on_fifo")
|
||||
|
||||
for item in item_list:
|
||||
@@ -122,7 +122,7 @@ def apply_pricing_rule(args):
|
||||
if set_serial_nos_based_on_fifo and not args.get('is_return'):
|
||||
out.append(get_serial_no_for_item(args_copy))
|
||||
return out
|
||||
|
||||
|
||||
def get_serial_no_for_item(args):
|
||||
from erpnext.stock.get_item_details import get_serial_no
|
||||
|
||||
@@ -143,7 +143,7 @@ def get_pricing_rule_for_item(args):
|
||||
"name": args.name,
|
||||
"pricing_rule": None
|
||||
})
|
||||
|
||||
|
||||
if args.ignore_pricing_rule or not args.item_code:
|
||||
if frappe.db.exists(args.doctype, args.name) and args.get("pricing_rule"):
|
||||
item_details = remove_pricing_rule_for_item(args.get("pricing_rule"), item_details)
|
||||
@@ -180,7 +180,7 @@ def get_pricing_rule_for_item(args):
|
||||
item_details.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
|
||||
if pricing_rule.price_or_discount == "Price":
|
||||
item_details.update({
|
||||
"price_list_rate": (pricing_rule.price/flt(args.conversion_rate)) * args.conversion_factor or 1.0 \
|
||||
"price_list_rate": (pricing_rule.price/flt(args.conversion_rate)) * (args.conversion_factor or 1.0) \
|
||||
if args.conversion_rate else 0.0,
|
||||
"discount_percentage": 0.0
|
||||
})
|
||||
@@ -192,7 +192,7 @@ def get_pricing_rule_for_item(args):
|
||||
return item_details
|
||||
|
||||
def remove_pricing_rule_for_item(pricing_rule, item_details):
|
||||
pricing_rule = frappe.db.get_value('Pricing Rule', pricing_rule,
|
||||
pricing_rule = frappe.db.get_value('Pricing Rule', pricing_rule,
|
||||
['price_or_discount', 'margin_type'], as_dict=1)
|
||||
if pricing_rule and pricing_rule.price_or_discount == 'Discount Percentage':
|
||||
item_details.discount_percentage = 0.0
|
||||
@@ -209,14 +209,14 @@ def remove_pricing_rule_for_item(pricing_rule, item_details):
|
||||
def remove_pricing_rules(item_list):
|
||||
if isinstance(item_list, basestring):
|
||||
item_list = json.loads(item_list)
|
||||
|
||||
out = []
|
||||
|
||||
out = []
|
||||
for item in item_list:
|
||||
item = frappe._dict(item)
|
||||
out.append(remove_pricing_rule_for_item(item.get("pricing_rule"), item))
|
||||
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def get_pricing_rules(args):
|
||||
def _get_tree_conditions(parenttype, allow_blank=True):
|
||||
field = frappe.scrub(parenttype)
|
||||
|
||||
@@ -71,8 +71,8 @@ def set_account_currency(filters):
|
||||
if gle_currency:
|
||||
account_currency = gle_currency
|
||||
else:
|
||||
account_currency = None if filters.party_type in ["Employee", "Student", "Shareholder"] else \
|
||||
frappe.db.get_value(filters.party_type, filters.party, "default_currency")
|
||||
account_currency = (None if filters.party_type in ["Employee", "Student", "Shareholder", "Member"] else
|
||||
frappe.db.get_value(filters.party_type, filters.party, "default_currency"))
|
||||
|
||||
filters["account_currency"] = account_currency or filters.company_currency
|
||||
|
||||
|
||||
@@ -157,9 +157,10 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
|
||||
# scan description only if items are less than 50000
|
||||
description_cond = 'or tabItem.description LIKE %(txt)s'
|
||||
|
||||
return frappe.db.sql("""select tabItem.name, tabItem.item_group,
|
||||
return frappe.db.sql("""select tabItem.name,
|
||||
if(length(tabItem.item_name) > 40,
|
||||
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
|
||||
tabItem.item_group,
|
||||
if(length(tabItem.description) > 40, \
|
||||
concat(substr(tabItem.description, 1, 40), "..."), description) as decription
|
||||
from tabItem
|
||||
|
||||
@@ -558,7 +558,8 @@ def get_itemised_tax_breakup_html(doc):
|
||||
itemised_tax=itemised_tax,
|
||||
itemised_taxable_amount=itemised_taxable_amount,
|
||||
tax_accounts=tax_accounts,
|
||||
company_currency=erpnext.get_company_currency(doc.company)
|
||||
conversion_rate=doc.conversion_rate,
|
||||
currency=doc.currency
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ frappe.ui.form.on('Student Report Generation Tool', {
|
||||
frm.page.clear_indicator();
|
||||
frm.page.set_primary_action(__('Print Report Card'), () => {
|
||||
let url = "/api/method/erpnext.education.doctype.student_report_generation_tool.student_report_generation_tool.preview_report_card";
|
||||
open_url_post(url, frm.doc, true);
|
||||
open_url_post(url, {"doc": frm.doc}, true);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe, json
|
||||
from frappe.model.document import Document
|
||||
from erpnext.education.api import get_grade
|
||||
from frappe.utils.pdf import get_pdf
|
||||
@@ -16,8 +16,8 @@ class StudentReportGenerationTool(Document):
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def preview_report_card(**kwargs):
|
||||
doc = frappe._dict(**kwargs)
|
||||
def preview_report_card(doc):
|
||||
doc = frappe._dict(json.loads(doc))
|
||||
doc.students = [doc.student]
|
||||
if not (doc.student_name and doc.student_batch):
|
||||
program_enrollment = frappe.get_all("Program Enrollment", fields=["student_batch_name", "student_name"],
|
||||
@@ -33,7 +33,7 @@ def preview_report_card(**kwargs):
|
||||
course_criteria = get_courses_criteria(courses)
|
||||
|
||||
# get the assessment group as per the user selection
|
||||
if int(doc.include_all_assessment):
|
||||
if doc.include_all_assessment:
|
||||
assessment_groups = get_child_assessment_groups(doc.assessment_group)
|
||||
else:
|
||||
assessment_groups = [doc.assessment_group]
|
||||
@@ -55,7 +55,7 @@ def preview_report_card(**kwargs):
|
||||
"assessment_groups": assessment_groups,
|
||||
"course_criteria": course_criteria,
|
||||
"letterhead": letterhead.content,
|
||||
"add_letterhead": int(doc.add_letterhead) if int(doc.add_letterhead) else 0
|
||||
"add_letterhead": doc.add_letterhead if doc.add_letterhead else 0
|
||||
})
|
||||
final_template = frappe.render_template(base_template_path, {"body": html, "title": "Report Card"})
|
||||
|
||||
|
||||
@@ -20,17 +20,19 @@ class Attendance(Document):
|
||||
set_employee_name(self)
|
||||
|
||||
def check_leave_record(self):
|
||||
leave_record = frappe.db.sql("""select leave_type, half_day from `tabLeave Application`
|
||||
leave_record = frappe.db.sql("""select leave_type, half_day, half_day_date from `tabLeave Application`
|
||||
where employee = %s and %s between from_date and to_date and status = 'Approved'
|
||||
and docstatus = 1""", (self.employee, self.attendance_date), as_dict=True)
|
||||
if leave_record:
|
||||
if leave_record[0].half_day:
|
||||
self.status = 'Half Day'
|
||||
frappe.msgprint(_("Employee {0} on Half day on {1}").format(self.employee, self.attendance_date))
|
||||
else:
|
||||
self.status = 'On Leave'
|
||||
self.leave_type = leave_record[0].leave_type
|
||||
frappe.msgprint(_("Employee {0} on Leave on {1}").format(self.employee, self.attendance_date))
|
||||
for d in leave_record:
|
||||
if d.half_day_date == getdate(self.attendance_date):
|
||||
self.status = 'Half Day'
|
||||
frappe.msgprint(_("Employee {0} on Half day on {1}").format(self.employee, self.attendance_date))
|
||||
else:
|
||||
self.status = 'On Leave'
|
||||
self.leave_type = d.leave_type
|
||||
frappe.msgprint(_("Employee {0} on Leave on {1}").format(self.employee, self.attendance_date))
|
||||
|
||||
if self.status == "On Leave" and not leave_record:
|
||||
frappe.throw(_("No leave record found for employee {0} for {1}").format(self.employee, self.attendance_date))
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ frappe.ui.form.on("Leave Application", {
|
||||
|
||||
employee: function(frm) {
|
||||
frm.trigger("get_leave_balance");
|
||||
frm.trigger("set_leave_approver");
|
||||
},
|
||||
|
||||
leave_type: function(frm) {
|
||||
@@ -95,6 +96,9 @@ frappe.ui.form.on("Leave Application", {
|
||||
if (!r.exc && r.message) {
|
||||
frm.set_value('leave_balance', r.message);
|
||||
}
|
||||
else {
|
||||
frm.set_value('leave_balance', "0");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -122,4 +126,21 @@ frappe.ui.form.on("Leave Application", {
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
set_leave_approver: function(frm) {
|
||||
if(frm.doc.employee) {
|
||||
// server call is done to include holidays in leave days calculations
|
||||
return frappe.call({
|
||||
method: 'erpnext.hr.doctype.leave_application.leave_application.get_leave_approver_data',
|
||||
args: {
|
||||
"employee": frm.doc.employee,
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r && r.message) {
|
||||
frm.set_value('leave_approver', r.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,12 +5,12 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \
|
||||
comma_or, get_fullname
|
||||
comma_or, get_fullname, nowdate
|
||||
from erpnext.hr.utils import set_employee_name
|
||||
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
|
||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||
from erpnext.hr.doctype.employee_leave_approver.employee_leave_approver import get_approver_list
|
||||
|
||||
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange
|
||||
|
||||
class LeaveDayBlockedError(frappe.ValidationError): pass
|
||||
class OverlapError(frappe.ValidationError): pass
|
||||
@@ -52,6 +52,7 @@ class LeaveApplication(Document):
|
||||
frappe.throw(_("Only Leave Applications with status 'Approved' and 'Rejected' can be submitted"))
|
||||
|
||||
self.validate_back_dated_application()
|
||||
self.update_attendance()
|
||||
|
||||
# notify leave applier about approval
|
||||
self.notify_employee(self.status)
|
||||
@@ -100,6 +101,43 @@ class LeaveApplication(Document):
|
||||
frappe.throw(_("Leave cannot be applied/cancelled before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}")
|
||||
.format(formatdate(future_allocation[0].from_date), future_allocation[0].name))
|
||||
|
||||
def update_attendance(self):
|
||||
if self.status == "Approved":
|
||||
attendance = frappe.db.sql("""select name from `tabAttendance` where employee = %s\
|
||||
and (attendance_date between %s and %s) and docstatus < 2""",(self.employee, self.from_date, self.to_date), as_dict=1)
|
||||
|
||||
if attendance:
|
||||
for d in attendance:
|
||||
doc = frappe.get_doc("Attendance", d.name)
|
||||
if getdate(self.half_day_date) == doc.attendance_date:
|
||||
status = "Half Day"
|
||||
else:
|
||||
status = "On Leave"
|
||||
frappe.db.sql("""update `tabAttendance` set status = %s, leave_type = %s\
|
||||
where name = %s""",(status, self.leave_type, d.name))
|
||||
|
||||
elif self.to_date <= nowdate():
|
||||
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
|
||||
date = dt.strftime("%Y-%m-%d")
|
||||
if not date == self.half_day_date:
|
||||
doc = frappe.new_doc("Attendance")
|
||||
doc.employee = self.employee
|
||||
doc.attendance_date = date
|
||||
doc.company = self.company
|
||||
doc.status = "On Leave"
|
||||
doc.leave_type = self.leave_type
|
||||
doc.insert(ignore_permissions=True)
|
||||
doc.submit()
|
||||
else:
|
||||
doc = frappe.new_doc("Attendance")
|
||||
doc.employee = self.employee
|
||||
doc.attendance_date = date
|
||||
doc.company = self.company
|
||||
doc.status = "Half Day"
|
||||
doc.leave_type = self.leave_type
|
||||
doc.insert(ignore_permissions=True)
|
||||
doc.submit()
|
||||
|
||||
def validate_salary_processed_days(self):
|
||||
if not frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
|
||||
return
|
||||
@@ -436,30 +474,17 @@ def add_department_leaves(events, start, end, employee, company):
|
||||
and company=%s""", (department, company))
|
||||
|
||||
match_conditions = "and employee in (\"%s\")" % '", "'.join(department_employees)
|
||||
add_leaves(events, start, end, filter_conditions=match_conditions)
|
||||
|
||||
def add_leaves(events, start, end, filter_conditions=None):
|
||||
conditions = []
|
||||
|
||||
if filter_conditions:
|
||||
conditions.append(filter_conditions)
|
||||
|
||||
if not cint(frappe.db.get_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar")):
|
||||
from frappe.desk.reportview import build_match_conditions
|
||||
match_conditions = build_match_conditions("Leave Application")
|
||||
|
||||
if match_conditions:
|
||||
conditions.append(match_conditions)
|
||||
add_leaves(events, start, end, match_conditions=match_conditions)
|
||||
|
||||
def add_leaves(events, start, end, match_conditions=None):
|
||||
query = """select name, from_date, to_date, employee_name, half_day,
|
||||
status, employee, docstatus
|
||||
from `tabLeave Application` where
|
||||
from_date <= %(end)s and to_date >= %(start)s <= to_date
|
||||
and docstatus < 2
|
||||
and status!="Rejected" """
|
||||
|
||||
if conditions:
|
||||
query += ' and '.join(conditions)
|
||||
if match_conditions:
|
||||
query += match_conditions
|
||||
|
||||
for d in frappe.db.sql(query, {"start":start, "end": end}, as_dict=True):
|
||||
e = {
|
||||
@@ -507,3 +532,8 @@ def add_holidays(events, start, end, employee, company):
|
||||
"title": _("Holiday") + ": " + cstr(holiday.description),
|
||||
"name": holiday.name
|
||||
})
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_leave_approver_data(employee):
|
||||
return frappe.db.get_value("Employee Leave Approver",
|
||||
{'parent': employee}, 'leave_approver')
|
||||
|
||||
@@ -22,6 +22,10 @@ def execute(filters=None):
|
||||
holiday_map = get_holiday(holiday_list, filters["month"])
|
||||
|
||||
data = []
|
||||
leave_types = frappe.db.sql("""select name from `tabLeave Type`""", as_list=True)
|
||||
leave_list = [d[0] for d in leave_types]
|
||||
columns.extend(leave_list)
|
||||
|
||||
for emp in sorted(att_map):
|
||||
emp_det = emp_map.get(emp)
|
||||
if not emp_det:
|
||||
@@ -49,10 +53,35 @@ def execute(filters=None):
|
||||
elif status == "Half Day":
|
||||
total_p += 0.5
|
||||
total_a += 0.5
|
||||
total_l += 0.5
|
||||
|
||||
row += [total_p, total_l, total_a]
|
||||
data.append(row)
|
||||
|
||||
if not filters.get("employee"):
|
||||
filters.update({"employee": emp})
|
||||
conditions += " and employee = %(employee)s"
|
||||
elif not filters.get("employee") == emp:
|
||||
filters.update({"employee": emp})
|
||||
|
||||
leave_details = frappe.db.sql("""select leave_type, status, count(*) as count from `tabAttendance`\
|
||||
where leave_type is not NULL %s group by leave_type, status""" % conditions, filters, as_dict=1)
|
||||
|
||||
leaves = {}
|
||||
for d in leave_details:
|
||||
if d.status == "Half Day":
|
||||
d.count = d.count * 0.5
|
||||
if d.leave_type in leaves:
|
||||
leaves[d.leave_type] += d.count
|
||||
else:
|
||||
leaves[d.leave_type] = d.count
|
||||
|
||||
for d in leave_list:
|
||||
if d in leaves:
|
||||
row.append(leaves[d])
|
||||
else:
|
||||
row.append("0.0")
|
||||
|
||||
data.append(row)
|
||||
return columns, data
|
||||
|
||||
def get_columns(filters):
|
||||
|
||||
@@ -64,8 +64,7 @@ erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({
|
||||
|
||||
var chart_data = this.get_chart_data ? this.get_chart_data() : null;
|
||||
|
||||
this.chart = new Chart({
|
||||
parent: ".chart",
|
||||
this.chart = new frappeChart.Chart(".chart", {
|
||||
data: chart_data,
|
||||
type: 'line'
|
||||
});
|
||||
|
||||
@@ -9,4 +9,13 @@ def execute():
|
||||
|
||||
ss = frappe.get_doc("Stock Settings")
|
||||
ss.set_qty_in_transactions_based_on_serial_no_input = 1
|
||||
|
||||
if ss.default_warehouse \
|
||||
and not frappe.db.exists("Warehouse", ss.default_warehouse):
|
||||
ss.default_warehouse = None
|
||||
|
||||
if ss.stock_uom and not frappe.db.exists("UOM", ss.stock_uom):
|
||||
ss.stock_uom = None
|
||||
|
||||
ss.flags.ignore_mandatory = True
|
||||
ss.save()
|
||||
@@ -75,7 +75,7 @@ class Project(Document):
|
||||
sum = 0
|
||||
for task in self.tasks:
|
||||
if task.task_weight > 0:
|
||||
sum = sum + task.task_weight
|
||||
sum = flt(sum + task.task_weight, task.precision('task_weight'))
|
||||
if sum > 0 and sum != 1:
|
||||
frappe.throw(_("Total of all task weights should be 1. Please adjust weights of all Project tasks accordingly"))
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
|
||||
if(
|
||||
this.frm.docstatus < 2
|
||||
this.frm.docstatus < 2
|
||||
&& this.frm.fields_dict["payment_terms_template"]
|
||||
&& this.frm.fields_dict["payment_schedule"]
|
||||
&& this.frm.doc.payment_terms_template
|
||||
@@ -1094,6 +1094,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
me.in_apply_price_list = false;
|
||||
}
|
||||
}
|
||||
}).always(() => {
|
||||
me.in_apply_price_list = false;
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class Gstr1Report(object):
|
||||
posting_date,
|
||||
base_grand_total,
|
||||
base_rounded_total,
|
||||
customer_gstin,
|
||||
COALESCE(NULLIF(customer_gstin,''), NULLIF(billing_address_gstin, '')) as customer_gstin,
|
||||
place_of_supply,
|
||||
ecommerce_gstin,
|
||||
reverse_charge,
|
||||
|
||||
@@ -316,7 +316,7 @@ def make_address(args, is_primary_address=1):
|
||||
return address
|
||||
|
||||
def get_customer_primary_contact(doctype, txt, searchfield, start, page_len, filters):
|
||||
customer = frappe.db.escape(filters.get('customer'))
|
||||
customer = filters.get('customer')
|
||||
return frappe.db.sql("""
|
||||
select `tabContact`.name from `tabContact`, `tabDynamic Link`
|
||||
where `tabContact`.name = `tabDynamic Link`.parent and `tabDynamic Link`.link_name = %(customer)s
|
||||
|
||||
@@ -91,17 +91,22 @@ def get_achieved_details(filters, sales_person, all_sales_persons, target_item_g
|
||||
start_date, end_date = get_fiscal_year(fiscal_year = filters["fiscal_year"])[1:]
|
||||
|
||||
item_details = frappe.db.sql("""
|
||||
select
|
||||
sum(soi.stock_qty * (st.allocated_percentage/100)) as qty,
|
||||
sum(soi.base_net_amount * (st.allocated_percentage/100)) as amount,
|
||||
st.sales_person, MONTHNAME(so.transaction_date) as month_name
|
||||
SELECT st.sales_person, MONTHNAME(so.transaction_date) as month_name,
|
||||
CASE
|
||||
WHEN so.status = "Closed" THEN sum(soi.delivered_qty * soi.conversion_factor * (st.allocated_percentage/100))
|
||||
ELSE sum(soi.stock_qty * (st.allocated_percentage/100))
|
||||
END as qty,
|
||||
CASE
|
||||
WHEN so.status = "Closed" THEN sum(soi.delivered_qty * soi.conversion_factor * soi.base_net_rate * (st.allocated_percentage/100))
|
||||
ELSE soi.base_net_amount * (st.allocated_percentage/100))
|
||||
END as amount
|
||||
from
|
||||
`tabSales Order Item` soi, `tabSales Order` so, `tabSales Team` st
|
||||
where
|
||||
soi.parent=so.name and so.docstatus=1 and st.parent=so.name
|
||||
and so.transaction_date>=%s and so.transaction_date<=%s
|
||||
and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name=st.sales_person)
|
||||
and exists(select name from `tabItem Group` where lft >= %s and rgt <= %s and name=soi.item_group)
|
||||
and exists(SELECT name from `tabSales Person` where lft >= %s and rgt <= %s and name=st.sales_person)
|
||||
and exists(SELECT name from `tabItem Group` where lft >= %s and rgt <= %s and name=soi.item_group)
|
||||
group by
|
||||
sales_person, month_name
|
||||
""",
|
||||
|
||||
@@ -15,11 +15,12 @@ def execute(filters=None):
|
||||
data = []
|
||||
|
||||
for d in entries:
|
||||
data.append([
|
||||
d.name, d.customer, d.territory, d.posting_date, d.item_code,
|
||||
item_details.get(d.item_code, {}).get("item_group"), item_details.get(d.item_code, {}).get("brand"),
|
||||
d.stock_qty, d.base_net_amount, d.sales_person, d.allocated_percentage, d.contribution_amt
|
||||
])
|
||||
if d.stock_qty > 0:
|
||||
data.append([
|
||||
d.name, d.customer, d.territory, d.posting_date, d.item_code,
|
||||
item_details.get(d.item_code, {}).get("item_group"), item_details.get(d.item_code, {}).get("brand"),
|
||||
d.stock_qty, d.base_net_amount, d.sales_person, d.allocated_percentage, d.contribution_amt
|
||||
])
|
||||
|
||||
if data:
|
||||
total_row = [""]*len(data[0])
|
||||
@@ -40,18 +41,34 @@ def get_columns(filters):
|
||||
|
||||
def get_entries(filters):
|
||||
date_field = filters["doc_type"] == "Sales Order" and "transaction_date" or "posting_date"
|
||||
if filters["doc_type"] == "Sales Order":
|
||||
qty_field = "delivered_qty"
|
||||
else:
|
||||
qty_field = "qty"
|
||||
conditions, values = get_conditions(filters, date_field)
|
||||
|
||||
entries = frappe.db.sql("""
|
||||
select
|
||||
dt.name, dt.customer, dt.territory, dt.%s as posting_date, dt_item.item_code,
|
||||
dt_item.stock_qty, dt_item.base_net_amount, st.sales_person, st.allocated_percentage,
|
||||
dt_item.base_net_amount*st.allocated_percentage/100 as contribution_amt
|
||||
st.sales_person, st.allocated_percentage,
|
||||
CASE
|
||||
WHEN dt.status = "Closed" THEN dt_item.%s * dt_item.conversion_factor
|
||||
ELSE dt_item.stock_qty
|
||||
END as stock_qty,
|
||||
CASE
|
||||
WHEN dt.status = "Closed" THEN (dt_item.base_net_rate * dt_item.%s * dt_item.conversion_factor)
|
||||
ELSE dt_item.base_net_amount
|
||||
END as base_net_amount,
|
||||
CASE
|
||||
WHEN dt.status = "Closed" THEN ((dt_item.base_net_rate * dt_item.%s * dt_item.conversion_factor) * st.allocated_percentage/100)
|
||||
ELSE dt_item.base_net_amount * st.allocated_percentage/100
|
||||
END as contribution_amt
|
||||
from
|
||||
`tab%s` dt, `tab%s Item` dt_item, `tabSales Team` st
|
||||
where
|
||||
st.parent = dt.name and dt.name = dt_item.parent and st.parenttype = %s
|
||||
and dt.docstatus = 1 %s order by st.sales_person, dt.name desc
|
||||
""" %(date_field, filters["doc_type"], filters["doc_type"], '%s', conditions),
|
||||
""" %(date_field, qty_field, qty_field, qty_field, filters["doc_type"], filters["doc_type"], '%s', conditions),
|
||||
tuple([filters["doc_type"]] + values), as_dict=1)
|
||||
|
||||
return entries
|
||||
|
||||
@@ -501,7 +501,7 @@ class Item(WebsiteGenerator):
|
||||
|
||||
def update_item_price(self):
|
||||
frappe.db.sql("""update `tabItem Price` set item_name=%s,
|
||||
item_description=%s, modified=NOW() where item_code=%s""",
|
||||
item_description=%s where item_code=%s""",
|
||||
(self.item_name, self.description, self.name))
|
||||
|
||||
def on_trash(self):
|
||||
|
||||
@@ -417,6 +417,7 @@ def raise_production_orders(material_request):
|
||||
prod_order.material_request_item = d.name
|
||||
prod_order.planned_start_date = mr.transaction_date
|
||||
prod_order.company = mr.company
|
||||
prod_order.set_production_order_operations()
|
||||
prod_order.save()
|
||||
production_orders.append(prod_order.name)
|
||||
else:
|
||||
|
||||
@@ -7,7 +7,7 @@ def get_data():
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Related'),
|
||||
'items': ['Request for Quotation', 'Supplier Quotation', 'Purchase Order']
|
||||
'items': ['Request for Quotation', 'Supplier Quotation', 'Purchase Order', "Stock Entry"]
|
||||
},
|
||||
{
|
||||
'label': _('Manufacturing'),
|
||||
|
||||
@@ -39,6 +39,8 @@ frappe.ui.form.on("Warehouse", {
|
||||
|
||||
frm.toggle_enable(['is_group', 'company'], false);
|
||||
|
||||
frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Warehouse'};
|
||||
|
||||
frm.fields_dict['parent_warehouse'].get_query = function(doc) {
|
||||
return {
|
||||
filters: {
|
||||
|
||||
@@ -14,6 +14,19 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = {
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.datetime.get_today()
|
||||
},
|
||||
{
|
||||
"fieldname":"item_group",
|
||||
"label": __("Item Group"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Item Group",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"brand",
|
||||
"label": __("Brand"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Brand"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,7 +10,7 @@ def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
float_preceision = frappe.db.get_default("float_preceision")
|
||||
|
||||
condition =get_condition(filters)
|
||||
condition = get_condition(filters)
|
||||
|
||||
avg_daily_outgoing = 0
|
||||
diff = ((getdate(filters.get("to_date")) - getdate(filters.get("from_date"))).days)+1
|
||||
@@ -18,7 +18,7 @@ def execute(filters=None):
|
||||
frappe.throw(_("'From Date' must be after 'To Date'"))
|
||||
|
||||
columns = get_columns()
|
||||
items = get_item_info()
|
||||
items = get_item_info(filters)
|
||||
consumed_item_map = get_consumed_items(condition)
|
||||
delivered_item_map = get_delivered_items(condition)
|
||||
|
||||
@@ -28,23 +28,31 @@ def execute(filters=None):
|
||||
avg_daily_outgoing = flt(total_outgoing / diff, float_preceision)
|
||||
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.safety_stock)
|
||||
|
||||
data.append([item.name, item.item_name, item.description, item.safety_stock, item.lead_time_days,
|
||||
consumed_item_map.get(item.name, 0), delivered_item_map.get(item.name,0), total_outgoing,
|
||||
avg_daily_outgoing, reorder_level])
|
||||
data.append([item.name, item.item_name, item.item_group, item.brand, item.description,
|
||||
item.safety_stock, item.lead_time_days, consumed_item_map.get(item.name, 0),
|
||||
delivered_item_map.get(item.name,0), total_outgoing, avg_daily_outgoing, reorder_level])
|
||||
|
||||
return columns , data
|
||||
|
||||
def get_columns():
|
||||
return[
|
||||
_("Item") + ":Link/Item:120", _("Item Name") + ":Data:120", _("Description") + "::160",
|
||||
_("Item") + ":Link/Item:120", _("Item Name") + ":Data:120", _("Item Group") + ":Link/Item Group:100",
|
||||
_("Brand") + ":Link/Brand:100", _("Description") + "::160",
|
||||
_("Safety Stock") + ":Float:160", _("Lead Time Days") + ":Float:120", _("Consumed") + ":Float:120",
|
||||
_("Delivered") + ":Float:120", _("Total Outgoing") + ":Float:120", _("Avg Daily Outgoing") + ":Float:160",
|
||||
_("Reorder Level") + ":Float:120"
|
||||
]
|
||||
|
||||
def get_item_info():
|
||||
return frappe.db.sql("""select name, item_name, description, safety_stock,
|
||||
lead_time_days from tabItem""", as_dict=1)
|
||||
def get_item_info(filters):
|
||||
from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition
|
||||
conditions = [get_item_group_condition(filters.get("item_group"))]
|
||||
if filters.get("brand"):
|
||||
conditions.append("item.brand=%(brand)s")
|
||||
|
||||
return frappe.db.sql("""select name, item_name, description, brand, item_group,
|
||||
safety_stock, lead_time_days from `tabItem` item where {}"""
|
||||
.format(" and ".join(conditions)), filters, as_dict=1)
|
||||
|
||||
|
||||
def get_consumed_items(condition):
|
||||
cn_items = frappe.db.sql("""select se_item.item_code,
|
||||
|
||||
@@ -926,6 +926,37 @@
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "via_customer_portal",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Via Customer Portal",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
@@ -939,7 +970,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-04-13 13:03:14.748090",
|
||||
"modified": "2018-05-07 05:53:20.684275",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Support",
|
||||
"name": "Issue",
|
||||
|
||||
@@ -17,6 +17,8 @@ class Issue(Document):
|
||||
return "{0}: {1}".format(_(self.status), self.subject)
|
||||
|
||||
def validate(self):
|
||||
if (self.get("__islocal") and self.via_customer_portal):
|
||||
self.flags.create_communication = True
|
||||
if not self.raised_by:
|
||||
self.raised_by = frappe.session.user
|
||||
self.update_status()
|
||||
@@ -26,6 +28,12 @@ class Issue(Document):
|
||||
from frappe.desk.form.assign_to import clear
|
||||
clear(self.doctype, self.name)
|
||||
|
||||
def on_update(self):
|
||||
# create the communication email and remove the description
|
||||
if (self.flags.create_communication and self.via_customer_portal):
|
||||
self.create_communication()
|
||||
self.flags.communication_created = None
|
||||
|
||||
def set_lead_contact(self, email_id):
|
||||
import email.utils
|
||||
email_id = email.utils.parseaddr(email_id)[1]
|
||||
@@ -53,6 +61,26 @@ class Issue(Document):
|
||||
# if no date, it should be set as None and not a blank string "", as per mysql strict config
|
||||
self.resolution_date = None
|
||||
|
||||
def create_communication(self):
|
||||
communication = frappe.new_doc("Communication")
|
||||
communication.update({
|
||||
"communication_type": "Communication",
|
||||
"communication_medium": "Email",
|
||||
"sent_or_received": "Received",
|
||||
"email_status": "Open",
|
||||
"subject": self.subject,
|
||||
"sender": self.raised_by,
|
||||
"content": self.description,
|
||||
"status": "Linked",
|
||||
"reference_doctype": "Issue",
|
||||
"reference_name": self.name
|
||||
})
|
||||
communication.ignore_permissions = True
|
||||
communication.ignore_mandatory = True
|
||||
communication.save()
|
||||
|
||||
self.db_set("description", "")
|
||||
|
||||
def get_list_context(context=None):
|
||||
return {
|
||||
"title": _("Issues"),
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"is_standard": 1,
|
||||
"login_required": 1,
|
||||
"max_attachment_size": 0,
|
||||
"modified": "2017-07-25 22:49:10.762704",
|
||||
"modified": "2018-05-07 05:54:22.213127",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Support",
|
||||
"name": "issues",
|
||||
@@ -83,6 +83,17 @@
|
||||
"max_value": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "via_customer_portal",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Via Customer Portal",
|
||||
"max_length": 0,
|
||||
"max_value": 0,
|
||||
"read_only": 1,
|
||||
"reqd": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -4,4 +4,5 @@ import frappe
|
||||
|
||||
def get_context(context):
|
||||
# do your magic here
|
||||
pass
|
||||
if context.doc:
|
||||
context.read_only = 1
|
||||
@@ -16,16 +16,16 @@
|
||||
<tr>
|
||||
<td>{{ item }}</td>
|
||||
<td class='text-right'>
|
||||
{{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, company_currency) }}
|
||||
{{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, currency) }}
|
||||
</td>
|
||||
{% for tax_account in tax_accounts %}
|
||||
{% set tax_details = taxes.get(tax_account) %}
|
||||
{% if tax_details %}
|
||||
<td class='text-right'>
|
||||
{% if tax_details.tax_rate or not tax_details.tax_amount %}
|
||||
({{ tax_details.tax_rate }}%)
|
||||
({{ tax_details.tax_rate }}%)
|
||||
{% endif %}
|
||||
{{ frappe.utils.fmt_money(tax_details.tax_amount, None, company_currency) }}
|
||||
{{ frappe.utils.fmt_money(tax_details.tax_amount / conversion_rate, None, currency) }}
|
||||
</td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
|
||||
@@ -146,7 +146,6 @@ frappe.Leaderboard = Class.extend({
|
||||
|
||||
me.$graph_area.show().empty();
|
||||
let args = {
|
||||
parent: '.leaderboard-graph',
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
@@ -160,7 +159,7 @@ frappe.Leaderboard = Class.extend({
|
||||
type: 'bar',
|
||||
height: 140
|
||||
};
|
||||
new Chart(args);
|
||||
new frappeChart.Chart('.leaderboard-graph', args);
|
||||
|
||||
notify(me, r, $container);
|
||||
}
|
||||
@@ -280,7 +279,7 @@ frappe.Leaderboard = Class.extend({
|
||||
fields.map(col => {
|
||||
let val = item[col];
|
||||
if(col=="name") {
|
||||
var formatted_value = `<a class="grey list-id ellipsis"
|
||||
var formatted_value = `<a class="grey list-id ellipsis"
|
||||
href="#Form/${me.options.selected_doctype}/${item["name"]}"> ${val} </a>`
|
||||
} else {
|
||||
var formatted_value = `<span class="text-muted ellipsis">
|
||||
|
||||
Reference in New Issue
Block a user