feat: Grant commission on certain items only (#27467)

Co-authored-by: Sagar Vora <sagar@resilient.tech>
This commit is contained in:
Raffael Meyer 2021-11-30 13:24:18 +01:00 committed by GitHub
parent d0f4f03b66
commit e10ab1626c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 190 additions and 66 deletions

View File

@ -171,6 +171,7 @@
"sales_team_section_break",
"sales_partner",
"column_break10",
"amount_eligible_for_commission",
"commission_rate",
"total_commission",
"section_break2",
@ -1561,16 +1562,23 @@
"label": "Coupon Code",
"options": "Coupon Code",
"print_hide": 1
},
{
"fieldname": "amount_eligible_for_commission",
"fieldtype": "Currency",
"label": "Amount Eligible for Commission",
"read_only": 1
}
],
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
"modified": "2021-08-27 20:12:57.306772",
"modified": "2021-10-05 12:11:53.871828",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
"name_case": "Title Case",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{

View File

@ -46,6 +46,7 @@
"base_amount",
"pricing_rules",
"is_free_item",
"grant_commission",
"section_break_21",
"net_rate",
"net_amount",
@ -800,14 +801,22 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
},
{
"default": "0",
"fieldname": "grant_commission",
"fieldtype": "Check",
"label": "Grant Commission",
"read_only": 1
}
],
"istable": 1,
"links": [],
"modified": "2021-01-04 17:34:49.924531",
"modified": "2021-10-05 12:23:47.506290",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice Item",
"naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",

View File

@ -182,6 +182,7 @@
"sales_team_section_break",
"sales_partner",
"column_break10",
"amount_eligible_for_commission",
"commission_rate",
"total_commission",
"section_break2",
@ -2019,6 +2020,12 @@
"label": "Total Billing Hours",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "amount_eligible_for_commission",
"fieldtype": "Currency",
"label": "Amount Eligible for Commission",
"read_only": 1
}
],
"icon": "fa fa-file-text",
@ -2031,7 +2038,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2021-10-11 20:19:38.667508",
"modified": "2021-10-21 20:19:38.667508",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
@ -2086,4 +2093,4 @@
"title_field": "title",
"track_changes": 1,
"track_seen": 1
}
}

View File

@ -2385,6 +2385,29 @@ class TestSalesInvoice(unittest.TestCase):
si.reload()
self.assertEqual(si.status, "Paid")
def test_sales_commission(self):
si = frappe.copy_doc(test_records[0])
item = copy.deepcopy(si.get('items')[0])
item.update({
"qty": 1,
"rate": 500,
"grant_commission": 1
})
si.append("items", item)
# Test valid values
for commission_rate, total_commission in ((0, 0), (10, 50), (100, 500)):
si.commission_rate = commission_rate
si.save()
self.assertEqual(si.amount_eligible_for_commission, 500)
self.assertEqual(si.total_commission, total_commission)
# Test invalid values
for commission_rate in (101, -1):
si.reload()
si.commission_rate = commission_rate
self.assertRaises(frappe.ValidationError, si.save)
def test_sales_invoice_submission_post_account_freezing_date(self):
frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', add_days(getdate(), 1))
si = create_sales_invoice(do_not_save=True)

View File

@ -47,6 +47,7 @@
"pricing_rules",
"stock_uom_rate",
"is_free_item",
"grant_commission",
"section_break_21",
"net_rate",
"net_amount",
@ -828,15 +829,23 @@
"fieldtype": "Link",
"label": "Discount Account",
"options": "Account"
},
{
"default": "0",
"fieldname": "grant_commission",
"fieldtype": "Check",
"label": "Grant Commission",
"read_only": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-08-19 13:41:53.435827",
"modified": "2021-10-05 12:24:54.968907",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
"naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",

View File

@ -1,27 +1,30 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2013-05-06 12:28:23",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-03-06 05:52:57.645281",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Partners Commission",
"owner": "Administrator",
"query": "SELECT\n sales_partner as \"Sales Partner:Link/Sales Partner:150\",\n\tsum(base_net_total) as \"Invoiced Amount (Exclusive Tax):Currency:210\",\n\tsum(total_commission) as \"Total Commission:Currency:150\",\n\tsum(total_commission)*100/sum(base_net_total) as \"Average Commission Rate:Currency:170\"\nFROM\n\t`tabSales Invoice`\nWHERE\n\tdocstatus = 1 and ifnull(base_net_total, 0) > 0 and ifnull(total_commission, 0) > 0\nGROUP BY\n\tsales_partner\nORDER BY\n\t\"Total Commission:Currency:120\"",
"ref_doctype": "Sales Invoice",
"report_name": "Sales Partners Commission",
"report_type": "Query Report",
"add_total_row": 0,
"columns": [],
"creation": "2013-05-06 12:28:23",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 3,
"is_standard": "Yes",
"modified": "2021-10-06 06:26:07.881340",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Partners Commission",
"owner": "Administrator",
"prepared_report": 0,
"query": "SELECT\n sales_partner as \"Sales Partner:Link/Sales Partner:220\",\n\tsum(base_net_total) as \"Invoiced Amount (Excl. Tax):Currency:220\",\n\tsum(amount_eligible_for_commission) as \"Amount Eligible for Commission:Currency:220\",\n\tsum(total_commission) as \"Total Commission:Currency:170\",\n\tsum(total_commission)*100/sum(amount_eligible_for_commission) as \"Average Commission Rate:Percent:220\"\nFROM\n\t`tabSales Invoice`\nWHERE\n\tdocstatus = 1 and ifnull(base_net_total, 0) > 0 and ifnull(total_commission, 0) > 0\nGROUP BY\n\tsales_partner\nORDER BY\n\t\"Total Commission:Currency:120\"",
"ref_doctype": "Sales Invoice",
"report_name": "Sales Partners Commission",
"report_type": "Query Report",
"roles": [
{
"role": "Accounts Manager"
},
},
{
"role": "Accounts User"
}
]
}
}

