Merge branch 'develop' into sales_person_dashboard
This commit is contained in:
commit
993cc287d5
@ -110,13 +110,12 @@
|
|||||||
"description": "Reference number of the invoice from the previous system",
|
"description": "Reference number of the invoice from the previous system",
|
||||||
"fieldname": "invoice_number",
|
"fieldname": "invoice_number",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
|
||||||
"label": "Invoice Number"
|
"label": "Invoice Number"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-12-17 19:25:06.053187",
|
"modified": "2022-03-21 19:31:45.382656",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Opening Invoice Creation Tool Item",
|
"name": "Opening Invoice Creation Tool Item",
|
||||||
@ -125,5 +124,6 @@
|
|||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
@ -485,16 +485,15 @@ class POSInvoice(SalesInvoice):
|
|||||||
"payment_account": pay.account,
|
"payment_account": pay.account,
|
||||||
}, ["name"])
|
}, ["name"])
|
||||||
|
|
||||||
args = {
|
filters = {
|
||||||
'doctype': 'Payment Request',
|
|
||||||
'reference_doctype': 'POS Invoice',
|
'reference_doctype': 'POS Invoice',
|
||||||
'reference_name': self.name,
|
'reference_name': self.name,
|
||||||
'payment_gateway_account': payment_gateway_account,
|
'payment_gateway_account': payment_gateway_account,
|
||||||
'email_to': self.contact_mobile
|
'email_to': self.contact_mobile
|
||||||
}
|
}
|
||||||
pr = frappe.db.exists(args)
|
pr = frappe.db.get_value('Payment Request', filters=filters)
|
||||||
if pr:
|
if pr:
|
||||||
return frappe.get_doc('Payment Request', pr[0][0])
|
return frappe.get_doc('Payment Request', pr)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_stock_availability(item_code, warehouse):
|
def get_stock_availability(item_code, warehouse):
|
||||||
|
@ -1711,6 +1711,7 @@ def make_delivery_note(source_name, target_doc=None):
|
|||||||
}
|
}
|
||||||
}, target_doc, set_missing_values)
|
}, target_doc, set_missing_values)
|
||||||
|
|
||||||
|
doclist.set_onload('ignore_price_list', True)
|
||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -442,6 +442,8 @@ def make_purchase_receipt(source_name, target_doc=None):
|
|||||||
}
|
}
|
||||||
}, target_doc, set_missing_values)
|
}, target_doc, set_missing_values)
|
||||||
|
|
||||||
|
doc.set_onload('ignore_price_list', True)
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@ -509,6 +511,7 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
|
|||||||
|
|
||||||
doc = get_mapped_doc("Purchase Order", source_name, fields,
|
doc = get_mapped_doc("Purchase Order", source_name, fields,
|
||||||
target_doc, postprocess, ignore_permissions=ignore_permissions)
|
target_doc, postprocess, ignore_permissions=ignore_permissions)
|
||||||
|
doc.set_onload('ignore_price_list', True)
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ def make_purchase_order(source_name, target_doc=None):
|
|||||||
},
|
},
|
||||||
}, target_doc, set_missing_values)
|
}, target_doc, set_missing_values)
|
||||||
|
|
||||||
|
doclist.set_onload('ignore_price_list', True)
|
||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -168,7 +168,7 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
{account_type_condition}
|
{account_type_condition}
|
||||||
AND is_group = 0
|
AND is_group = 0
|
||||||
AND company = %(company)s
|
AND company = %(company)s
|
||||||
AND account_currency = %(currency)s
|
AND (account_currency = %(currency)s or ifnull(account_currency, '') = '')
|
||||||
AND `{searchfield}` LIKE %(txt)s
|
AND `{searchfield}` LIKE %(txt)s
|
||||||
{mcond}
|
{mcond}
|
||||||
ORDER BY idx DESC, name
|
ORDER BY idx DESC, name
|
||||||
|
@ -225,9 +225,7 @@ def _check_agent_availability(agent_email, scheduled_time):
|
|||||||
|
|
||||||
|
|
||||||
def _get_employee_from_user(user):
|
def _get_employee_from_user(user):
|
||||||
employee_docname = frappe.db.exists(
|
employee_docname = frappe.db.get_value('Employee', {'user_id': user})
|
||||||
{'doctype': 'Employee', 'user_id': user})
|
|
||||||
if employee_docname:
|
if employee_docname:
|
||||||
# frappe.db.exists returns a tuple of a tuple
|
return frappe.get_doc('Employee', employee_docname)
|
||||||
return frappe.get_doc('Employee', employee_docname[0][0])
|
|
||||||
return None
|
return None
|
||||||
|
@ -8,33 +8,29 @@ import frappe
|
|||||||
|
|
||||||
|
|
||||||
def create_test_lead():
|
def create_test_lead():
|
||||||
test_lead = frappe.db.exists({'doctype': 'Lead', 'email_id':'test@example.com'})
|
test_lead = frappe.db.get_value("Lead", {"email_id": "test@example.com"})
|
||||||
if test_lead:
|
if test_lead:
|
||||||
return frappe.get_doc('Lead', test_lead[0][0])
|
return frappe.get_doc("Lead", test_lead)
|
||||||
test_lead = frappe.get_doc({
|
test_lead = frappe.get_doc(
|
||||||
'doctype': 'Lead',
|
{"doctype": "Lead", "lead_name": "Test Lead", "email_id": "test@example.com"}
|
||||||
'lead_name': 'Test Lead',
|
)
|
||||||
'email_id': 'test@example.com'
|
|
||||||
})
|
|
||||||
test_lead.insert(ignore_permissions=True)
|
test_lead.insert(ignore_permissions=True)
|
||||||
return test_lead
|
return test_lead
|
||||||
|
|
||||||
|
|
||||||
def create_test_appointments():
|
def create_test_appointments():
|
||||||
test_appointment = frappe.db.exists(
|
test_appointment = frappe.get_doc(
|
||||||
{'doctype': 'Appointment', 'scheduled_time':datetime.datetime.now(),'email':'test@example.com'})
|
{
|
||||||
if test_appointment:
|
"doctype": "Appointment",
|
||||||
return frappe.get_doc('Appointment', test_appointment[0][0])
|
"email": "test@example.com",
|
||||||
test_appointment = frappe.get_doc({
|
"status": "Open",
|
||||||
'doctype': 'Appointment',
|
"customer_name": "Test Lead",
|
||||||
'email': 'test@example.com',
|
"customer_phone_number": "666",
|
||||||
'status': 'Open',
|
"customer_skype": "test",
|
||||||
'customer_name': 'Test Lead',
|
"customer_email": "test@example.com",
|
||||||
'customer_phone_number': '666',
|
"scheduled_time": datetime.datetime.now(),
|
||||||
'customer_skype': 'test',
|
}
|
||||||
'customer_email': 'test@example.com',
|
)
|
||||||
'scheduled_time': datetime.datetime.now()
|
|
||||||
})
|
|
||||||
test_appointment.insert()
|
test_appointment.insert()
|
||||||
return test_appointment
|
return test_appointment
|
||||||
|
|
||||||
@ -47,11 +43,9 @@ class TestAppointment(unittest.TestCase):
|
|||||||
self.test_appointment = create_test_appointments()
|
self.test_appointment = create_test_appointments()
|
||||||
|
|
||||||
def test_calendar_event_created(self):
|
def test_calendar_event_created(self):
|
||||||
cal_event = frappe.get_doc(
|
cal_event = frappe.get_doc("Event", self.test_appointment.calendar_event)
|
||||||
'Event', self.test_appointment.calendar_event)
|
self.assertEqual(cal_event.starts_on, self.test_appointment.scheduled_time)
|
||||||
self.assertEqual(cal_event.starts_on,
|
|
||||||
self.test_appointment.scheduled_time)
|
|
||||||
|
|
||||||
def test_lead_linked(self):
|
def test_lead_linked(self):
|
||||||
lead = frappe.get_doc('Lead', self.test_lead.name)
|
lead = frappe.get_doc("Lead", self.test_lead.name)
|
||||||
self.assertIsNotNone(lead)
|
self.assertIsNotNone(lead)
|
||||||
|
@ -418,6 +418,22 @@ erpnext.ProductView = class {
|
|||||||
|
|
||||||
me.change_route_with_filters();
|
me.change_route_with_filters();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// bind filter lookup input box
|
||||||
|
$('.filter-lookup-input').on('keydown', frappe.utils.debounce((e) => {
|
||||||
|
const $input = $(e.target);
|
||||||
|
const keyword = ($input.val() || '').toLowerCase();
|
||||||
|
const $filter_options = $input.next('.filter-options');
|
||||||
|
|
||||||
|
$filter_options.find('.filter-lookup-wrapper').show();
|
||||||
|
$filter_options.find('.filter-lookup-wrapper').each((i, el) => {
|
||||||
|
const $el = $(el);
|
||||||
|
const value = $el.data('value').toLowerCase();
|
||||||
|
if (!value.includes(keyword)) {
|
||||||
|
$el.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 300));
|
||||||
}
|
}
|
||||||
|
|
||||||
change_route_with_filters() {
|
change_route_with_filters() {
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from erpnext.setup.utils import insert_record
|
|
||||||
|
|
||||||
|
|
||||||
def setup_education():
|
def setup_education():
|
||||||
@ -13,6 +12,21 @@ def setup_education():
|
|||||||
return
|
return
|
||||||
create_academic_sessions()
|
create_academic_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def insert_record(records):
|
||||||
|
for r in records:
|
||||||
|
doc = frappe.new_doc(r.get("doctype"))
|
||||||
|
doc.update(r)
|
||||||
|
try:
|
||||||
|
doc.insert(ignore_permissions=True)
|
||||||
|
except frappe.DuplicateEntryError as e:
|
||||||
|
# pass DuplicateEntryError and continue
|
||||||
|
if e.args and e.args[0]==doc.doctype and e.args[1]==doc.name:
|
||||||
|
# make sure DuplicateEntryError is for the exact same doc and not a related doc
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
def create_academic_sessions():
|
def create_academic_sessions():
|
||||||
data = [
|
data = [
|
||||||
{"doctype": "Academic Year", "academic_year_name": "2015-16"},
|
{"doctype": "Academic Year", "academic_year_name": "2015-16"},
|
||||||
|
@ -25,6 +25,7 @@ from erpnext.hr.doctype.leave_application.leave_application import (
|
|||||||
LeaveDayBlockedError,
|
LeaveDayBlockedError,
|
||||||
NotAnOptionalHoliday,
|
NotAnOptionalHoliday,
|
||||||
OverlapError,
|
OverlapError,
|
||||||
|
get_leave_allocation_records,
|
||||||
get_leave_balance_on,
|
get_leave_balance_on,
|
||||||
get_leave_details,
|
get_leave_details,
|
||||||
)
|
)
|
||||||
@ -882,6 +883,27 @@ class TestLeaveApplication(unittest.TestCase):
|
|||||||
self.assertEqual(leave_allocation['leaves_pending_approval'], 1)
|
self.assertEqual(leave_allocation['leaves_pending_approval'], 1)
|
||||||
self.assertEqual(leave_allocation['remaining_leaves'], 26)
|
self.assertEqual(leave_allocation['remaining_leaves'], 26)
|
||||||
|
|
||||||
|
@set_holiday_list('Salary Slip Test Holiday List', '_Test Company')
|
||||||
|
def test_get_leave_allocation_records(self):
|
||||||
|
employee = get_employee()
|
||||||
|
leave_type = create_leave_type(
|
||||||
|
leave_type_name="_Test_CF_leave_expiry",
|
||||||
|
is_carry_forward=1,
|
||||||
|
expire_carry_forwarded_leaves_after_days=90)
|
||||||
|
leave_type.insert()
|
||||||
|
|
||||||
|
leave_alloc = create_carry_forwarded_allocation(employee, leave_type)
|
||||||
|
details = get_leave_allocation_records(employee.name, getdate(), leave_type.name)
|
||||||
|
expected_data = {
|
||||||
|
"from_date": getdate(leave_alloc.from_date),
|
||||||
|
"to_date": getdate(leave_alloc.to_date),
|
||||||
|
"total_leaves_allocated": 30.0,
|
||||||
|
"unused_leaves": 15.0,
|
||||||
|
"new_leaves_allocated": 15.0,
|
||||||
|
"leave_type": leave_type.name
|
||||||
|
}
|
||||||
|
self.assertEqual(details.get(leave_type.name), expected_data)
|
||||||
|
|
||||||
|
|
||||||
def create_carry_forwarded_allocation(employee, leave_type):
|
def create_carry_forwarded_allocation(employee, leave_type):
|
||||||
# initial leave allocation
|
# initial leave allocation
|
||||||
@ -903,6 +925,8 @@ def create_carry_forwarded_allocation(employee, leave_type):
|
|||||||
carry_forward=1)
|
carry_forward=1)
|
||||||
leave_allocation.submit()
|
leave_allocation.submit()
|
||||||
|
|
||||||
|
return leave_allocation
|
||||||
|
|
||||||
def make_allocation_record(employee=None, leave_type=None, from_date=None, to_date=None, carry_forward=False, leaves=None):
|
def make_allocation_record(employee=None, leave_type=None, from_date=None, to_date=None, carry_forward=False, leaves=None):
|
||||||
allocation = frappe.get_doc({
|
allocation = frappe.get_doc({
|
||||||
"doctype": "Leave Allocation",
|
"doctype": "Leave Allocation",
|
||||||
@ -931,12 +955,9 @@ def set_leave_approver():
|
|||||||
dept_doc.save(ignore_permissions=True)
|
dept_doc.save(ignore_permissions=True)
|
||||||
|
|
||||||
def get_leave_period():
|
def get_leave_period():
|
||||||
leave_period_name = frappe.db.exists({
|
leave_period_name = frappe.db.get_value("Leave Period", {"company": "_Test Company"})
|
||||||
"doctype": "Leave Period",
|
|
||||||
"company": "_Test Company"
|
|
||||||
})
|
|
||||||
if leave_period_name:
|
if leave_period_name:
|
||||||
return frappe.get_doc("Leave Period", leave_period_name[0][0])
|
return frappe.get_doc("Leave Period", leave_period_name)
|
||||||
else:
|
else:
|
||||||
return frappe.get_doc(dict(
|
return frappe.get_doc(dict(
|
||||||
name = 'Test Leave Period',
|
name = 'Test Leave Period',
|
||||||
|
@ -500,6 +500,9 @@ class JobCard(Document):
|
|||||||
2: "Cancelled"
|
2: "Cancelled"
|
||||||
}[self.docstatus or 0]
|
}[self.docstatus or 0]
|
||||||
|
|
||||||
|
if self.for_quantity <= self.transferred_qty:
|
||||||
|
self.status = 'Material Transferred'
|
||||||
|
|
||||||
if self.time_logs:
|
if self.time_logs:
|
||||||
self.status = 'Work In Progress'
|
self.status = 'Work In Progress'
|
||||||
|
|
||||||
@ -507,10 +510,6 @@ class JobCard(Document):
|
|||||||
(self.for_quantity <= self.total_completed_qty or not self.items)):
|
(self.for_quantity <= self.total_completed_qty or not self.items)):
|
||||||
self.status = 'Completed'
|
self.status = 'Completed'
|
||||||
|
|
||||||
if self.status != 'Completed':
|
|
||||||
if self.for_quantity <= self.transferred_qty:
|
|
||||||
self.status = 'Material Transferred'
|
|
||||||
|
|
||||||
if update_status:
|
if update_status:
|
||||||
self.db_set('status', self.status)
|
self.db_set('status', self.status)
|
||||||
|
|
||||||
|
@ -169,6 +169,7 @@ class TestJobCard(FrappeTestCase):
|
|||||||
|
|
||||||
job_card_name = frappe.db.get_value("Job Card", {'work_order': self.work_order.name})
|
job_card_name = frappe.db.get_value("Job Card", {'work_order': self.work_order.name})
|
||||||
job_card = frappe.get_doc("Job Card", job_card_name)
|
job_card = frappe.get_doc("Job Card", job_card_name)
|
||||||
|
self.assertEqual(job_card.status, "Open")
|
||||||
|
|
||||||
# fully transfer both RMs
|
# fully transfer both RMs
|
||||||
transfer_entry_1 = make_stock_entry_from_jc(job_card_name)
|
transfer_entry_1 = make_stock_entry_from_jc(job_card_name)
|
||||||
|
@ -1150,6 +1150,10 @@ def create_job_card(work_order, row, enable_capacity_planning=False, auto_create
|
|||||||
doc.insert()
|
doc.insert()
|
||||||
frappe.msgprint(_("Job card {0} created").format(get_link_to_form("Job Card", doc.name)), alert=True)
|
frappe.msgprint(_("Job card {0} created").format(get_link_to_form("Job Card", doc.name)), alert=True)
|
||||||
|
|
||||||
|
if enable_capacity_planning:
|
||||||
|
# automatically added scheduling rows shouldn't change status to WIP
|
||||||
|
doc.db_set("status", "Open")
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
def get_work_order_operation_data(work_order, operation, workstation):
|
def get_work_order_operation_data(work_order, operation, workstation):
|
||||||
|
@ -708,6 +708,8 @@ def submit_salary_slips_for_employees(payroll_entry, salary_slips, publish_progr
|
|||||||
if not_submitted_ss:
|
if not_submitted_ss:
|
||||||
frappe.msgprint(_("Could not submit some Salary Slips"))
|
frappe.msgprint(_("Could not submit some Salary Slips"))
|
||||||
|
|
||||||
|
frappe.flags.via_payroll_entry = False
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@frappe.validate_and_sanitize_search_inputs
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
def get_payroll_entries_for_jv(doctype, txt, searchfield, start, page_len, filters):
|
def get_payroll_entries_for_jv(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
@ -38,6 +38,8 @@ from erpnext.payroll.doctype.salary_structure.salary_structure import make_salar
|
|||||||
class TestSalarySlip(unittest.TestCase):
|
class TestSalarySlip(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
setup_test()
|
setup_test()
|
||||||
|
frappe.flags.pop("via_payroll_entry", None)
|
||||||
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
frappe.db.rollback()
|
frappe.db.rollback()
|
||||||
@ -409,15 +411,17 @@ class TestSalarySlip(unittest.TestCase):
|
|||||||
"email_salary_slip_to_employee": 1
|
"email_salary_slip_to_employee": 1
|
||||||
})
|
})
|
||||||
def test_email_salary_slip(self):
|
def test_email_salary_slip(self):
|
||||||
frappe.db.sql("delete from `tabEmail Queue`")
|
frappe.db.delete("Email Queue")
|
||||||
|
|
||||||
make_employee("test_email_salary_slip@salary.com", company="_Test Company")
|
user_id = "test_email_salary_slip@salary.com"
|
||||||
ss = make_employee_salary_slip("test_email_salary_slip@salary.com", "Monthly", "Test Salary Slip Email")
|
|
||||||
|
make_employee(user_id, company="_Test Company")
|
||||||
|
ss = make_employee_salary_slip(user_id, "Monthly", "Test Salary Slip Email")
|
||||||
ss.company = "_Test Company"
|
ss.company = "_Test Company"
|
||||||
ss.save()
|
ss.save()
|
||||||
ss.submit()
|
ss.submit()
|
||||||
|
|
||||||
email_queue = frappe.db.sql("""select name from `tabEmail Queue`""")
|
email_queue = frappe.db.a_row_exists("Email Queue")
|
||||||
self.assertTrue(email_queue)
|
self.assertTrue(email_queue)
|
||||||
|
|
||||||
def test_loan_repayment_salary_slip(self):
|
def test_loan_repayment_salary_slip(self):
|
||||||
|
@ -1070,7 +1070,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(flt(this.frm.doc.conversion_rate)>0.0) {
|
if(flt(this.frm.doc.conversion_rate)>0.0) {
|
||||||
if(this.frm.doc.ignore_pricing_rule) {
|
if(this.frm.doc.__onload && this.frm.doc.__onload.ignore_price_list) {
|
||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
} else if (!this.in_apply_price_list){
|
} else if (!this.in_apply_price_list){
|
||||||
this.apply_price_list();
|
this.apply_price_list();
|
||||||
@ -1884,6 +1884,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(!r.exc) {
|
if(!r.exc) {
|
||||||
item.item_tax_rate = r.message;
|
item.item_tax_rate = r.message;
|
||||||
|
me.add_taxes_from_item_tax_template(item.item_tax_rate);
|
||||||
me.calculate_taxes_and_totals();
|
me.calculate_taxes_and_totals();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -608,6 +608,11 @@ function check_can_calculate_pending_qty(me) {
|
|||||||
&& doc.fg_completed_qty
|
&& doc.fg_completed_qty
|
||||||
&& erpnext.stock.bom
|
&& erpnext.stock.bom
|
||||||
&& erpnext.stock.bom.name === doc.bom_no;
|
&& erpnext.stock.bom.name === doc.bom_no;
|
||||||
const itemChecks = !!item && !item.allow_alternative_item;
|
const itemChecks = !!item
|
||||||
|
&& !item.allow_alternative_item
|
||||||
|
&& erpnext.stock.bom && erpnext.stock.items
|
||||||
|
&& (item.item_code in erpnext.stock.bom.items);
|
||||||
return docChecks && itemChecks;
|
return docChecks && itemChecks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//# sourceURL=serial_no_batch_selector.js
|
||||||
|
@ -264,6 +264,15 @@ body.product-page {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-lookup-input {
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid var(--gray-300);
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border: 1px solid var(--primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.filter-label {
|
.filter-label {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
@ -206,6 +206,7 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
|
|||||||
}, target_doc, set_missing_values, ignore_permissions=ignore_permissions)
|
}, target_doc, set_missing_values, ignore_permissions=ignore_permissions)
|
||||||
|
|
||||||
# postprocess: fetch shipping address, set missing values
|
# postprocess: fetch shipping address, set missing values
|
||||||
|
doclist.set_onload('ignore_price_list', True)
|
||||||
|
|
||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
@ -269,6 +270,8 @@ def _make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
|||||||
}
|
}
|
||||||
}, target_doc, set_missing_values, ignore_permissions=ignore_permissions)
|
}, target_doc, set_missing_values, ignore_permissions=ignore_permissions)
|
||||||
|
|
||||||
|
doclist.set_onload('ignore_price_list', True)
|
||||||
|
|
||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
def _make_customer(source_name, ignore_permissions=False):
|
def _make_customer(source_name, ignore_permissions=False):
|
||||||
|
@ -584,6 +584,8 @@ def make_delivery_note(source_name, target_doc=None, skip_item_mapping=False):
|
|||||||
|
|
||||||
target_doc = get_mapped_doc("Sales Order", source_name, mapper, target_doc, set_missing_values)
|
target_doc = get_mapped_doc("Sales Order", source_name, mapper, target_doc, set_missing_values)
|
||||||
|
|
||||||
|
target_doc.set_onload('ignore_price_list', True)
|
||||||
|
|
||||||
return target_doc
|
return target_doc
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@ -664,6 +666,8 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
|||||||
if automatically_fetch_payment_terms:
|
if automatically_fetch_payment_terms:
|
||||||
doclist.set_payment_schedule()
|
doclist.set_payment_schedule()
|
||||||
|
|
||||||
|
doclist.set_onload('ignore_price_list', True)
|
||||||
|
|
||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -21,9 +21,7 @@ default_mail_footer = """<div style="padding: 7px; text-align: right; color: #88
|
|||||||
def after_install():
|
def after_install():
|
||||||
frappe.get_doc({'doctype': "Role", "role_name": "Analytics"}).insert()
|
frappe.get_doc({'doctype': "Role", "role_name": "Analytics"}).insert()
|
||||||
set_single_defaults()
|
set_single_defaults()
|
||||||
create_compact_item_print_custom_field()
|
create_print_setting_custom_fields()
|
||||||
create_print_uom_after_qty_custom_field()
|
|
||||||
create_print_zero_amount_taxes_custom_field()
|
|
||||||
add_all_roles_to("Administrator")
|
add_all_roles_to("Administrator")
|
||||||
create_default_cash_flow_mapper_templates()
|
create_default_cash_flow_mapper_templates()
|
||||||
create_default_success_action()
|
create_default_success_action()
|
||||||
@ -77,7 +75,7 @@ def setup_currency_exchange():
|
|||||||
except frappe.ValidationError:
|
except frappe.ValidationError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def create_compact_item_print_custom_field():
|
def create_print_setting_custom_fields():
|
||||||
create_custom_field('Print Settings', {
|
create_custom_field('Print Settings', {
|
||||||
'label': _('Compact Item Print'),
|
'label': _('Compact Item Print'),
|
||||||
'fieldname': 'compact_item_print',
|
'fieldname': 'compact_item_print',
|
||||||
@ -85,9 +83,6 @@ def create_compact_item_print_custom_field():
|
|||||||
'default': 1,
|
'default': 1,
|
||||||
'insert_after': 'with_letterhead'
|
'insert_after': 'with_letterhead'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def create_print_uom_after_qty_custom_field():
|
|
||||||
create_custom_field('Print Settings', {
|
create_custom_field('Print Settings', {
|
||||||
'label': _('Print UOM after Quantity'),
|
'label': _('Print UOM after Quantity'),
|
||||||
'fieldname': 'print_uom_after_quantity',
|
'fieldname': 'print_uom_after_quantity',
|
||||||
@ -95,9 +90,6 @@ def create_print_uom_after_qty_custom_field():
|
|||||||
'default': 0,
|
'default': 0,
|
||||||
'insert_after': 'compact_item_print'
|
'insert_after': 'compact_item_print'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def create_print_zero_amount_taxes_custom_field():
|
|
||||||
create_custom_field('Print Settings', {
|
create_custom_field('Print Settings', {
|
||||||
'label': _('Print taxes with zero amount'),
|
'label': _('Print taxes with zero amount'),
|
||||||
'fieldname': 'print_taxes_with_zero_amount',
|
'fieldname': 'print_taxes_with_zero_amount',
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
"add_sample_data": 1,
|
|
||||||
"bank_account": "HDFC",
|
|
||||||
"company_abbr": "FT",
|
|
||||||
"company_name": "For Testing",
|
|
||||||
"company_tagline": "Just for GST",
|
|
||||||
"country": "India",
|
|
||||||
"currency": "INR",
|
|
||||||
"customer_1": "Test Customer 1",
|
|
||||||
"customer_2": "Test Customer 2",
|
|
||||||
"domains": ["Manufacturing"],
|
|
||||||
"email": "great@example.com",
|
|
||||||
"full_name": "Great Tester",
|
|
||||||
"fy_end_date": "2018-03-31",
|
|
||||||
"fy_start_date": "2017-04-01",
|
|
||||||
"is_purchase_item_1": 1,
|
|
||||||
"is_purchase_item_2": 1,
|
|
||||||
"is_purchase_item_3": 0,
|
|
||||||
"is_purchase_item_4": 0,
|
|
||||||
"is_purchase_item_5": 0,
|
|
||||||
"is_sales_item_1": 1,
|
|
||||||
"is_sales_item_2": 1,
|
|
||||||
"is_sales_item_3": 1,
|
|
||||||
"is_sales_item_4": 1,
|
|
||||||
"is_sales_item_5": 1,
|
|
||||||
"item_1": "Test Item 1",
|
|
||||||
"item_2": "Test Item 2",
|
|
||||||
"item_group_1": "Products",
|
|
||||||
"item_group_2": "Products",
|
|
||||||
"item_group_3": "Products",
|
|
||||||
"item_group_4": "Products",
|
|
||||||
"item_group_5": "Products",
|
|
||||||
"item_uom_1": "Unit",
|
|
||||||
"item_uom_2": "Unit",
|
|
||||||
"item_uom_3": "Unit",
|
|
||||||
"item_uom_4": "Unit",
|
|
||||||
"item_uom_5": "Unit",
|
|
||||||
"language": "English (United States)",
|
|
||||||
"password": "test",
|
|
||||||
"setup_website": 1,
|
|
||||||
"supplier_1": "Test Supplier 1",
|
|
||||||
"supplier_2": "Test Supplier 2",
|
|
||||||
"timezone": "Asia/Kolkata",
|
|
||||||
"user_accountant_1": 1,
|
|
||||||
"user_accountant_2": 1,
|
|
||||||
"user_accountant_3": 1,
|
|
||||||
"user_accountant_4": 1,
|
|
||||||
"user_purchaser_1": 1,
|
|
||||||
"user_purchaser_2": 1,
|
|
||||||
"user_purchaser_3": 1,
|
|
||||||
"user_purchaser_4": 1,
|
|
||||||
"user_sales_1": 1,
|
|
||||||
"user_sales_2": 1,
|
|
||||||
"user_sales_3": 1,
|
|
||||||
"user_sales_4": 1
|
|
||||||
}
|
|
@ -1,179 +0,0 @@
|
|||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
|
|
||||||
import frappe
|
|
||||||
import frappe.utils
|
|
||||||
from frappe import _
|
|
||||||
from frappe.utils.make_random import add_random_children
|
|
||||||
|
|
||||||
|
|
||||||
def make_sample_data(domains, make_dependent = False):
|
|
||||||
"""Create a few opportunities, quotes, material requests, issues, todos, projects
|
|
||||||
to help the user get started"""
|
|
||||||
|
|
||||||
if make_dependent:
|
|
||||||
items = frappe.get_all("Item", {'is_sales_item': 1})
|
|
||||||
customers = frappe.get_all("Customer")
|
|
||||||
warehouses = frappe.get_all("Warehouse")
|
|
||||||
|
|
||||||
if items and customers:
|
|
||||||
for i in range(3):
|
|
||||||
customer = random.choice(customers).name
|
|
||||||
make_opportunity(items, customer)
|
|
||||||
make_quote(items, customer)
|
|
||||||
|
|
||||||
if items and warehouses:
|
|
||||||
make_material_request(frappe.get_all("Item"))
|
|
||||||
|
|
||||||
make_projects(domains)
|
|
||||||
import_notification()
|
|
||||||
|
|
||||||
def make_opportunity(items, customer):
|
|
||||||
b = frappe.get_doc({
|
|
||||||
"doctype": "Opportunity",
|
|
||||||
"opportunity_from": "Customer",
|
|
||||||
"customer": customer,
|
|
||||||
"opportunity_type": _("Sales"),
|
|
||||||
"with_items": 1
|
|
||||||
})
|
|
||||||
|
|
||||||
add_random_children(b, "items", rows=len(items), randomize = {
|
|
||||||
"qty": (1, 5),
|
|
||||||
"item_code": ["Item"]
|
|
||||||
}, unique="item_code")
|
|
||||||
|
|
||||||
b.insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
b.add_comment('Comment', text="This is a dummy record")
|
|
||||||
|
|
||||||
def make_quote(items, customer):
|
|
||||||
qtn = frappe.get_doc({
|
|
||||||
"doctype": "Quotation",
|
|
||||||
"quotation_to": "Customer",
|
|
||||||
"party_name": customer,
|
|
||||||
"order_type": "Sales"
|
|
||||||
})
|
|
||||||
|
|
||||||
add_random_children(qtn, "items", rows=len(items), randomize = {
|
|
||||||
"qty": (1, 5),
|
|
||||||
"item_code": ["Item"]
|
|
||||||
}, unique="item_code")
|
|
||||||
|
|
||||||
qtn.insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
qtn.add_comment('Comment', text="This is a dummy record")
|
|
||||||
|
|
||||||
def make_material_request(items):
|
|
||||||
for i in items:
|
|
||||||
mr = frappe.get_doc({
|
|
||||||
"doctype": "Material Request",
|
|
||||||
"material_request_type": "Purchase",
|
|
||||||
"schedule_date": frappe.utils.add_days(frappe.utils.nowdate(), 7),
|
|
||||||
"items": [{
|
|
||||||
"schedule_date": frappe.utils.add_days(frappe.utils.nowdate(), 7),
|
|
||||||
"item_code": i.name,
|
|
||||||
"qty": 10
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
mr.insert()
|
|
||||||
mr.submit()
|
|
||||||
|
|
||||||
mr.add_comment('Comment', text="This is a dummy record")
|
|
||||||
|
|
||||||
|
|
||||||
def make_issue():
|
|
||||||
pass
|
|
||||||
|
|
||||||
def make_projects(domains):
|
|
||||||
current_date = frappe.utils.nowdate()
|
|
||||||
project = frappe.get_doc({
|
|
||||||
"doctype": "Project",
|
|
||||||
"project_name": "ERPNext Implementation",
|
|
||||||
})
|
|
||||||
|
|
||||||
tasks = [
|
|
||||||
{
|
|
||||||
"title": "Explore ERPNext",
|
|
||||||
"start_date": current_date,
|
|
||||||
"end_date": current_date,
|
|
||||||
"file": "explore.md"
|
|
||||||
}]
|
|
||||||
|
|
||||||
if 'Education' in domains:
|
|
||||||
tasks += [
|
|
||||||
{
|
|
||||||
"title": _("Setup your Institute in ERPNext"),
|
|
||||||
"start_date": current_date,
|
|
||||||
"end_date": frappe.utils.add_days(current_date, 1),
|
|
||||||
"file": "education_masters.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Setup Master Data",
|
|
||||||
"start_date": current_date,
|
|
||||||
"end_date": frappe.utils.add_days(current_date, 1),
|
|
||||||
"file": "education_masters.md"
|
|
||||||
}]
|
|
||||||
|
|
||||||
else:
|
|
||||||
tasks += [
|
|
||||||
{
|
|
||||||
"title": "Setup Your Company",
|
|
||||||
"start_date": current_date,
|
|
||||||
"end_date": frappe.utils.add_days(current_date, 1),
|
|
||||||
"file": "masters.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Start Tracking your Sales",
|
|
||||||
"start_date": current_date,
|
|
||||||
"end_date": frappe.utils.add_days(current_date, 2),
|
|
||||||
"file": "sales.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Start Managing Purchases",
|
|
||||||
"start_date": current_date,
|
|
||||||
"end_date": frappe.utils.add_days(current_date, 3),
|
|
||||||
"file": "purchase.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Import Data",
|
|
||||||
"start_date": current_date,
|
|
||||||
"end_date": frappe.utils.add_days(current_date, 4),
|
|
||||||
"file": "import_data.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Go Live!",
|
|
||||||
"start_date": current_date,
|
|
||||||
"end_date": frappe.utils.add_days(current_date, 5),
|
|
||||||
"file": "go_live.md"
|
|
||||||
}]
|
|
||||||
|
|
||||||
for t in tasks:
|
|
||||||
with open (os.path.join(os.path.dirname(__file__), "tasks", t['file'])) as f:
|
|
||||||
t['description'] = frappe.utils.md_to_html(f.read())
|
|
||||||
del t['file']
|
|
||||||
|
|
||||||
project.append('tasks', t)
|
|
||||||
|
|
||||||
project.insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
def import_notification():
|
|
||||||
'''Import notification for task start'''
|
|
||||||
with open (os.path.join(os.path.dirname(__file__), "tasks/task_alert.json")) as f:
|
|
||||||
notification = frappe.get_doc(json.loads(f.read())[0])
|
|
||||||
notification.insert()
|
|
||||||
|
|
||||||
# trigger the first message!
|
|
||||||
from frappe.email.doctype.notification.notification import trigger_daily_alerts
|
|
||||||
trigger_daily_alerts()
|
|
||||||
|
|
||||||
def test_sample():
|
|
||||||
frappe.db.sql('delete from `tabNotification`')
|
|
||||||
frappe.db.sql('delete from tabProject')
|
|
||||||
frappe.db.sql('delete from tabTask')
|
|
||||||
make_projects('Education')
|
|
||||||
import_notification()
|
|
@ -7,7 +7,6 @@ from frappe import _
|
|||||||
|
|
||||||
from .operations import company_setup
|
from .operations import company_setup
|
||||||
from .operations import install_fixtures as fixtures
|
from .operations import install_fixtures as fixtures
|
||||||
from .operations import sample_data
|
|
||||||
|
|
||||||
|
|
||||||
def get_setup_stages(args=None):
|
def get_setup_stages(args=None):
|
||||||
@ -103,16 +102,6 @@ def fin(args):
|
|||||||
frappe.local.message_log = []
|
frappe.local.message_log = []
|
||||||
login_as_first_user(args)
|
login_as_first_user(args)
|
||||||
|
|
||||||
make_sample_data(args.get('domains'))
|
|
||||||
|
|
||||||
def make_sample_data(domains):
|
|
||||||
try:
|
|
||||||
sample_data.make_sample_data(domains)
|
|
||||||
except Exception:
|
|
||||||
# clear message
|
|
||||||
if frappe.message_log:
|
|
||||||
frappe.message_log.pop()
|
|
||||||
pass
|
|
||||||
|
|
||||||
def login_as_first_user(args):
|
def login_as_first_user(args):
|
||||||
if args.get("email") and hasattr(frappe.local, "login_manager"):
|
if args.get("email") and hasattr(frappe.local, "login_manager"):
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
Lets start making things in ERPNext that are representative of your institution.
|
|
||||||
|
|
||||||
1. Make a list of **Programs** that you offer
|
|
||||||
1. Add a few **Courses** that your programs cover
|
|
||||||
1. Create **Academic Terms** and **Academic Years**
|
|
||||||
1. Start adding **Students**
|
|
||||||
1. Group your students into **Batches**
|
|
||||||
|
|
||||||
Watch this video to learn more about ERPNext Education: https://www.youtube.com/watch?v=f6foQOyGzdA
|
|
@ -1,7 +0,0 @@
|
|||||||
Thanks for checking this out! ❤️
|
|
||||||
|
|
||||||
If you are evaluating an ERP system for the first time, this is going to be quite a task! But don't worry, ERPNext is awesome.
|
|
||||||
|
|
||||||
First, get familiar with the surroundings. ERPNext covers a *lot of features*, go to the home page and click on the "Explore" icon.
|
|
||||||
|
|
||||||
All the best!
|
|
@ -1,18 +0,0 @@
|
|||||||
Ready to go live with ERPNext? 🏁🏁🏁
|
|
||||||
|
|
||||||
Here are the steps:
|
|
||||||
|
|
||||||
1. Sync up your **Chart of Accounts**
|
|
||||||
3. Add your opening stock using **Stock Reconciliation**
|
|
||||||
4. Add your open invoices (both sales and purchase)
|
|
||||||
3. Add your opening account balances by making a **Journal Entry**
|
|
||||||
|
|
||||||
If you need help for going live, sign up for an account at erpnext.com or find a partner to help you with this.
|
|
||||||
|
|
||||||
Or you can watch these videos 📺:
|
|
||||||
|
|
||||||
Setup your chart of accounts: https://www.youtube.com/watch?v=AcfMCT7wLLo
|
|
||||||
|
|
||||||
Add Open Stock: https://www.youtube.com/watch?v=nlHX0ZZ84Lw
|
|
||||||
|
|
||||||
Add Opening Balances: https://www.youtube.com/watch?v=nlHX0ZZ84Lw
|
|
@ -1,5 +0,0 @@
|
|||||||
Lets import some data! 💪💪
|
|
||||||
|
|
||||||
If you are already running a business, you most likely have your Items, Customers or Suppliers in some spreadsheet file somewhere, import it into ERPNext with the Data Import Tool.
|
|
||||||
|
|
||||||
Watch this video to get started: https://www.youtube.com/watch?v=Ta2Xx3QoK3E
|
|
@ -1,7 +0,0 @@
|
|||||||
Start building a model of your business in ERPNext by adding your Items and Customers.
|
|
||||||
|
|
||||||
These videos 📺 will help you get started:
|
|
||||||
|
|
||||||
Adding Customers and Suppliers: https://www.youtube.com/watch?v=zsrrVDk6VBs
|
|
||||||
|
|
||||||
Adding Items and Prices: https://www.youtube.com/watch?v=FcOsV-e8ymE
|
|
@ -1,10 +0,0 @@
|
|||||||
How to manage your purchasing in ERPNext 🛒🛒🛒:
|
|
||||||
|
|
||||||
1. Add a few **Suppliers**
|
|
||||||
2. Find out what you need by making **Material Requests**.
|
|
||||||
3. Now start placing orders via **Purchase Order**.
|
|
||||||
4. When your suppliers deliver, make **Purchase Receipts**
|
|
||||||
|
|
||||||
Now never run out of stock again! 😎
|
|
||||||
|
|
||||||
Watch this video 📺 to get an overview: https://www.youtube.com/watch?v=4TN9kPyfIqM
|
|
@ -1,8 +0,0 @@
|
|||||||
Start managing your sales with ERPNext 🔔🔔🔔:
|
|
||||||
|
|
||||||
1. Add potential business contacts as **Leads**
|
|
||||||
2. Udpate your deals in pipeline in **Opportunities**
|
|
||||||
3. Send proposals to your leads or customers with **Quotations**
|
|
||||||
4. Track confirmed orders with **Sales Orders**
|
|
||||||
|
|
||||||
Watch this video 📺 to get an overview: https://www.youtube.com/watch?v=o9XCSZHJfpA
|
|
@ -1,5 +0,0 @@
|
|||||||
Lets import some data! 💪💪
|
|
||||||
|
|
||||||
If you are already running a Institute, you most likely have your Students in some spreadsheet file somewhere. Import it into ERPNext with the Data Import Tool.
|
|
||||||
|
|
||||||
Watch this video to get started: https://www.youtube.com/watch?v=Ta2Xx3QoK3E
|
|
@ -1,28 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"attach_print": 0,
|
|
||||||
"condition": "doc.status in ('Open', 'Overdue')",
|
|
||||||
"date_changed": "exp_end_date",
|
|
||||||
"days_in_advance": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "Notification",
|
|
||||||
"document_type": "Task",
|
|
||||||
"enabled": 1,
|
|
||||||
"event": "Days After",
|
|
||||||
"is_standard": 0,
|
|
||||||
"message": "<p>Task due today:</p>\n\n<div>\n{{ doc.description }}\n</div>\n\n<hr>\n<p style=\"font-size: 85%\">\nThis is a notification for a task that is due today, and a sample <b>Notification</b>. In ERPNext you can setup notifications on anything, Invoices, Orders, Leads, Opportunities, so you never miss a thing.\n<br>To edit this, and setup other alerts, just type <b>Notification</b> in the search bar.</p>",
|
|
||||||
"method": null,
|
|
||||||
"modified": "2017-03-09 07:34:58.168370",
|
|
||||||
"module": null,
|
|
||||||
"name": "Task Due Alert",
|
|
||||||
"recipients": [
|
|
||||||
{
|
|
||||||
"cc": null,
|
|
||||||
"condition": null,
|
|
||||||
"email_by_document_field": "owner"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"subject": "{{ doc.subject }}",
|
|
||||||
"value_changed": null
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,12 +0,0 @@
|
|||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
from frappe.desk.page.setup_wizard.setup_wizard import setup_complete
|
|
||||||
|
|
||||||
|
|
||||||
def complete():
|
|
||||||
with open(os.path.join(os.path.dirname(__file__),
|
|
||||||
'data', 'test_mfg.json'), 'r') as f:
|
|
||||||
data = json.loads(f.read())
|
|
||||||
|
|
||||||
setup_complete(data)
|
|
@ -5,28 +5,17 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import add_days, flt, get_datetime_str, nowdate
|
from frappe.utils import add_days, flt, get_datetime_str, nowdate
|
||||||
|
from frappe.utils.data import now_datetime
|
||||||
|
from frappe.utils.nestedset import get_ancestors_of, get_root_of # noqa
|
||||||
|
|
||||||
from erpnext import get_default_company
|
from erpnext import get_default_company
|
||||||
|
|
||||||
|
|
||||||
def get_root_of(doctype):
|
|
||||||
"""Get root element of a DocType with a tree structure"""
|
|
||||||
result = frappe.db.sql_list("""select name from `tab%s`
|
|
||||||
where lft=1 and rgt=(select max(rgt) from `tab%s` where docstatus < 2)""" %
|
|
||||||
(doctype, doctype))
|
|
||||||
return result[0] if result else None
|
|
||||||
|
|
||||||
def get_ancestors_of(doctype, name):
|
|
||||||
"""Get ancestor elements of a DocType with a tree structure"""
|
|
||||||
lft, rgt = frappe.db.get_value(doctype, name, ["lft", "rgt"])
|
|
||||||
result = frappe.db.sql_list("""select name from `tab%s`
|
|
||||||
where lft<%s and rgt>%s order by lft desc""" % (doctype, "%s", "%s"), (lft, rgt))
|
|
||||||
return result or []
|
|
||||||
|
|
||||||
def before_tests():
|
def before_tests():
|
||||||
frappe.clear_cache()
|
frappe.clear_cache()
|
||||||
# complete setup if missing
|
# complete setup if missing
|
||||||
from frappe.desk.page.setup_wizard.setup_wizard import setup_complete
|
from frappe.desk.page.setup_wizard.setup_wizard import setup_complete
|
||||||
|
current_year = now_datetime().year
|
||||||
if not frappe.get_list("Company"):
|
if not frappe.get_list("Company"):
|
||||||
setup_complete({
|
setup_complete({
|
||||||
"currency" :"USD",
|
"currency" :"USD",
|
||||||
@ -36,8 +25,8 @@ def before_tests():
|
|||||||
"company_abbr" :"WP",
|
"company_abbr" :"WP",
|
||||||
"industry" :"Manufacturing",
|
"industry" :"Manufacturing",
|
||||||
"country" :"United States",
|
"country" :"United States",
|
||||||
"fy_start_date" :"2021-01-01",
|
"fy_start_date" :f"{current_year}-01-01",
|
||||||
"fy_end_date" :"2021-12-31",
|
"fy_end_date" :f"{current_year}-12-31",
|
||||||
"language" :"english",
|
"language" :"english",
|
||||||
"company_tagline" :"Testing",
|
"company_tagline" :"Testing",
|
||||||
"email" :"test@erpnext.com",
|
"email" :"test@erpnext.com",
|
||||||
@ -51,7 +40,6 @@ def before_tests():
|
|||||||
frappe.db.sql("delete from `tabSalary Slip`")
|
frappe.db.sql("delete from `tabSalary Slip`")
|
||||||
frappe.db.sql("delete from `tabItem Price`")
|
frappe.db.sql("delete from `tabItem Price`")
|
||||||
|
|
||||||
frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 0)
|
|
||||||
enable_all_roles_and_domains()
|
enable_all_roles_and_domains()
|
||||||
set_defaults_for_tests()
|
set_defaults_for_tests()
|
||||||
|
|
||||||
@ -142,13 +130,13 @@ def enable_all_roles_and_domains():
|
|||||||
add_all_roles_to('Administrator')
|
add_all_roles_to('Administrator')
|
||||||
|
|
||||||
def set_defaults_for_tests():
|
def set_defaults_for_tests():
|
||||||
from frappe.utils.nestedset import get_root_of
|
|
||||||
|
|
||||||
selling_settings = frappe.get_single("Selling Settings")
|
selling_settings = frappe.get_single("Selling Settings")
|
||||||
selling_settings.customer_group = get_root_of("Customer Group")
|
selling_settings.customer_group = get_root_of("Customer Group")
|
||||||
selling_settings.territory = get_root_of("Territory")
|
selling_settings.territory = get_root_of("Territory")
|
||||||
selling_settings.save()
|
selling_settings.save()
|
||||||
|
|
||||||
|
frappe.db.set_single_value("Stock Settings", "auto_insert_price_list_rate_if_missing", 0)
|
||||||
|
|
||||||
|
|
||||||
def insert_record(records):
|
def insert_record(records):
|
||||||
for r in records:
|
for r in records:
|
||||||
|
@ -519,6 +519,8 @@ def make_sales_invoice(source_name, target_doc=None):
|
|||||||
if automatically_fetch_payment_terms:
|
if automatically_fetch_payment_terms:
|
||||||
doc.set_payment_schedule()
|
doc.set_payment_schedule()
|
||||||
|
|
||||||
|
doc.set_onload('ignore_price_list', True)
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -823,6 +823,7 @@ def make_purchase_invoice(source_name, target_doc=None):
|
|||||||
}
|
}
|
||||||
}, target_doc, set_missing_values)
|
}, target_doc, set_missing_values)
|
||||||
|
|
||||||
|
doclist.set_onload('ignore_price_list', True)
|
||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
def get_invoiced_qty_map(purchase_receipt):
|
def get_invoiced_qty_map(purchase_receipt):
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import ValidationError, _
|
from frappe import ValidationError, _
|
||||||
@ -574,22 +575,30 @@ def get_delivery_note_serial_no(item_code, qty, delivery_note):
|
|||||||
return serial_nos
|
return serial_nos
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def auto_fetch_serial_number(qty, item_code, warehouse,
|
def auto_fetch_serial_number(
|
||||||
posting_date=None, batch_nos=None, for_doctype=None, exclude_sr_nos=None):
|
qty: float,
|
||||||
|
item_code: str,
|
||||||
|
warehouse: str,
|
||||||
|
posting_date: Optional[str] = None,
|
||||||
|
batch_nos: Optional[Union[str, List[str]]] = None,
|
||||||
|
for_doctype: Optional[str] = None,
|
||||||
|
exclude_sr_nos: Optional[List[str]] = None
|
||||||
|
) -> List[str]:
|
||||||
|
|
||||||
filters = frappe._dict({"item_code": item_code, "warehouse": warehouse})
|
filters = frappe._dict({"item_code": item_code, "warehouse": warehouse})
|
||||||
|
|
||||||
if exclude_sr_nos is None:
|
if exclude_sr_nos is None:
|
||||||
exclude_sr_nos = []
|
exclude_sr_nos = []
|
||||||
else:
|
else:
|
||||||
|
exclude_sr_nos = safe_json_loads(exclude_sr_nos)
|
||||||
exclude_sr_nos = get_serial_nos(clean_serial_no_string("\n".join(exclude_sr_nos)))
|
exclude_sr_nos = get_serial_nos(clean_serial_no_string("\n".join(exclude_sr_nos)))
|
||||||
|
|
||||||
if batch_nos:
|
if batch_nos:
|
||||||
batch_nos = safe_json_loads(batch_nos)
|
batch_nos = safe_json_loads(batch_nos)
|
||||||
if isinstance(batch_nos, list):
|
if isinstance(batch_nos, list):
|
||||||
filters.batch_no = batch_nos
|
filters.batch_no = batch_nos
|
||||||
elif isinstance(batch_nos, str):
|
else:
|
||||||
filters.batch_no = [batch_nos]
|
filters.batch_no = [str(batch_nos)]
|
||||||
|
|
||||||
if posting_date:
|
if posting_date:
|
||||||
filters.expiry_date = posting_date
|
filters.expiry_date = posting_date
|
||||||
|
@ -274,7 +274,8 @@ class TestSerialNo(FrappeTestCase):
|
|||||||
msg=f"{partial_fetch} should be subset of {first_fetch}")
|
msg=f"{partial_fetch} should be subset of {first_fetch}")
|
||||||
|
|
||||||
# exclusion
|
# exclusion
|
||||||
remaining = auto_fetch_serial_number(3, item_code, warehouse, exclude_sr_nos=partial_fetch)
|
remaining = auto_fetch_serial_number(3, item_code, warehouse,
|
||||||
|
exclude_sr_nos=json.dumps(partial_fetch))
|
||||||
self.assertEqual(sorted(remaining + partial_fetch), first_fetch)
|
self.assertEqual(sorted(remaining + partial_fetch), first_fetch)
|
||||||
|
|
||||||
# batchwise
|
# batchwise
|
||||||
|
@ -52,24 +52,6 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
frappe.ready(() => {
|
|
||||||
$('.product-filter-filter').on('keydown', frappe.utils.debounce((e) => {
|
|
||||||
const $input = $(e.target);
|
|
||||||
const keyword = ($input.val() || '').toLowerCase();
|
|
||||||
const $filter_options = $input.next('.filter-options');
|
|
||||||
|
|
||||||
$filter_options.find('.custom-control').show();
|
|
||||||
$filter_options.find('.custom-control').each((i, el) => {
|
|
||||||
const $el = $(el);
|
|
||||||
const value = $el.data('value').toLowerCase();
|
|
||||||
if (!value.includes(keyword)) {
|
|
||||||
$el.hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 300));
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -300,13 +300,13 @@
|
|||||||
|
|
||||||
{% if values | len > 20 %}
|
{% if values | len > 20 %}
|
||||||
<!-- show inline filter if values more than 20 -->
|
<!-- show inline filter if values more than 20 -->
|
||||||
<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
|
<input type="text" class="form-control form-control-sm mb-2 filter-lookup-input" placeholder="Search {{ item_field.label + 's' }}"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if values %}
|
{% if values %}
|
||||||
<div class="filter-options">
|
<div class="filter-options">
|
||||||
{% for value in values %}
|
{% for value in values %}
|
||||||
<div class="checkbox" data-value="{{ value }}">
|
<div class="filter-lookup-wrapper checkbox" data-value="{{ value }}">
|
||||||
<label for="{{value}}">
|
<label for="{{value}}">
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
class="product-filter field-filter"
|
class="product-filter field-filter"
|
||||||
@ -329,16 +329,16 @@
|
|||||||
{%- macro attribute_filter_section(filters)-%}
|
{%- macro attribute_filter_section(filters)-%}
|
||||||
{% for attribute in filters %}
|
{% for attribute in filters %}
|
||||||
<div class="mb-4 filter-block pb-5">
|
<div class="mb-4 filter-block pb-5">
|
||||||
<div class="filter-label mb-3">{{ attribute.name}}</div>
|
<div class="filter-label mb-3">{{ attribute.name }}</div>
|
||||||
{% if values | len > 20 %}
|
{% if attribute.item_attribute_values | len > 20 %}
|
||||||
<!-- show inline filter if values more than 20 -->
|
<!-- show inline filter if values more than 20 -->
|
||||||
<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
|
<input type="text" class="form-control form-control-sm mb-2 filter-lookup-input" placeholder="Search {{ attribute.name + 's' }}"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if attribute.item_attribute_values %}
|
{% if attribute.item_attribute_values %}
|
||||||
<div class="filter-options">
|
<div class="filter-options">
|
||||||
{% for attr_value in attribute.item_attribute_values %}
|
{% for attr_value in attribute.item_attribute_values %}
|
||||||
<div class="checkbox">
|
<div class="filter-lookup-wrapper checkbox" data-value="{{ attr_value }}">
|
||||||
<label data-value="{{ attr_value }}">
|
<label data-value="{{ attr_value }}">
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
class="product-filter attribute-filter"
|
class="product-filter attribute-filter"
|
||||||
|
@ -31,24 +31,6 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
frappe.ready(() => {
|
|
||||||
$('.product-filter-filter').on('keydown', frappe.utils.debounce((e) => {
|
|
||||||
const $input = $(e.target);
|
|
||||||
const keyword = ($input.val() || '').toLowerCase();
|
|
||||||
const $filter_options = $input.next('.filter-options');
|
|
||||||
|
|
||||||
$filter_options.find('.custom-control').show();
|
|
||||||
$filter_options.find('.custom-control').each((i, el) => {
|
|
||||||
const $el = $(el);
|
|
||||||
const value = $el.data('value').toLowerCase();
|
|
||||||
if (!value.includes(keyword)) {
|
|
||||||
$el.hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 300));
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user