Skip to content

Commit f1790d2

Browse files
committed
feat: sales commission
1 parent 876d6ab commit f1790d2

File tree

2 files changed

+93
-33
lines changed

2 files changed

+93
-33
lines changed

erpnext/payroll/doctype/sales_commission/sales_commission.json

+8-7
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"commission_against",
2121
"omit_sales_person_transactions",
2222
"column_break_14",
23-
"filtro",
23+
"commission_against_filter",
2424
"section_break_10",
2525
"from_date",
2626
"to_date",
@@ -245,24 +245,25 @@
245245
"fieldname": "commission_against",
246246
"fieldtype": "Link",
247247
"label": "Comisionar Sobre",
248+
"mandatory_depends_on": "eval:doc.omit_sales_person_transactions == 1;",
248249
"options": "DocType"
249250
},
251+
{
252+
"fieldname": "column_break_14",
253+
"fieldtype": "Column Break"
254+
},
250255
{
251256
"depends_on": "eval:doc.omit_sales_person_transactions == 1;",
252-
"fieldname": "filtro",
257+
"fieldname": "commission_against_filter",
253258
"fieldtype": "Dynamic Link",
254259
"label": "Filtro",
255260
"options": "commission_against"
256-
},
257-
{
258-
"fieldname": "column_break_14",
259-
"fieldtype": "Column Break"
260261
}
261262
],
262263
"index_web_pages_for_search": 1,
263264
"is_submittable": 1,
264265
"links": [],
265-
"modified": "2024-09-30 13:48:21.649556",
266+
"modified": "2024-09-30 14:33:15.176817",
266267
"modified_by": "Administrator",
267268
"module": "Payroll",
268269
"name": "Sales Commission",

erpnext/payroll/doctype/sales_commission/sales_commission.py

