Merge branch 'develop' into update-items-permission-fix
This commit is contained in:
commit
7dd92f15fa
@ -14,6 +14,9 @@ frappe.treeview_settings["Account"] = {
|
||||
on_change: function() {
|
||||
var me = frappe.treeview_settings['Account'].treeview;
|
||||
var company = me.page.fields_dict.company.get_value();
|
||||
if (!company) {
|
||||
frappe.throw(__("Please set a Company"));
|
||||
}
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.account.account.get_root_company",
|
||||
args: {
|
||||
|
@ -319,7 +319,7 @@ class PaymentEntry(AccountsController):
|
||||
invoice_payment_amount_map.setdefault(key, 0.0)
|
||||
invoice_payment_amount_map[key] += reference.allocated_amount
|
||||
|
||||
if not invoice_paid_amount_map.get(reference.reference_name):
|
||||
if not invoice_paid_amount_map.get(key):
|
||||
payment_schedule = frappe.get_all('Payment Schedule', filters={'parent': reference.reference_name},
|
||||
fields=['paid_amount', 'payment_amount', 'payment_term'])
|
||||
for term in payment_schedule:
|
||||
@ -332,12 +332,14 @@ class PaymentEntry(AccountsController):
|
||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` - %s
|
||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
||||
else:
|
||||
outstanding = invoice_paid_amount_map.get(key)['outstanding']
|
||||
outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding'))
|
||||
|
||||
if amount > outstanding:
|
||||
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
|
||||
|
||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` + %s
|
||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
||||
if amount and outstanding:
|
||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` + %s
|
||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
||||
|
||||
def set_status(self):
|
||||
if self.docstatus == 2:
|
||||
@ -1091,17 +1093,20 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
|
||||
references = []
|
||||
for payment_term in payment_schedule:
|
||||
references.append({
|
||||
'reference_doctype': dt,
|
||||
'reference_name': dn,
|
||||
'bill_no': doc.get('bill_no'),
|
||||
'due_date': doc.get('due_date'),
|
||||
'total_amount': grand_total,
|
||||
'outstanding_amount': outstanding_amount,
|
||||
'payment_term': payment_term.payment_term,
|
||||
'allocated_amount': flt(payment_term.payment_amount - payment_term.paid_amount,
|
||||
payment_term_outstanding = flt(payment_term.payment_amount - payment_term.paid_amount,
|
||||
payment_term.precision('payment_amount'))
|
||||
})
|
||||
|
||||
if payment_term_outstanding:
|
||||
references.append({
|
||||
'reference_doctype': dt,
|
||||
'reference_name': dn,
|
||||
'bill_no': doc.get('bill_no'),
|
||||
'due_date': doc.get('due_date'),
|
||||
'total_amount': grand_total,
|
||||
'outstanding_amount': outstanding_amount,
|
||||
'payment_term': payment_term.payment_term,
|
||||
'allocated_amount': payment_term_outstanding
|
||||
})
|
||||
|
||||
return references
|
||||
|
||||
|
@ -349,9 +349,10 @@
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"in_create": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-08 10:23:02.815237",
|
||||
"modified": "2020-05-29 17:38:49.392713",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Request",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -582,14 +582,14 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def validate_item_code(self):
|
||||
for d in self.get('items'):
|
||||
if not d.item_code:
|
||||
if not d.item_code and self.is_opening == "No":
|
||||
msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True)
|
||||
|
||||
def validate_warehouse(self):
|
||||
super(SalesInvoice, self).validate_warehouse()
|
||||
|
||||
for d in self.get_item_list():
|
||||
if not d.warehouse and frappe.get_cached_value("Item", d.item_code, "is_stock_item"):
|
||||
if not d.warehouse and d.item_code and frappe.get_cached_value("Item", d.item_code, "is_stock_item"):
|
||||
frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code))
|
||||
|
||||
def validate_delivery_note(self):
|
||||
@ -1450,11 +1450,17 @@ def get_inter_company_details(doc, doctype):
|
||||
parties = frappe.db.get_all("Supplier", fields=["name"], filters={"disabled": 0, "is_internal_supplier": 1, "represents_company": doc.company})
|
||||
company = frappe.get_cached_value("Customer", doc.customer, "represents_company")
|
||||
|
||||
if not parties:
|
||||
frappe.throw(_('No Supplier found for Inter Company Transactions which represents company {0}').format(frappe.bold(doc.company)))
|
||||
|
||||
party = get_internal_party(parties, "Supplier", doc)
|
||||
else:
|
||||
parties = frappe.db.get_all("Customer", fields=["name"], filters={"disabled": 0, "is_internal_customer": 1, "represents_company": doc.company})
|
||||
company = frappe.get_cached_value("Supplier", doc.supplier, "represents_company")
|
||||
|
||||
if not parties:
|
||||
frappe.throw(_('No Customer found for Inter Company Transactions which represents company {0}').format(frappe.bold(doc.company)))
|
||||
|
||||
party = get_internal_party(parties, "Customer", doc)
|
||||
|
||||
return {
|
||||
|
@ -56,9 +56,8 @@ def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_
|
||||
to_date = add_months(start_date, months_to_add)
|
||||
start_date = to_date
|
||||
|
||||
if to_date == get_first_day(to_date):
|
||||
# if to_date is the first day, get the last day of previous month
|
||||
to_date = add_days(to_date, -1)
|
||||
# Subtract one day from to_date, as it may be first day in next fiscal year or month
|
||||
to_date = add_days(to_date, -1)
|
||||
|
||||
if to_date <= year_end_date:
|
||||
# the normal case
|
||||
@ -406,6 +405,7 @@ def set_gl_entries_by_account(
|
||||
FROM `tabDistributed Cost Center`
|
||||
WHERE cost_center IN %(cost_center)s
|
||||
AND parent NOT IN %(cost_center)s
|
||||
AND is_cancelled = 0
|
||||
GROUP BY parent
|
||||
) as DCC_allocation
|
||||
WHERE company=%(company)s
|
||||
@ -418,6 +418,7 @@ def set_gl_entries_by_account(
|
||||
where company=%(company)s
|
||||
{additional_conditions}
|
||||
and posting_date <= %(to_date)s
|
||||
and is_cancelled = 0
|
||||
{distributed_cost_center_query}
|
||||
order by account, posting_date""".format(
|
||||
additional_conditions=additional_conditions,
|
||||
|
@ -265,13 +265,6 @@ def get_columns(additional_table_columns, filters):
|
||||
'fieldtype': 'Currency',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'fieldname': 'currency',
|
||||
'label': _('Currency'),
|
||||
'fieldtype': 'Currency',
|
||||
'width': 80,
|
||||
'hidden': 1
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -223,7 +223,7 @@ def get_columns(additional_table_columns, filters):
|
||||
}
|
||||
]
|
||||
|
||||
if filters.get('group_by') != 'Terriotory':
|
||||
if filters.get('group_by') != 'Territory':
|
||||
columns.extend([
|
||||
{
|
||||
'label': _("Territory"),
|
||||
@ -304,13 +304,6 @@ def get_columns(additional_table_columns, filters):
|
||||
'fieldtype': 'Currency',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'fieldname': 'currency',
|
||||
'label': _('Currency'),
|
||||
'fieldtype': 'Currency',
|
||||
'width': 80,
|
||||
'hidden': 1
|
||||
}
|
||||
]
|
||||
|
||||
@ -536,6 +529,13 @@ def get_tax_accounts(item_list, columns, company_currency,
|
||||
'fieldtype': 'Currency',
|
||||
'options': 'currency',
|
||||
'width': 100
|
||||
},
|
||||
{
|
||||
'fieldname': 'currency',
|
||||
'label': _('Currency'),
|
||||
'fieldtype': 'Currency',
|
||||
'width': 80,
|
||||
'hidden': 1
|
||||
}
|
||||
]
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,8 @@ class QualityInspectionNotSubmittedError(frappe.ValidationError): pass
|
||||
class StockController(AccountsController):
|
||||
def validate(self):
|
||||
super(StockController, self).validate()
|
||||
self.validate_inspection()
|
||||
if not self.get('is_return'):
|
||||
self.validate_inspection()
|
||||
self.validate_serialized_batch()
|
||||
self.validate_customer_provided_item()
|
||||
|
||||
|
@ -3,11 +3,7 @@ from frappe import _
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
'fieldname': 'prevdoc_docname',
|
||||
'non_standard_fieldnames': {
|
||||
'Supplier Quotation': 'opportunity',
|
||||
'Quotation': 'opportunity'
|
||||
},
|
||||
'fieldname': 'opportunity',
|
||||
'transactions': [
|
||||
{
|
||||
'items': ['Quotation', 'Supplier Quotation']
|
||||
|
@ -30,24 +30,32 @@
|
||||
"fieldname": "text",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Tweet",
|
||||
"mandatory_depends_on": "eval:doc.twitter ==1"
|
||||
"mandatory_depends_on": "eval:doc.twitter ==1",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Attach Image",
|
||||
"label": "Image"
|
||||
"label": "Image",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "twitter",
|
||||
"fieldtype": "Check",
|
||||
"label": "Twitter"
|
||||
"label": "Twitter",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "linkedin",
|
||||
"fieldtype": "Check",
|
||||
"label": "LinkedIn"
|
||||
"label": "LinkedIn",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
@ -56,13 +64,17 @@
|
||||
"no_copy": 1,
|
||||
"options": "Social Media Post",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.twitter ==1",
|
||||
"fieldname": "content",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Twitter"
|
||||
"label": "Twitter",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
@ -70,7 +82,9 @@
|
||||
"fieldtype": "Select",
|
||||
"label": "Post Status",
|
||||
"options": "\nScheduled\nPosted\nError",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
@ -78,7 +92,9 @@
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Twitter Post Id",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
@ -86,68 +102,89 @@
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "LinkedIn Post Id",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "campaign_name",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Campaign",
|
||||
"options": "Campaign"
|
||||
"options": "Campaign",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break",
|
||||
"label": "Share On"
|
||||
"label": "Share On",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_14",
|
||||
"fieldtype": "Column Break"
|
||||
"fieldtype": "Column Break",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "tweet_preview",
|
||||
"fieldtype": "HTML"
|
||||
"fieldtype": "HTML",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"depends_on": "eval:doc.linkedin==1",
|
||||
"fieldname": "linkedin_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "LinkedIn"
|
||||
"label": "LinkedIn",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "attachments_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Attachments"
|
||||
"label": "Attachments",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "linkedin_post",
|
||||
"fieldtype": "Text",
|
||||
"label": "Post",
|
||||
"mandatory_depends_on": "eval:doc.linkedin ==1"
|
||||
"mandatory_depends_on": "eval:doc.linkedin ==1",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_15",
|
||||
"fieldtype": "Column Break"
|
||||
"fieldtype": "Column Break",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "scheduled_time",
|
||||
"fieldtype": "Datetime",
|
||||
"label": "Scheduled Time",
|
||||
"read_only_depends_on": "eval:doc.post_status == \"Posted\""
|
||||
"read_only_depends_on": "eval:doc.post_status == \"Posted\"",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-21 15:10:04.953713",
|
||||
"modified": "2020-06-14 10:31:33.961381",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Social Media Post",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
@ -157,6 +194,35 @@
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
|
@ -19,11 +19,15 @@
|
||||
"attendance_date",
|
||||
"company",
|
||||
"department",
|
||||
"shift",
|
||||
"attendance_request",
|
||||
"amended_from",
|
||||
"details_section",
|
||||
"shift",
|
||||
"in_time",
|
||||
"out_time",
|
||||
"column_break_18",
|
||||
"late_entry",
|
||||
"early_exit"
|
||||
"early_exit",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -172,13 +176,36 @@
|
||||
"fieldname": "early_exit",
|
||||
"fieldtype": "Check",
|
||||
"label": "Early Exit"
|
||||
},
|
||||
{
|
||||
"fieldname": "details_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Details"
|
||||
},
|
||||
{
|
||||
"depends_on": "shift",
|
||||
"fieldname": "in_time",
|
||||
"fieldtype": "Datetime",
|
||||
"label": "In Time",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "shift",
|
||||
"fieldname": "out_time",
|
||||
"fieldtype": "Datetime",
|
||||
"label": "Out Time",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_18",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-ok",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-11 11:40:14.319496",
|
||||
"modified": "2020-05-29 13:51:37.177231",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Attendance",
|
||||
|
@ -139,13 +139,13 @@ frappe.ui.form.on('Employee Advance', {
|
||||
employee: function (frm) {
|
||||
if (frm.doc.employee) {
|
||||
return frappe.call({
|
||||
method: "erpnext.hr.doctype.employee_advance.employee_advance.get_due_advance_amount",
|
||||
method: "erpnext.hr.doctype.employee_advance.employee_advance.get_pending_amount",
|
||||
args: {
|
||||
"employee": frm.doc.employee,
|
||||
"posting_date": frm.doc.posting_date
|
||||
},
|
||||
callback: function(r) {
|
||||
frm.set_value("due_advance_amount",r.message);
|
||||
frm.set_value("pending_amount",r.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
"column_break_11",
|
||||
"advance_amount",
|
||||
"paid_amount",
|
||||
"due_advance_amount",
|
||||
"pending_amount",
|
||||
"claimed_amount",
|
||||
"return_amount",
|
||||
"section_break_7",
|
||||
@ -102,14 +102,6 @@
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:cur_frm.doc.employee",
|
||||
"fieldname": "due_advance_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Due Advance Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "claimed_amount",
|
||||
"fieldtype": "Currency",
|
||||
@ -177,11 +169,19 @@
|
||||
"fieldname": "repay_unclaimed_amount_from_salary",
|
||||
"fieldtype": "Check",
|
||||
"label": "Repay unclaimed amount from salary"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:cur_frm.doc.employee",
|
||||
"fieldname": "pending_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Pending Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-06 15:11:33.747535",
|
||||
"modified": "2020-06-12 12:42:39.833818",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Advance",
|
||||
|
@ -95,7 +95,7 @@ class EmployeeAdvance(Document):
|
||||
frappe.db.set_value("Employee Advance", self.name, "status", self.status)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_due_advance_amount(employee, posting_date):
|
||||
def get_pending_amount(employee, posting_date):
|
||||
employee_due_amount = frappe.get_all("Employee Advance", \
|
||||
filters = {"employee":employee, "docstatus":1, "posting_date":("<=", posting_date)}, \
|
||||
fields = ["advance_amount", "paid_amount"])
|
||||
|
@ -72,7 +72,7 @@ def add_log_based_on_employee_field(employee_field_value, timestamp, device_id=N
|
||||
return doc
|
||||
|
||||
|
||||
def mark_attendance_and_link_log(logs, attendance_status, attendance_date, working_hours=None, late_entry=False, early_exit=False, shift=None):
|
||||
def mark_attendance_and_link_log(logs, attendance_status, attendance_date, working_hours=None, late_entry=False, early_exit=False, in_time=None, out_time=None, shift=None):
|
||||
"""Creates an attendance and links the attendance to the Employee Checkin.
|
||||
Note: If attendance is already present for the given date, the logs are marked as skipped and no exception is thrown.
|
||||
|
||||
@ -100,7 +100,9 @@ def mark_attendance_and_link_log(logs, attendance_status, attendance_date, worki
|
||||
'company': employee_doc.company,
|
||||
'shift': shift,
|
||||
'late_entry': late_entry,
|
||||
'early_exit': early_exit
|
||||
'early_exit': early_exit,
|
||||
'in_time': in_time,
|
||||
'out_time': out_time
|
||||
}
|
||||
attendance = frappe.get_doc(doc_dict).insert()
|
||||
attendance.submit()
|
||||
|
@ -46,6 +46,7 @@ frappe.ui.form.on("Leave Application", {
|
||||
|
||||
make_dashboard: function(frm) {
|
||||
var leave_details;
|
||||
let lwps;
|
||||
if (frm.doc.employee) {
|
||||
frappe.call({
|
||||
method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_details",
|
||||
@ -61,6 +62,7 @@ frappe.ui.form.on("Leave Application", {
|
||||
if (!r.exc && r.message['leave_approver']) {
|
||||
frm.set_value('leave_approver', r.message['leave_approver']);
|
||||
}
|
||||
lwps = r.message["lwps"];
|
||||
}
|
||||
});
|
||||
$("div").remove(".form-dashboard-section.custom");
|
||||
@ -70,12 +72,17 @@ frappe.ui.form.on("Leave Application", {
|
||||
})
|
||||
);
|
||||
frm.dashboard.show();
|
||||
let allowed_leave_types = Object.keys(leave_details);
|
||||
|
||||
// lwps should be allowed, lwps don't have any allocation
|
||||
allowed_leave_types = allowed_leave_types.concat(lwps);
|
||||
|
||||
frm.set_query('leave_type', function(){
|
||||
return {
|
||||
filters : [
|
||||
['leave_type_name', 'in', Object.keys(leave_details)]
|
||||
['leave_type_name', 'in', allowed_leave_types]
|
||||
]
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -19,7 +19,6 @@ class NotAnOptionalHoliday(frappe.ValidationError): pass
|
||||
|
||||
from frappe.model.document import Document
|
||||
class LeaveApplication(Document):
|
||||
|
||||
def get_feed(self):
|
||||
return _("{0}: From {0} of type {1}").format(self.employee_name, self.leave_type)
|
||||
|
||||
@ -463,9 +462,14 @@ def get_leave_details(employee, date):
|
||||
"pending_leaves": leaves_pending,
|
||||
"remaining_leaves": remaining_leaves}
|
||||
|
||||
#is used in set query
|
||||
lwps = frappe.get_list("Leave Type", filters = {"is_lwp": 1})
|
||||
lwps = [lwp.name for lwp in lwps]
|
||||
|
||||
ret = {
|
||||
'leave_allocation': leave_allocation,
|
||||
'leave_approver': get_leave_approver(employee)
|
||||
'leave_approver': get_leave_approver(employee),
|
||||
'lwps': lwps
|
||||
}
|
||||
|
||||
return ret
|
||||
|
@ -28,13 +28,14 @@ class ShiftType(Document):
|
||||
logs = frappe.db.get_list('Employee Checkin', fields="*", filters=filters, order_by="employee,time")
|
||||
for key, group in itertools.groupby(logs, key=lambda x: (x['employee'], x['shift_actual_start'])):
|
||||
single_shift_logs = list(group)
|
||||
attendance_status, working_hours, late_entry, early_exit = self.get_attendance(single_shift_logs)
|
||||
mark_attendance_and_link_log(single_shift_logs, attendance_status, key[1].date(), working_hours, late_entry, early_exit, self.name)
|
||||
attendance_status, working_hours, late_entry, early_exit, in_time, out_time = self.get_attendance(single_shift_logs)
|
||||
mark_attendance_and_link_log(single_shift_logs, attendance_status, key[1].date(), working_hours, late_entry, early_exit, in_time, out_time, self.name)
|
||||
for employee in self.get_assigned_employee(self.process_attendance_after, True):
|
||||
self.mark_absent_for_dates_with_no_attendance(employee)
|
||||
|
||||
def get_attendance(self, logs):
|
||||
"""Return attendance_status, working_hours for a set of logs belonging to a single shift.
|
||||
"""Return attendance_status, working_hours, late_entry, early_exit, in_time, out_time
|
||||
for a set of logs belonging to a single shift.
|
||||
Assumtion:
|
||||
1. These logs belongs to an single shift, single employee and is not in a holiday date.
|
||||
2. Logs are in chronological order
|
||||
@ -48,10 +49,10 @@ class ShiftType(Document):
|
||||
early_exit = True
|
||||
|
||||
if self.working_hours_threshold_for_absent and total_working_hours < self.working_hours_threshold_for_absent:
|
||||
return 'Absent', total_working_hours, late_entry, early_exit
|
||||
return 'Absent', total_working_hours, late_entry, early_exit, in_time, out_time
|
||||
if self.working_hours_threshold_for_half_day and total_working_hours < self.working_hours_threshold_for_half_day:
|
||||
return 'Half Day', total_working_hours, late_entry, early_exit
|
||||
return 'Present', total_working_hours, late_entry, early_exit
|
||||
return 'Half Day', total_working_hours, late_entry, early_exit, in_time, out_time
|
||||
return 'Present', total_working_hours, late_entry, early_exit, in_time, out_time
|
||||
|
||||
def mark_absent_for_dates_with_no_attendance(self, employee):
|
||||
"""Marks Absents for the given employee on working days in this shift which have no attendance marked.
|
||||
|
@ -77,6 +77,7 @@ def create_customer(user_details):
|
||||
customer = frappe.new_doc("Customer")
|
||||
customer.customer_name = user_details.fullname
|
||||
customer.customer_type = "Individual"
|
||||
customer.flags.ignore_mandatory = True
|
||||
customer.insert(ignore_permissions=True)
|
||||
|
||||
try:
|
||||
@ -91,7 +92,11 @@ def create_customer(user_details):
|
||||
"link_name": customer.name
|
||||
})
|
||||
|
||||
contact.insert()
|
||||
contact.save()
|
||||
|
||||
except frappe.DuplicateEntryError:
|
||||
return customer.name
|
||||
|
||||
except Exception as e:
|
||||
frappe.log_error(frappe.get_traceback(), _("Contact Creation Failed"))
|
||||
pass
|
||||
|
@ -62,7 +62,10 @@ def get_member_based_on_subscription(subscription_id, email):
|
||||
'subscription_id': subscription_id,
|
||||
'email_id': email
|
||||
}, order_by="creation desc")
|
||||
return frappe.get_doc("Member", members[0]['name'])
|
||||
try:
|
||||
return frappe.get_doc("Member", members[0]['name'])
|
||||
except:
|
||||
return None
|
||||
|
||||
def verify_signature(data):
|
||||
signature = frappe.request.headers.get('X-Razorpay-Signature')
|
||||
@ -77,7 +80,7 @@ def verify_signature(data):
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def trigger_razorpay_subscription(*args, **kwargs):
|
||||
data = frappe.request.get_data()
|
||||
data = frappe.request.get_data(as_text=True)
|
||||
verify_signature(data)
|
||||
|
||||
if isinstance(data, six.string_types):
|
||||
@ -96,7 +99,10 @@ def trigger_razorpay_subscription(*args, **kwargs):
|
||||
except Exception as e:
|
||||
error_log = frappe.log_error(frappe.get_traceback() + '\n' + data_json , _("Membership Webhook Failed"))
|
||||
notify_failure(error_log)
|
||||
raise e
|
||||
return False
|
||||
|
||||
if not member:
|
||||
return False
|
||||
|
||||
if data.event == "subscription.activated":
|
||||
member.customer_id = payment.customer_id
|
||||
|
@ -680,6 +680,8 @@ erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
|
||||
erpnext.patches.v12_0.retain_permission_rules_for_video_doctype
|
||||
erpnext.patches.v12_0.remove_duplicate_leave_ledger_entries #2020-05-22
|
||||
erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive
|
||||
execute:frappe.reload_doc("HR", "doctype", "Employee Advance")
|
||||
erpnext.patches.v12_0.move_due_advance_amount_to_pending_amount
|
||||
execute:frappe.delete_doc_if_exists("Page", "appointment-analytic")
|
||||
execute:frappe.rename_doc("Desk Page", "Getting Started", "Home", force=True)
|
||||
erpnext.patches.v12_0.unset_customer_supplier_based_on_type_of_item_price
|
||||
@ -694,4 +696,4 @@ execute:frappe.delete_doc("Report", "Department Analytics")
|
||||
execute:frappe.rename_doc("Desk Page", "Loan Management", "Loan", force=True)
|
||||
erpnext.patches.v12_0.update_uom_conversion_factor
|
||||
erpnext.patches.v13_0.delete_old_purchase_reports
|
||||
erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions
|
||||
erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions
|
||||
|
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2019, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
''' Move from due_advance_amount to pending_amount '''
|
||||
frappe.db.sql(''' UPDATE `tabEmployee Advance` SET pending_amount=due_advance_amount ''')
|
@ -7,4 +7,4 @@ def execute():
|
||||
for entry in doctypes:
|
||||
if frappe.db.exists('DocType', entry):
|
||||
frappe.reload_doc('Healthcare', 'doctype', entry)
|
||||
frappe.db.sql("update `tab{dt}` set company = '{company}' where ifnull(company, '') = ''".format(dt=entry, company=company))
|
||||
frappe.db.sql("update `tab{dt}` set company = {company} where ifnull(company, '') = ''".format(dt=entry, company=frappe.db.escape(company)))
|
||||
|
@ -73,6 +73,8 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
me.frm.set_query('contact_person', erpnext.queries.contact_query);
|
||||
me.frm.set_query('supplier_address', erpnext.queries.address_query);
|
||||
|
||||
me.frm.set_query('billing_address', erpnext.queries.company_address_query);
|
||||
|
||||
if(this.frm.fields_dict.supplier) {
|
||||
this.frm.set_query("supplier", function() {
|
||||
return{ query: "erpnext.controllers.queries.supplier_query" }});
|
||||
@ -283,6 +285,11 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
"shipping_address_display", true);
|
||||
},
|
||||
|
||||
billing_address: function() {
|
||||
erpnext.utils.get_address_display(this.frm, "billing_address",
|
||||
"billing_address_display", true);
|
||||
},
|
||||
|
||||
tc_name: function() {
|
||||
this.get_terms();
|
||||
},
|
||||
|
@ -552,7 +552,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
if (show_batch_dialog)
|
||||
return frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
|
||||
.then((r) => {
|
||||
if(r.message.has_batch_no || r.message.has_serial_no) {
|
||||
if (r.message &&
|
||||
(r.message.has_batch_no || r.message.has_serial_no)) {
|
||||
frappe.flags.hide_serial_batch_dialog = false;
|
||||
}
|
||||
});
|
||||
|
@ -3,16 +3,19 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import json
|
||||
from frappe.model.naming import set_name_by_naming_series
|
||||
from frappe import _, msgprint, throw
|
||||
from frappe import _, msgprint
|
||||
import frappe.defaults
|
||||
from frappe.utils import flt, cint, cstr, today
|
||||
from frappe.utils import flt, cint, cstr, today, get_formatted_email
|
||||
from frappe.desk.reportview import build_match_conditions, get_filters_cond
|
||||
from erpnext.utilities.transaction_base import TransactionBase
|
||||
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
|
||||
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
|
||||
from frappe.model.rename_doc import update_linked_doctypes
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from frappe.utils.user import get_users_with_role
|
||||
|
||||
|
||||
class Customer(TransactionBase):
|
||||
def get_feed(self):
|
||||
@ -378,10 +381,45 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False,
|
||||
.format(customer, customer_outstanding, credit_limit))
|
||||
|
||||
# If not authorized person raise exception
|
||||
credit_controller = frappe.db.get_value('Accounts Settings', None, 'credit_controller')
|
||||
if not credit_controller or credit_controller not in frappe.get_roles():
|
||||
throw(_("Please contact to the user who have Sales Master Manager {0} role")
|
||||
.format(" / " + credit_controller if credit_controller else ""))
|
||||
credit_controller_role = frappe.db.get_single_value('Accounts Settings', 'credit_controller')
|
||||
if not credit_controller_role or credit_controller_role not in frappe.get_roles():
|
||||
# form a list of emails for the credit controller users
|
||||
credit_controller_users = get_users_with_role(credit_controller_role or "Sales Master Manager")
|
||||
|
||||
# form a list of emails and names to show to the user
|
||||
credit_controller_users_list = [user for user in credit_controller_users if frappe.db.exists("Employee", {"prefered_email": user})]
|
||||
credit_controller_users = [get_formatted_email(user).replace("<", "(").replace(">", ")") for user in credit_controller_users_list]
|
||||
|
||||
if not credit_controller_users:
|
||||
frappe.throw(_("Please contact your administrator to extend the credit limits for {0}.".format(customer)))
|
||||
|
||||
message = """Please contact any of the following users to extend the credit limits for {0}:
|
||||
<br><br><ul><li>{1}</li></ul>""".format(customer, '<li>'.join(credit_controller_users))
|
||||
|
||||
# if the current user does not have permissions to override credit limit,
|
||||
# prompt them to send out an email to the controller users
|
||||
frappe.msgprint(message,
|
||||
title="Notify",
|
||||
raise_exception=1,
|
||||
primary_action={
|
||||
'label': 'Send Email',
|
||||
'server_action': 'erpnext.selling.doctype.customer.customer.send_emails',
|
||||
'args': {
|
||||
'customer': customer,
|
||||
'customer_outstanding': customer_outstanding,
|
||||
'credit_limit': credit_limit,
|
||||
'credit_controller_users_list': credit_controller_users_list
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@frappe.whitelist()
|
||||
def send_emails(args):
|
||||
args = json.loads(args)
|
||||
subject = (_("Credit limit reached for customer {0}").format(args.get('customer')))
|
||||
message = (_("Credit limit has been crossed for customer {0} ({1}/{2})")
|
||||
.format(args.get('customer'), args.get('customer_outstanding'), args.get('credit_limit')))
|
||||
frappe.sendmail(recipients=[args.get('credit_controller_users_list')], subject=subject, message=message)
|
||||
|
||||
def get_customer_outstanding(customer, company, ignore_outstanding_sales_order=False, cost_center=None):
|
||||
# Outstanding based on GL Entries
|
||||
|
@ -337,21 +337,17 @@ def set_price_list_and_rate(quotation, cart_settings):
|
||||
def _set_price_list(cart_settings, quotation=None):
|
||||
"""Set price list based on customer or shopping cart default"""
|
||||
from erpnext.accounts.party import get_default_price_list
|
||||
|
||||
# check if customer price list exists
|
||||
party_name = quotation.get("party_name") if quotation else get_party().get("name")
|
||||
selling_price_list = None
|
||||
if quotation and quotation.get("party_name"):
|
||||
selling_price_list = frappe.db.get_value('Customer', quotation.get("party_name"), 'default_price_list')
|
||||
|
||||
# else check for territory based price list
|
||||
# check if default customer price list exists
|
||||
if party_name:
|
||||
selling_price_list = get_default_price_list(frappe.get_doc("Customer", party_name))
|
||||
|
||||
# check default price list in shopping cart
|
||||
if not selling_price_list:
|
||||
selling_price_list = cart_settings.price_list
|
||||
|
||||
party_name = quotation.get("party_name") if quotation else get_party().get("name")
|
||||
|
||||
if not selling_price_list and party_name:
|
||||
selling_price_list = get_default_price_list(frappe.get_doc("Customer", party_name))
|
||||
|
||||
if quotation:
|
||||
quotation.selling_price_list = selling_price_list
|
||||
|
||||
|
@ -119,11 +119,13 @@ def get_items_with_location_and_quantity(item_doc, item_location_map):
|
||||
if item_location.serial_no:
|
||||
serial_nos = '\n'.join(item_location.serial_no[0: cint(stock_qty)])
|
||||
|
||||
auto_set_serial_no = frappe.db.get_single_value("Stock Settings", "automatically_set_serial_nos_based_on_fifo")
|
||||
|
||||
locations.append(frappe._dict({
|
||||
'qty': qty,
|
||||
'stock_qty': stock_qty,
|
||||
'warehouse': item_location.warehouse,
|
||||
'serial_no': serial_nos,
|
||||
'serial_no': serial_nos if auto_set_serial_no else item_doc.serial_no,
|
||||
'batch_no': item_location.batch_no
|
||||
}))
|
||||
|
||||
@ -206,6 +208,7 @@ def get_available_item_locations_for_batched_item(item_code, from_warehouses, re
|
||||
sle.batch_no = batch.name
|
||||
and sle.`item_code`=%(item_code)s
|
||||
and sle.`company` = %(company)s
|
||||
and batch.disabled = 0
|
||||
and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
|
||||
{warehouse_condition}
|
||||
GROUP BY
|
||||
@ -471,4 +474,4 @@ def update_common_item_properties(item, location):
|
||||
item.material_request = location.material_request
|
||||
item.serial_no = location.serial_no
|
||||
item.batch_no = location.batch_no
|
||||
item.material_request_item = location.material_request_item
|
||||
item.material_request_item = location.material_request_item
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@ from frappe.utils import getdate, flt
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
float_preceision = frappe.db.get_default("float_preceision")
|
||||
float_precision = frappe.db.get_default("float_precision")
|
||||
|
||||
condition = get_condition(filters)
|
||||
|
||||
@ -25,7 +25,7 @@ def execute(filters=None):
|
||||
data = []
|
||||
for item in items:
|
||||
total_outgoing = flt(consumed_item_map.get(item.name, 0)) + flt(delivered_item_map.get(item.name,0))
|
||||
avg_daily_outgoing = flt(total_outgoing / diff, float_preceision)
|
||||
avg_daily_outgoing = flt(total_outgoing / diff, float_precision)
|
||||
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.safety_stock)
|
||||
|
||||
data.append([item.name, item.item_name, item.item_group, item.brand, item.description,
|
||||
|
@ -180,10 +180,10 @@ def get_fifo_queue(filters, sle=None):
|
||||
qty_to_pop = abs(d.actual_qty)
|
||||
while qty_to_pop:
|
||||
batch = fifo_queue[0] if fifo_queue else [0, None]
|
||||
if 0 < batch[0] <= qty_to_pop:
|
||||
if 0 < flt(batch[0]) <= qty_to_pop:
|
||||
# if batch qty > 0
|
||||
# not enough or exactly same qty in current batch, clear batch
|
||||
qty_to_pop -= batch[0]
|
||||
qty_to_pop -= flt(batch[0])
|
||||
transferred_item_details[(d.voucher_no, d.name)].append(fifo_queue.pop(0))
|
||||
else:
|
||||
# all from current batch
|
||||
@ -262,4 +262,4 @@ def get_chart_data(data, filters):
|
||||
]
|
||||
},
|
||||
"type" : "bar"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user