View File

@ -250,7 +250,12 @@ class AccountsController(TransactionBase):
from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals
calculate_taxes_and_totals(self)
if self.doctype in ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]:
if self.doctype in (
'Sales Order',
'Delivery Note',
'Sales Invoice',
'POS Invoice',
):
self.calculate_commission()
self.calculate_contribution()

View File

@ -120,13 +120,27 @@ class SellingController(StockController):
self.in_words = money_in_words(amount, self.currency)
def calculate_commission(self):
if self.meta.get_field("commission_rate"):
self.round_floats_in(self, ["base_net_total", "commission_rate"])
if self.commission_rate > 100.0:
throw(_("Commission rate cannot be greater than 100"))
if not self.meta.get_field("commission_rate"):
return
self.total_commission = flt(self.base_net_total * self.commission_rate / 100.0,
self.precision("total_commission"))
self.round_floats_in(
self, ("amount_eligible_for_commission", "commission_rate")
)
if not (0 <= self.commission_rate <= 100.0):
throw("{} {}".format(
_(self.meta.get_label("commission_rate")),
_("must be between 0 and 100"),
))
self.amount_eligible_for_commission = sum(
item.base_net_amount for item in self.items if item.grant_commission
)
self.total_commission = flt(
self.amount_eligible_for_commission * self.commission_rate / 100.0,
self.precision("total_commission")
)
def calculate_contribution(self):
if not self.meta.get_field("sales_team"):
@ -138,7 +152,7 @@ class SellingController(StockController):
self.round_floats_in(sales_person)
sales_person.allocated_amount = flt(
self.base_net_total * sales_person.allocated_percentage / 100.0,
self.amount_eligible_for_commission * sales_person.allocated_percentage / 100.0,
self.precision("allocated_amount", sales_person))
if sales_person.commission_rate:

View File