+85-26
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import frappe
55
import erpnext
66
from frappe import _
7-
from frappe.utils import get_link_to_form
7+
from frappe.utils import get_link_to_form, flt, nowdate
88
from erpnext.accounts.general_ledger import make_gl_entries
99
from erpnext.controllers.accounts_controller import (
1010
AccountsController,
@@ -13,14 +13,32 @@
1313
class SalesCommission(AccountsController):
1414
def validate(self):
1515
self.validate_from_to_dates()
16-
16+
self.validate_omit_transaction_duplicates()
1717
self.validate_salary_component()
1818
self.calculate_total_contribution_and_total_commission_amount()
1919
self.create_employee()
2020

2121
def validate_from_to_dates(self):
2222
return super().validate_from_to_dates("from_date", "to_date")
2323

24+
def validate_omit_transaction_duplicates(self):
25+
# TODO chequear por solapamiento de fechas
26+
if not self.omit_sales_person_transactions:
27+
return
28+
29+
previous_contibutions = frappe.get_all(
30+
"Sales Commission",
31+
filters={
32+
"sales_person": self.sales_person,
33+
"docstatus": 1,
34+
"from_date": self.from_date,
35+
"to_date": self.to_date,
36+
},
37+
pluck="name"
38+
)
39+
if previous_contibutions:
40+
frappe.throw(_("Este vendedor ya tiene liquidado ventas en el período seleccionado"))
41+
2442
def validate_amount(self):
2543
if self.total_commission_amount <= 0:
2644
frappe.throw(_("Total Commission Amount should be greater than 0"))
@@ -46,15 +64,15 @@ def make_gl_entries(self, cancel=False):
4664
def get_gl_entries(self):
4765
gl_entry = []
4866

49-
sales_commission_expense_account = frappe.get_value("Company", self.company, "sales_commission_expense_account") # DEBIT
50-
payment_account_sales_commission = frappe.get_value("Company", self.company, "payment_account_sales_commission") # CREDIT
67+
sales_commission_expense_account = frappe.get_value("Company", self.company, "sales_commission_expense_account")
68+
payment_account_sales_commission = frappe.get_value("Company", self.company, "payment_account_sales_commission")
5169

5270
if not sales_commission_expense_account or not payment_account_sales_commission:
5371
frappe.throw(_("Debe configurar la Cuenta de Pago Comisión Vendedores y la Cuenta de Gastos Comisión Vendedores en la Compañia."))
5472

5573
gl_entry.append(
5674
self.get_gl_dict({
57-
"posting_date": self.creation.date(),
75+
"posting_date": nowdate(),
5876
"account": payment_account_sales_commission,
5977
"credit": self.total_commission_amount,
6078
"credit_in_account_currency": self.total_commission_amount,
@@ -69,7 +87,7 @@ def get_gl_entries(self):
6987

7088
gl_entry.append(
7189
self.get_gl_dict({
72-
"posting_date": self.creation.date(),
90+
"posting_date": nowdate(),
7391
"account": sales_commission_expense_account,
7492
"debit": self.total_commission_amount,
7593
"debit_in_account_currency": self.total_commission_amount,
@@ -86,28 +104,69 @@ def add_contributions(self, process_sales_commission):
86104
self.set("contributions", [])
87105
filter_date = "transaction_date" if self.commission_based_on == "Sales Order" else "posting_date"
88106
customer_field = "customer" if self.commission_based_on != "Payment Entry" else "party"
89-
records = [entry.name for entry in frappe.db.get_all(self.commission_based_on, filters={"company": self.company, "docstatus": 1, filter_date: ('between', [self.from_date, self.to_date])})]
90-
sales_persons_details = frappe.get_all(
91-
"Sales Team", filters={"parent": ['in', records], "sales_person": self.sales_person},
92-
fields=["sales_person", "commission_rate", "incentives", "allocated_percentage", "allocated_amount", "parent"])
93-
if sales_persons_details:
94-
for record in sales_persons_details:
95-
if add_record(record, self.sales_person):
96-
record_details = frappe.db.get_value(self.commission_based_on, filters={"name": record["parent"]}, fieldname=[customer_field, filter_date], as_dict=True)
97-
contribution = {
98-
"document_type": self.commission_based_on,
99-
"order_or_invoice": record["parent"],
100-
"customer": record_details.get(customer_field),
101-
"posting_date": record_details[filter_date],
102-
"contribution_percent": record["allocated_percentage"],
103-
"contribution_amount": record["allocated_amount"],
104-
"commission_rate": record["commission_rate"],
105-
"commission_amount": record["incentives"],
106-
"process_sales_commission": process_sales_commission,
107-
}
108-
self.append("contributions", contribution)
107+
108+
if self.omit_sales_person_transactions:
109+
filter_fieldname = self.get_filter_commission_against_field()
110+
filter_value = self.commission_against_filter
111+
commission_rate = frappe.get_value("Sales Person", self.sales_person, "commission_rate")
112+
filter_value_sql = f"AND {filter_fieldname} = '{filter_value}'" if filter_fieldname and filter_value else ""
113+
records = frappe.db.sql(f"""
114+
SELECT {filter_fieldname} AS commission_filter, SUM(total) AS allocated_amount
115+
FROM `tab{self.commission_based_on}`
116+
WHERE docstatus = 1
117+
AND company = '{self.company}'
118+
AND {filter_date} BETWEEN '{self.from_date}' AND '{self.to_date}'
119+
{filter_value_sql}
120+
GROUP BY {filter_fieldname}
121+
""", as_dict=True)
122+
123+
commission_rate = frappe.get_value("Sales Person", self.sales_person, "commission_rate")
124+
125+
for record in records:
126+
record['commission_rate'] = commission_rate
127+
record['incentives'] = flt(record['allocated_amount'] * flt(commission_rate) / 100.0, self.precision("total_contribution"))
128+
record['allocated_percentage'] = 100
129+
contribution = {
130+
"commission_filter": record["commission_filter"],
131+
"contribution_percent": record["allocated_percentage"],
132+
"contribution_amount": record["allocated_amount"],
133+
"commission_rate": record["commission_rate"],
134+
"commission_amount": record["incentives"],
135+
"process_sales_commission": process_sales_commission,
136+
}
137+
self.append("contributions", contribution)
138+
else:
139+
records = [entry.name for entry in frappe.db.get_all(self.commission_based_on, filters={"company": self.company, "docstatus": 1, filter_date: ('between', [self.from_date, self.to_date])})]
140+
141+
sales_persons_details = frappe.get_all(
142+
"Sales Team", filters={"parent": ['in', records], "sales_person": self.sales_person},
143+
fields=["sales_person", "commission_rate", "incentives", "allocated_percentage", "allocated_amount", "parent"])
144+
145+
if sales_persons_details:
146+
for record in sales_persons_details:
147+
if add_record(record, self.sales_person):
148+
record_details = frappe.db.get_value(self.commission_based_on, filters={"name": record["parent"]}, fieldname=[customer_field, filter_date], as_dict=True)
149+
contribution = {
150+
"document_type": self.commission_based_on,
151+
"order_or_invoice": record["parent"],
152+
"customer": record_details.get(customer_field),
153+
"posting_date": record_details[filter_date],
154+
"contribution_percent": record["allocated_percentage"],
155+
"contribution_amount": record["allocated_amount"],
156+
"commission_rate": record["commission_rate"],
157+
"commission_amount": record["incentives"],
158+
"process_sales_commission": process_sales_commission,
159+
}
160+
self.append("contributions", contribution)
109161
self.calculate_total_contribution_and_total_commission_amount()
110162

163+
def get_filter_commission_against_field(self):
164+
commission_based_on_meta = frappe.get_meta(self.commission_based_on)
165+
for field in commission_based_on_meta.fields:
166+
if field.fieldtype == "Link" and field.options == self.commission_against:
167+
return field.fieldname
168+
frappe.throw(f"{self.commission_based_on} no tiene campo {self.commission_against}")
169+
111170
def calculate_total_contribution_and_total_commission_amount(self):
112171
total_contribution, total_commission_amount = 0, 0
113172
for entry in self.contributions:

0 commit comments

Comments
 (0)