[ Major ] Loyalty Program Fixes (#14863)
* fix checking of customer_group & territory of customer in loyalty program * fetch and set applicable loyalty program - in customer.py if found 1 program, set it or show a message to set it manually - in sales invoice, if found 1 program for selected customer with no program set, set it else open a dialog with applicable options * removed disabled field, added from_date & to_date * loyalty program section made collapsible, added redeem check in it * setting loyalty program improvised, manual selection if multiple found * get_query added, amount calculation updated * args passed rectified for expiry_date * get loyalty_points logic improv, redemption_details logic added * improv based on from/to date and other rectification * code rectified based on different scenarios - is_return, cancel, make loyalty points entry improv
This commit is contained in:
parent
9a3b785a03
commit
5899d98077
@ -13,15 +13,22 @@ class LoyaltyPointEntry(Document):
|
||||
pass
|
||||
|
||||
|
||||
def get_loyalty_point_entries(customer, loyalty_program, expiry_date=None, company=None):
|
||||
def get_loyalty_point_entries(customer, loyalty_program, company, expiry_date=None):
|
||||
if not expiry_date:
|
||||
date = today()
|
||||
args_list = [customer, loyalty_program, expiry_date]
|
||||
condition = ''
|
||||
if company:
|
||||
condition = " and company=%s "
|
||||
args_list.append(company)
|
||||
loyalty_point_details = frappe.db.sql('''select name, loyalty_points, expiry_date, loyalty_program_tier
|
||||
from `tabLoyalty Point Entry` where customer=%s and loyalty_program=%s and expiry_date>=%s and loyalty_points>0
|
||||
{condition} order by expiry_date'''.format(condition=condition), tuple(args_list), as_dict=1)
|
||||
return loyalty_point_details
|
||||
|
||||
return frappe.db.sql('''
|
||||
select name, loyalty_points, expiry_date, loyalty_program_tier
|
||||
from `tabLoyalty Point Entry`
|
||||
where customer=%s and loyalty_program=%s
|
||||
and expiry_date>=%s and loyalty_points>0 and company=%s
|
||||
order by expiry_date
|
||||
''', (customer, loyalty_program, expiry_date, company), as_dict=1)
|
||||
|
||||
def get_redemption_details(customer, loyalty_program, company):
|
||||
return frappe._dict(frappe.db.sql('''
|
||||
select redeem_against, sum(loyalty_points)
|
||||
from `tabLoyalty Point Entry`
|
||||
where customer=%s and loyalty_program=%s and loyalty_points<0 and company=%s
|
||||
group by redeem_against
|
||||
''', (customer, loyalty_program, company)))
|
||||
|
@ -15,128 +15,7 @@
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "disabled",
|
||||
"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": "Disabled",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "auto_opt_in",
|
||||
"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": "Auto Opt In (For all customers)",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"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
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -164,10 +43,11 @@
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -200,6 +80,72 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fieldname": "from_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "From Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "to_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "To Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -230,6 +176,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -262,6 +209,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -294,6 +242,39 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "auto_opt_in",
|
||||
"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": "Auto Opt In (For all customers)",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -325,6 +306,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -357,6 +339,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -388,6 +371,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -420,6 +404,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -451,6 +436,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -481,6 +467,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -513,6 +500,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -545,6 +533,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -577,6 +566,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -608,6 +598,7 @@
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -648,7 +639,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-03-21 10:20:25.468206",
|
||||
"modified": "2018-07-10 19:15:24.994385",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Loyalty Program",
|
||||
@ -657,7 +648,6 @@
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
@ -683,5 +673,6 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
@ -16,14 +16,17 @@ class LoyaltyProgram(Document):
|
||||
def get_loyalty_details(customer, loyalty_program, expiry_date=None, company=None):
|
||||
if not expiry_date:
|
||||
expiry_date = today()
|
||||
args_list = [customer, loyalty_program, expiry_date]
|
||||
|
||||
args_list = [customer, loyalty_program, expiry_date, expiry_date]
|
||||
condition = ''
|
||||
if company:
|
||||
condition = " and company=%s "
|
||||
args_list.append(company)
|
||||
loyalty_point_details = frappe.db.sql('''select sum(loyalty_points) as loyalty_points,
|
||||
sum(purchase_amount) as total_spent from `tabLoyalty Point Entry`
|
||||
where customer=%s and loyalty_program=%s and (expiry_date>=%s) {condition}
|
||||
where customer=%s and loyalty_program=%s
|
||||
and expiry_date>=%s and posting_date <= %s
|
||||
{condition}
|
||||
group by customer'''.format(condition=condition), tuple(args_list), as_dict=1)
|
||||
if loyalty_point_details:
|
||||
return loyalty_point_details[0]
|
||||
@ -33,35 +36,28 @@ def get_loyalty_details(customer, loyalty_program, expiry_date=None, company=Non
|
||||
@frappe.whitelist()
|
||||
def get_loyalty_program_details(customer, loyalty_program=None, expiry_date=None, company=None, silent=False):
|
||||
lp_details = frappe._dict()
|
||||
customer_loyalty_program = frappe.db.get_value("Customer", customer, "loyalty_program")
|
||||
|
||||
if not (customer_loyalty_program or silent):
|
||||
frappe.throw(_("Customer isn't enrolled in any Loyalty Program"))
|
||||
elif silent and not customer_loyalty_program:
|
||||
return frappe._dict({"loyalty_program": None})
|
||||
|
||||
if loyalty_program and loyalty_program != customer_loyalty_program:
|
||||
frappe.throw(_("Customer isn't enrolled in this Loyalty Program"))
|
||||
|
||||
if not loyalty_program:
|
||||
loyalty_program = customer_loyalty_program
|
||||
loyalty_program = frappe.db.get_value("Customer", customer, "loyalty_program")
|
||||
|
||||
if not (loyalty_program or silent):
|
||||
frappe.throw(_("Customer isn't enrolled in any Loyalty Program"))
|
||||
elif silent and not loyalty_program:
|
||||
return frappe._dict({"loyalty_program": None})
|
||||
|
||||
if not company:
|
||||
company = frappe.db.get_default("company") or frappe.get_all("Company")[0].name
|
||||
|
||||
lp_details.update(get_loyalty_details(customer, loyalty_program, expiry_date, company))
|
||||
loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program)
|
||||
lp_details.update({"loyalty_program": loyalty_program.name})
|
||||
lp_details.update(loyalty_program.as_dict())
|
||||
|
||||
lp_details.update({"loyalty_program": loyalty_program})
|
||||
loyalty_program = frappe.get_doc("Loyalty Program", lp_details.loyalty_program)
|
||||
lp_details.update(get_loyalty_details(customer, loyalty_program.name, expiry_date, company))
|
||||
|
||||
lp_details.expiry_duration = loyalty_program.expiry_duration
|
||||
lp_details.conversion_factor = loyalty_program.conversion_factor
|
||||
lp_details.expense_account = loyalty_program.expense_account
|
||||
lp_details.cost_center = loyalty_program.cost_center
|
||||
lp_details.company = loyalty_program.company
|
||||
|
||||
tier_spent_level = sorted([d.as_dict() for d in loyalty_program.collection_rules], key=lambda rule:rule.min_spent, reverse=True)
|
||||
tier_spent_level = sorted([d.as_dict() for d in loyalty_program.collection_rules],
|
||||
key=lambda rule:rule.min_spent, reverse=True)
|
||||
for i, d in enumerate(tier_spent_level):
|
||||
if i==0 or lp_details.total_spent < d.min_spent:
|
||||
if i == 0 or lp_details.total_spent < d.min_spent:
|
||||
lp_details.tier_name = d.tier_name
|
||||
lp_details.collection_factor = d.collection_factor
|
||||
else:
|
||||
@ -122,4 +118,4 @@ def validate_loyalty_points(ref_doc, points_to_redeem):
|
||||
ref_doc.loyalty_redemption_cost_center = loyalty_program_details.cost_center
|
||||
|
||||
elif ref_doc.doctype == "Sales Order":
|
||||
return loyalty_amount
|
||||
return loyalty_amount
|
||||
|
@ -230,6 +230,20 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
}, function() {
|
||||
me.apply_pricing_rule();
|
||||
});
|
||||
|
||||
if(this.frm.doc.customer) {
|
||||
frappe.call({
|
||||
"method": "erpnext.accounts.doctype.sales_invoice.sales_invoice.get_loyalty_programs",
|
||||
"args": {
|
||||
"customer": this.frm.doc.customer
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
select_loyalty_program(me.frm, r.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
make_inter_company_invoice: function() {
|
||||
@ -530,10 +544,6 @@ cur_frm.set_query("asset", "items", function(doc, cdt, cdn) {
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Sales Invoice', {
|
||||
refresh: function(frm) {
|
||||
frm.add_fetch('customer', 'loyalty_program', 'loyalty_program');
|
||||
},
|
||||
|
||||
setup: function(frm){
|
||||
|
||||
frm.custom_make_buttons = {
|
||||
@ -598,6 +608,24 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// set get_query for loyalty redemption account
|
||||
frm.fields_dict["loyalty_redemption_account"].get_query = function() {
|
||||
return {
|
||||
filters:{
|
||||
"company": frm.doc.company
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// set get_query for loyalty redemption cost center
|
||||
frm.fields_dict["loyalty_redemption_cost_center"].get_query = function() {
|
||||
return {
|
||||
filters:{
|
||||
"company": frm.doc.company
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
//When multiple companies are set up. in case company name is changed set default company address
|
||||
company:function(frm){
|
||||
@ -661,18 +689,15 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
method: "erpnext.accounts.doctype.loyalty_program.loyalty_program.get_loyalty_program_details",
|
||||
args: {
|
||||
"customer": frm.doc.customer,
|
||||
"till_date": frm.doc.posting_date,
|
||||
"loyalty_program": frm.doc.loyalty_program,
|
||||
"expiry_date": frm.doc.posting_date,
|
||||
"company": frm.doc.company
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r) {
|
||||
frm.set_value("loyalty_program", r.message.loyalty_program);
|
||||
frm.set_value("loyalty_redemption_account", r.message.expense_account);
|
||||
frm.set_value("loyalty_redemption_cost_center", r.message.cost_center);
|
||||
frm.redemption_conversion_factor = r.message.conversion_factor;
|
||||
// let max_loyalty_points = parseInt((frm.doc.grand_total-frm.doc.total_advance)/r.message.conversion_factor);
|
||||
// let redeemable_points = max_loyalty_points > r.message.loyalty_points ? r.message.loyalty_points : max_loyalty_points;
|
||||
// frm.set_value("loyalty_points", redeemable_points);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -682,10 +707,10 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
set_loyalty_points: function(frm) {
|
||||
if (frm.redemption_conversion_factor) {
|
||||
let loyalty_amount = flt(frm.redemption_conversion_factor*flt(frm.doc.loyalty_points), precision("loyalty_amount"));
|
||||
var remaining_amount = flt(frm.doc.grand_total - frm.doc.total_advance)
|
||||
var remaining_amount = flt(frm.doc.grand_total) - flt(frm.doc.total_advance) - flt(frm.doc.write_off_amount);
|
||||
if (frm.doc.grand_total && (remaining_amount < loyalty_amount)) {
|
||||
let redeemable_amount = parseInt(remaining_amount/frm.redemption_conversion_factor);
|
||||
frappe.throw(__("You can only redeem max {0} points in this order.",[redeemable_amount]));
|
||||
let redeemable_points = parseInt(remaining_amount/frm.redemption_conversion_factor);
|
||||
frappe.throw(__("You can only redeem max {0} points in this order.",[redeemable_points]));
|
||||
}
|
||||
frm.set_value("loyalty_amount", loyalty_amount);
|
||||
}
|
||||
@ -729,3 +754,34 @@ var calculate_total_billing_amount = function(frm) {
|
||||
|
||||
refresh_field('total_billing_amount')
|
||||
}
|
||||
|
||||
var select_loyalty_program = function(frm, loyalty_programs) {
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
title: __("Select Loyalty Program"),
|
||||
fields: [
|
||||
{
|
||||
"label": __("Loyalty Program"),
|
||||
"fieldname": "loyalty_program",
|
||||
"fieldtype": "Select",
|
||||
"options": loyalty_programs,
|
||||
"default": loyalty_programs[0]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
dialog.set_primary_action(__("Set"), function() {
|
||||
dialog.hide();
|
||||
return frappe.call({
|
||||
method: "frappe.client.set_value",
|
||||
args: {
|
||||
doctype: "Customer",
|
||||
name: frm.doc.customer,
|
||||
fieldname: "loyalty_program",
|
||||
value: dialog.get_value("loyalty_program"),
|
||||
},
|
||||
callback: function(r) { }
|
||||
});
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
@ -381,38 +381,6 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "redeem_loyalty_points",
|
||||
"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": "Redeem Loyalty Points",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
@ -2460,10 +2428,10 @@
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "",
|
||||
"columns": 0,
|
||||
"depends_on": "redeem_loyalty_points",
|
||||
"depends_on": "",
|
||||
"fieldname": "loyalty_points_redemption",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -2496,6 +2464,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "redeem_loyalty_points",
|
||||
"fieldname": "loyalty_points",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
@ -2528,6 +2497,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "redeem_loyalty_points",
|
||||
"fieldname": "loyalty_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
@ -2560,6 +2530,38 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "redeem_loyalty_points",
|
||||
"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": "Redeem Loyalty Points",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_77",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -2591,6 +2593,8 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fetch_from": "customer.loyalty_program",
|
||||
"fieldname": "loyalty_program",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2624,6 +2628,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "redeem_loyalty_points",
|
||||
"fieldname": "loyalty_redemption_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2657,6 +2662,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "redeem_loyalty_points",
|
||||
"fieldname": "loyalty_redemption_cost_center",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -5376,7 +5382,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-07-06 18:15:09.600814",
|
||||
"modified": "2018-07-10 19:28:04.351108",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
@ -163,6 +163,7 @@ class SalesInvoice(SellingController):
|
||||
elif self.is_return and self.return_against and self.loyalty_program:
|
||||
against_si_doc = frappe.get_doc("Sales Invoice", self.return_against)
|
||||
against_si_doc.delete_loyalty_point_entry()
|
||||
against_si_doc.make_loyalty_point_entry()
|
||||
if self.redeem_loyalty_points and self.loyalty_points:
|
||||
self.apply_loyalty_points()
|
||||
|
||||
@ -209,6 +210,7 @@ class SalesInvoice(SellingController):
|
||||
self.delete_loyalty_point_entry()
|
||||
elif self.is_return and self.return_against and self.loyalty_program:
|
||||
against_si_doc = frappe.get_doc("Sales Invoice", self.return_against)
|
||||
against_si_doc.delete_loyalty_point_entry()
|
||||
against_si_doc.make_loyalty_point_entry()
|
||||
|
||||
unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
|
||||
@ -967,24 +969,28 @@ class SalesInvoice(SellingController):
|
||||
|
||||
# collection of the loyalty points, create the ledger entry for that.
|
||||
def make_loyalty_point_entry(self):
|
||||
loyalty_program_details = get_loyalty_program_details(self.customer, company=self.company)
|
||||
if loyalty_program_details:
|
||||
points_earned = int(self.grand_total/loyalty_program_details.collection_factor)
|
||||
lp_details = get_loyalty_program_details(self.customer, company=self.company,
|
||||
loyalty_program=self.loyalty_program, expiry_date=self.posting_date)
|
||||
if lp_details and getdate(lp_details.from_date) <= getdate(self.posting_date) and \
|
||||
(not lp_details.to_date or getdate(lp_details.to_date) >= getdate(self.posting_date)):
|
||||
returned_amount = self.get_returned_amount()
|
||||
eligible_amount = flt(self.grand_total) - cint(self.loyalty_amount) - returned_amount
|
||||
points_earned = cint(eligible_amount/lp_details.collection_factor)
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Loyalty Point Entry",
|
||||
"company": self.company,
|
||||
"loyalty_program": loyalty_program_details.loyalty_program,
|
||||
"loyalty_program_tier": loyalty_program_details.tier_name,
|
||||
"loyalty_program": lp_details.loyalty_program,
|
||||
"loyalty_program_tier": lp_details.tier_name,
|
||||
"customer": self.customer,
|
||||
"sales_invoice": self.name,
|
||||
"loyalty_points": points_earned,
|
||||
"purchase_amount": self.grand_total,
|
||||
"expiry_date": add_days(self.posting_date, loyalty_program_details.expiry_duration),
|
||||
"purchase_amount": eligible_amount,
|
||||
"expiry_date": add_days(self.posting_date, lp_details.expiry_duration),
|
||||
"posting_date": self.posting_date
|
||||
})
|
||||
doc.flags.ignore_permissions = 1
|
||||
doc.save()
|
||||
# frappe.db.set_value("Customer", self.customer, "loyalty_program_tier", loyalty_program_details.tier_name)
|
||||
frappe.db.set_value("Customer", self.customer, "loyalty_program_tier", lp_details.tier_name)
|
||||
|
||||
# valdite the redemption and then delete the loyalty points earned on cancel of the invoice
|
||||
def delete_loyalty_point_entry(self):
|
||||
@ -998,19 +1004,33 @@ class SalesInvoice(SellingController):
|
||||
First cancel the Sales Invoice No {0}''').format(invoice_list))
|
||||
else:
|
||||
frappe.db.sql('''delete from `tabLoyalty Point Entry` where sales_invoice=%s''', (self.name))
|
||||
# Set loyalty program
|
||||
lp_details = get_loyalty_program_details(self.customer, company=self.company,
|
||||
loyalty_program=self.loyalty_program, expiry_date=self.posting_date)
|
||||
frappe.db.set_value("Customer", self.customer, "loyalty_program_tier", lp_details.tier_name)
|
||||
|
||||
def get_returned_amount(self):
|
||||
returned_amount = frappe.db.sql("""
|
||||
select sum(grand_total)
|
||||
from `tabSales Invoice`
|
||||
where docstatus=1 and is_return=1 and ifnull(return_against, '')=%s
|
||||
""", self.name)
|
||||
return flt(returned_amount[0][0]) if returned_amount else 0
|
||||
|
||||
# redeem the loyalty points.
|
||||
def apply_loyalty_points(self):
|
||||
from erpnext.accounts.doctype.loyalty_point_entry.loyalty_point_entry \
|
||||
import get_loyalty_point_entries
|
||||
loyalty_point_entries = get_loyalty_point_entries(self.customer, self.loyalty_program, self.posting_date, self.company)
|
||||
import get_loyalty_point_entries, get_redemption_details
|
||||
loyalty_point_entries = get_loyalty_point_entries(self.customer, self.loyalty_program, self.company, self.posting_date)
|
||||
redemption_details = get_redemption_details(self.customer, self.loyalty_program, self.company)
|
||||
|
||||
points_to_redeem = self.loyalty_amount
|
||||
points_to_redeem = self.loyalty_points
|
||||
for lp_entry in loyalty_point_entries:
|
||||
if lp_entry.loyalty_points > points_to_redeem:
|
||||
available_points = lp_entry.loyalty_points - redemption_details.get(lp_entry.name)
|
||||
if available_points > points_to_redeem:
|
||||
redeemed_points = points_to_redeem
|
||||
else:
|
||||
redeemed_points = lp_entry.loyalty_points
|
||||
redeemed_points = available_points
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Loyalty Point Entry",
|
||||
"company": self.company,
|
||||
@ -1019,7 +1039,7 @@ class SalesInvoice(SellingController):
|
||||
"customer": self.customer,
|
||||
"sales_invoice": self.name,
|
||||
"redeem_against": lp_entry.name,
|
||||
"loyalty_points": -(redeemed_points),
|
||||
"loyalty_points": -1*redeemed_points,
|
||||
"purchase_amount": self.grand_total,
|
||||
"expiry_date": lp_entry.expiry_date,
|
||||
"posting_date": self.posting_date
|
||||
@ -1312,3 +1332,19 @@ def make_inter_company_invoice(doctype, source_name, target_doc=None):
|
||||
}, target_doc, set_missing_values)
|
||||
|
||||
return doclist
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_loyalty_programs(customer):
|
||||
''' sets applicable loyalty program to the customer or returns a list of applicable programs '''
|
||||
from erpnext.selling.doctype.customer.customer import get_loyalty_programs
|
||||
|
||||
customer = frappe.get_doc('Customer', customer)
|
||||
if customer.loyalty_program: return
|
||||
|
||||
lp_details = get_loyalty_programs(customer)
|
||||
|
||||
if len(lp_details) == 1:
|
||||
frappe.db.set(customer, 'loyalty_program', lp_details[0])
|
||||
return []
|
||||
else:
|
||||
return lp_details
|
||||
|
@ -6,7 +6,7 @@ import frappe
|
||||
from frappe.model.naming import set_name_by_naming_series
|
||||
from frappe import _, msgprint, throw
|
||||
import frappe.defaults
|
||||
from frappe.utils import flt, cint, cstr
|
||||
from frappe.utils import flt, cint, cstr, today
|
||||
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
|
||||
@ -188,16 +188,33 @@ class Customer(TransactionBase):
|
||||
frappe.db.set(self, "customer_name", newdn)
|
||||
|
||||
def set_loyalty_program(self):
|
||||
if not self.loyalty_program:
|
||||
loyalty_programs = frappe.get_all("Loyalty Program", fields=["name", "customer_group",
|
||||
"customer_territory"], filters={"auto_opt_in": 1, "disabled": 0})
|
||||
from frappe.desk.treeview import get_children
|
||||
for loyalty_program in loyalty_programs:
|
||||
customer_groups = get_children("Customer Group", loyalty_program.customer_group, )
|
||||
if self.customer_group in customer_groups and\
|
||||
self.territory in get_children("Territory", loyalty_program.customer_territory):
|
||||
self.loyalty_program = loyalty_program.name
|
||||
if self.loyalty_program: return
|
||||
loyalty_program = get_loyalty_programs(self)
|
||||
if not loyalty_program: return
|
||||
if len(loyalty_program) == 1:
|
||||
self.loyalty_program = loyalty_program[0]
|
||||
else:
|
||||
frappe.msgprint(_("Multiple Loyalty Program found for the Customer. Please select manually."))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_loyalty_programs(doc):
|
||||
''' returns applicable loyalty programs for a customer '''
|
||||
from frappe.desk.treeview import get_children
|
||||
|
||||
lp_details = []
|
||||
loyalty_programs = frappe.get_all("Loyalty Program",
|
||||
fields=["name", "customer_group", "customer_territory"],
|
||||
filters={"auto_opt_in": 1, "from_date": ["<=", today()],
|
||||
"ifnull(to_date, '2500-01-01')": [">=", today()]})
|
||||
|
||||
for loyalty_program in loyalty_programs:
|
||||
customer_groups = [d.value for d in get_children("Customer Group", loyalty_program.customer_group)]
|
||||
customer_territories = [d.value for d in get_children("Territory", loyalty_program.customer_territory)]
|
||||
if (not loyalty_program.customer_group or doc.customer_group in customer_groups)\
|
||||
and (not loyalty_program.customer_territory or doc.territory in customer_territories):
|
||||
lp_details.append(loyalty_program.name)
|
||||
|
||||
return lp_details
|
||||
|
||||
def get_customer_list(doctype, txt, searchfield, start, page_len, filters=None):
|
||||
if frappe.db.get_default("cust_master_name") == "Customer Name":
|
||||
|
@ -129,7 +129,7 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
method: "erpnext.accounts.doctype.loyalty_program.loyalty_program.get_loyalty_program_details",
|
||||
args: {
|
||||
"customer": me.frm.doc.customer,
|
||||
"till_date": me.frm.doc.posting_date,
|
||||
"expiry_date": me.frm.doc.posting_date,
|
||||
"company": me.frm.doc.company,
|
||||
"silent": true
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user