@ -134,6 +134,7 @@
"sales_team_section_break",
"sales_partner",
"column_break7",
"amount_eligible_for_commission",
"commission_rate",
"total_commission",
"section_break1",
@ -1507,16 +1508,23 @@
"fieldtype": "Small Text",
"label": "Dispatch Address",
"read_only": 1
},
{
"fieldname": "amount_eligible_for_commission",
"fieldtype": "Currency",
"label": "Amount Eligible for Commission",
"read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
"modified": "2021-09-28 13:09:51.515542",
"modified": "2021-10-05 12:16:40.775704",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{

View File

@ -48,6 +48,7 @@
"pricing_rules",
"stock_uom_rate",
"is_free_item",
"grant_commission",
"section_break_24",
"net_rate",
"net_amount",
@ -789,15 +790,23 @@
"no_copy": 1,
"options": "currency",
"read_only": 1
},
{
"default": "0",
"fieldname": "grant_commission",
"fieldtype": "Check",
"label": "Grant Commission",
"read_only": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-02-23 01:15:05.803091",
"modified": "2021-10-05 12:27:25.014789",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",
"naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",

View File

@ -157,25 +157,19 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
commission_rate() {
this.calculate_commission();
refresh_field("total_commission");
}
total_commission() {
if(this.frm.doc.base_net_total) {
frappe.model.round_floats_in(this.frm.doc, ["base_net_total", "total_commission"]);
frappe.model.round_floats_in(this.frm.doc, ["amount_eligible_for_commission", "total_commission"]);
if(this.frm.doc.base_net_total < this.frm.doc.total_commission) {
var msg = (__("[Error]") + " " +
__(frappe.meta.get_label(this.frm.doc.doctype, "total_commission",
this.frm.doc.name)) + " > " +
__(frappe.meta.get_label(this.frm.doc.doctype, "base_net_total", this.frm.doc.name)));
frappe.msgprint(msg);
throw msg;
}
const { amount_eligible_for_commission } = this.frm.doc;
if(!amount_eligible_for_commission) return;
this.frm.set_value("commission_rate",
flt(this.frm.doc.total_commission * 100.0 / this.frm.doc.base_net_total));
}
this.frm.set_value(
"commission_rate", flt(
this.frm.doc.total_commission * 100.0 / amount_eligible_for_commission
)
);
}
allocated_percentage(doc, cdt, cdn) {
@ -185,7 +179,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
sales_person.allocated_percentage = flt(sales_person.allocated_percentage,
precision("allocated_percentage", sales_person));
sales_person.allocated_amount = flt(this.frm.doc.base_net_total *
sales_person.allocated_amount = flt(this.frm.doc.amount_eligible_for_commission *
sales_person.allocated_percentage / 100.0,
precision("allocated_amount", sales_person));
refresh_field(["allocated_amount"], sales_person);
@ -259,28 +253,39 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
}
calculate_commission() {
if(this.frm.fields_dict.commission_rate) {
if(this.frm.doc.commission_rate > 100) {
var msg = __(frappe.meta.get_label(this.frm.doc.doctype, "commission_rate", this.frm.doc.name)) +
" " + __("cannot be greater than 100");
frappe.msgprint(msg);
throw msg;
}
if(!this.frm.fields_dict.commission_rate) return;
this.frm.doc.total_commission = flt(this.frm.doc.base_net_total * this.frm.doc.commission_rate / 100.0,
precision("total_commission"));
if(this.frm.doc.commission_rate > 100) {
this.frm.set_value("commission_rate", 100);
frappe.throw(`${__(frappe.meta.get_label(
this.frm.doc.doctype, "commission_rate", this.frm.doc.name
))} ${__("cannot be greater than 100")}`);
}
this.frm.doc.amount_eligible_for_commission = this.frm.doc.items.reduce(
(sum, item) => item.grant_commission ? sum + item.base_net_amount : sum, 0
)
this.frm.doc.total_commission = flt(
this.frm.doc.amount_eligible_for_commission * this.frm.doc.commission_rate / 100.0,
precision("total_commission")
);
refresh_field(["amount_eligible_for_commission", "total_commission"]);
}
calculate_contribution() {
var me = this;
$.each(this.frm.doc.doctype.sales_team || [], function(i, sales_person) {
frappe.model.round_floats_in(sales_person);
if(sales_person.allocated_percentage) {
sales_person.allocated_amount = flt(
me.frm.doc.base_net_total * sales_person.allocated_percentage / 100.0,
precision("allocated_amount", sales_person));
}
if (!sales_person.allocated_percentage) return;
sales_person.allocated_amount = flt(
me.frm.doc.amount_eligible_for_commission
* sales_person.allocated_percentage
/ 100.0,
precision("allocated_amount", sales_person)
);
});
}

View File

@ -145,6 +145,7 @@
"sales_team_section_break",
"sales_partner",
"column_break7",
"amount_eligible_for_commission",
"commission_rate",
"total_commission",
"section_break1",
@ -1302,6 +1303,12 @@
"label": "Dispatch Address",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "amount_eligible_for_commission",
"fieldtype": "Currency",
"label": "Amount Eligible for Commission",
"read_only": 1
}
],
"icon": "fa fa-truck",
@ -1312,6 +1319,7 @@
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{

View File

@ -49,6 +49,7 @@
"pricing_rules",
"stock_uom_rate",
"is_free_item",
"grant_commission",
"section_break_25",
"net_rate",
"net_amount",
@ -753,13 +754,20 @@
"no_copy": 1,
"options": "currency",
"read_only": 1
},
{
"default": "0",
"fieldname": "grant_commission",
"fieldtype": "Check",
"label": "Grant Commission",
"read_only": 1
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-10-05 12:12:44.018872",
"modified": "2021-10-06 12:12:44.018872",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",

View File

@ -88,6 +88,7 @@
"sales_details",
"sales_uom",
"is_sales_item",
"grant_commission",
"column_break3",
"max_discount",
"deferred_revenue",
@ -1020,6 +1021,12 @@
"fieldname": "website_image_alt",
"fieldtype": "Data",
"label": "Image Description"
},
{
"default": "1",
"fieldname": "grant_commission",
"fieldtype": "Check",
"label": "Grant Commission"
}
],
"has_web_view": 1,
@ -1028,7 +1035,7 @@
"image_field": "image",
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-11-30 01:33:06.572442",
"modified": "2021-11-30 02:33:06.572442",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@ -327,7 +327,8 @@ def get_basic_details(args, item, overwrite_warehouse=True):
"against_blanket_order": args.get("against_blanket_order"),
"bom_no": item.get("default_bom"),
"weight_per_unit": args.get("weight_per_unit") or item.get("weight_per_unit"),
"weight_uom": args.get("weight_uom") or item.get("weight_uom")
"weight_uom": args.get("weight_uom") or item.get("weight_uom"),
"grant_commission": item.get("grant_commission")
})
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):