Skip to content

Commit

Permalink
feat: Add Employee Cost to Daily P&L
Browse files Browse the repository at this point in the history
  • Loading branch information
jabir-tridz committed Jan 9, 2024
1 parent 8e0b96d commit 70c457e
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 31 deletions.
1 change: 1 addition & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- Direct Expenses: The sum of consumables and other direct fixed expenses.
- Cost of Goods Sold: This includes the cost of the items sold, factoring in product bundles and Bill of Materials (BOM) sub-items.
- Gross Profit/Loss: The difference between gross sales and the cost of goods sold.
- Employee Cost: The total Employee Cost for the day, including wages, salaries, benefits, and any other related expenses. This cost is part of the Total Indirect Expense.
- Indirect Expenses: The total of indirect fixed expenses and any percentage-based expenses.
- Net Profit/Loss: The final profit or loss for the day.

Expand Down
25 changes: 24 additions & 1 deletion SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,27 @@ Follow these steps to set up URY Pulse after completing basic ERPNext configurat
- **Expense** : Provide the expense name.
- **Percentage Type** : Choose the percentage type (Net Sales or Gross Sales).
- **Percent** : Specify the percentage of the selected type.
- **Depreciation** : Add depreciation amount if applicable.
- Under **Employee Costs**:
- **Employee Costs** : Table to list daily fixed expenses as a part of employee costs.
- **Expense** : Provide the expense name.
- **Amount** : Specify amount for each expense.
- **Depreciation** : Add depreciation amount if applicable.


### Daily Gross Salary Cost is calculated from employees attendance.

Follow these steps to set up the payment type and payment amount for employees:

#### Step 1:

- Navigate to **Employee** in your site.
- Choose the relevant **Employee**.

#### Step 2:

- Under the **Salary** tab:
- **Payment Type** : Choose between Salary or Daily Wage.
- **Payment Amount** : Enter the corresponding payment amount.


Follow the [Attendance documentation](https://frappehr.com/docs/v14/en/attendance#3-features) for marking the attendance or use the [Employee Attendance Tool](https://frappehr.com/docs/v14/en/employee-attendance-tool#2-how-to-mark-attendance-using-employee-attendance-tool)
110 changes: 110 additions & 0 deletions ury_pulse/fixtures/custom_field.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
[
{
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"default": null,
"depends_on": null,
"description": null,
"docstatus": 0,
"doctype": "Custom Field",
"dt": "Employee",
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "payment_type",
"fieldtype": "Select",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"insert_after": "salary_currency",
"is_system_generated": 0,
"is_virtual": 0,
"label": "Payment Type",
"length": 0,
"mandatory_depends_on": null,
"modified": "2024-01-09 14:49:44.365494",
"module": null,
"name": "Employee-payment_type",
"no_copy": 0,
"non_negative": 0,
"options": "\nDaily Wage\nSalary",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"sort_options": 0,
"translatable": 0,
"unique": 0,
"width": null
},
{
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"default": null,
"depends_on": null,
"description": null,
"docstatus": 0,
"doctype": "Custom Field",
"dt": "Employee",
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "payment_amount",
"fieldtype": "Currency",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"insert_after": "payment_type",
"is_system_generated": 0,
"is_virtual": 0,
"label": "Payment Amount",
"length": 0,
"mandatory_depends_on": null,
"modified": "2024-01-09 15:27:00.294408",
"module": null,
"name": "Employee-payment_amount",
"no_copy": 0,
"non_negative": 0,
"options": null,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"sort_options": 0,
"translatable": 0,
"unique": 0,
"width": null
}
]
16 changes: 16 additions & 0 deletions ury_pulse/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,19 @@
# auth_hooks = [
# "ury_pulse.auth.validate"
# ]

fixtures = [
{
"doctype": "Custom Field",
"filters": [
[
"name",
"in",
{
"Employee-payment_amount",
"Employee-payment_type",
},
]
],
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ <h4 class="ellipsis" style="color: rgb(0, 0, 0);">Date: {{ data.date }}</h4>
<td>{{ frappe.utils.fmt_money(data.gross_profit or '', currency=currency) }}</td>
<td>{{ data.gross_profit_percent }}%</td>
</tr>
<!-- <tr>
<tr>
<td class="text-left font-bold">{{ _('Employee Cost') }}</td>
<td>{{ frappe.utils.fmt_money(data.total_employee_costs or '', currency=currency) }}</td>
<td>{{ data.total_employee_costs_percent }}%</td>
</tr> -->
</tr>
{% for expense in data.indirect_expenses_breakup %}
<tr>
<td class="text-left font-bold">{{ expense.breakup }}</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,6 @@
"depends_on": "eval:doc.docstatus==1",
"fieldname": "total_employee_costs",
"fieldtype": "Currency",
"hidden": 1,
"label": "Employee Cost",
"precision": "2",
"read_only": 1
Expand All @@ -378,7 +377,6 @@
"depends_on": "eval:doc.docstatus==1",
"fieldname": "total_employee_costs_percent",
"fieldtype": "Percent",
"hidden": 1,
"label": "Employee Cost Percent",
"read_only": 1
},
Expand All @@ -402,7 +400,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-11-15 00:18:37.012201",
"modified": "2024-01-09 14:15:52.566841",
"modified_by": "Administrator",
"module": "URY Pulse",
"name": "URY Daily P and L",
Expand Down
110 changes: 108 additions & 2 deletions ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ def before_submit(self):
self.net_sales = self.gross_sales - self.cash_discount_round_off - self.tax

if self.net_sales == 0.0:
self.gross_sales_percent = self.cash_discount_round_off_percent = self.tax_percent = self.cogs_percent = self.total_direct_expenses_percent = self.gross_profit_percent = self.other_expenses_percent = self.depreciation_percent = self.total_indirect_expenses_percent = self.net_profit_percent = 0.0
self.gross_sales_percent = self.cash_discount_round_off_percent = self.tax_percent = self.cogs_percent = self.total_direct_expenses_percent = self.gross_profit_percent = self.total_employee_costs_percent = self.other_expenses_percent = self.depreciation_percent = self.total_indirect_expenses_percent = self.net_profit_percent = 0.0
else:
self.gross_sales_percent = round(((self.gross_sales / self.net_sales) * 100),2)
self.cash_discount_round_off_percent = round(((self.cash_discount_round_off / self.net_sales) * 100),2)
Expand Down Expand Up @@ -298,9 +298,115 @@ def before_submit(self):

'''INDIRECT EXPENSES'''

self.total_indirect_expenses = 0


#EMPLOYEE COSTS
salary_cost_gross = 0
self.total_employee_costs = 0

attendance_count = frappe.db.sql('''
SELECT
%(date)s AS "Date",
COUNT(b.`name`) AS "Total Attendance"
FROM `tabAttendance` b
LEFT JOIN `tabEmployee` c ON
c.name = b.employee
WHERE
b.`attendance_date` = %(date)s
AND c.`branch` = %(branch)s
AND b.`docstatus` = 1
AND b.`status` IN ("Present", "Half Day")
''', {"branch": self.branch, "date": self.date}, as_dict=True)

attendance_count = attendance_count[0]

if attendance_count['Total Attendance'] == 0:
frappe.throw(title='No Attendance !',msg=("Attendance not marked"))

ns_employee_attendance_list = frappe.db.sql('''
SELECT
b.`employee_name` AS "Name"
FROM `tabAttendance` b
LEFT JOIN `tabEmployee` c ON (
c.name = b.employee
AND (
(c.`payment_amount` IS NULL OR c.`payment_amount` = 0.0 )
OR
(c.`payment_type` IS NULL OR c.`payment_type` = "")
)
)
WHERE
b.`attendance_date` = %(date)s
AND c.`branch` = %(branch)s
GROUP BY
b.`employee_name`
''', {"branch": self.branch, "date": self.date}, as_dict=True)

if len(ns_employee_attendance_list) > 0:
ns_employee_attendance_list = json.dumps(ns_employee_attendance_list)
frappe.throw(title='Set Payment Type/Amount',msg=("Employees: {0}").format(ns_employee_attendance_list))

employee_attendance_dw_list = frappe.db.sql('''
SELECT
%(date)s AS "Date",
b.`employee` AS "Employee",
b.`status` AS "Status",
c.`payment_amount` AS "Salary"
FROM `tabAttendance` b
LEFT JOIN `tabEmployee` c ON c.name = b.employee
WHERE
b.`attendance_date` = %(date)s
AND c.`branch` = %(branch)s
AND c.`payment_type` = "Daily Wage"
''', {"branch": self.branch, "date": self.date}, as_dict=True)

for attendance in employee_attendance_dw_list:
if attendance["Status"] == "Half Day":
salary_cost_gross = round((salary_cost_gross + 0.5 * attendance["Salary"]),2)
if attendance["Status"] == "Present":
salary_cost_gross = round((salary_cost_gross + attendance["Salary"]),2)

date_str = self.date
date_obj = datetime.strptime(date_str, '%Y-%m-%d')
year = date_obj.year
month_number = date_obj.month
days = calendar.monthrange(year, month_number)[1]

employee_attendance_sl_list = frappe.db.sql('''
SELECT
%(date)s AS "Date",
b.`name` AS "Employee",
b.`payment_amount` AS "Salary"
FROM `tabEmployee` b
WHERE
b.`branch` = %(branch)s
AND b.`payment_type` = "Salary"
''', {"branch": self.branch, "date": self.date}, as_dict=True)

for attendance in employee_attendance_sl_list:
salary_cost_gross = round((salary_cost_gross + attendance["Salary"]/days),2)

if self.net_sales != 0.0:
salary_cost_gross_percent = round(((salary_cost_gross / self.net_sales) * 100),3)
else:
salary_cost_gross_percent = 0.0
self.append("employee_costs_breakup", {"breakup": "Salary Cost Gross", "amount": salary_cost_gross,"percent":salary_cost_gross_percent})
self.total_employee_costs += salary_cost_gross

for expense in report_settings.employee_costs:
if self.net_sales != 0.0:
expense_percent = round(((expense.amount / self.net_sales) * 100),3)
else:
expense_percent = 0.0
self.append("employee_costs_breakup", {"breakup": expense.expense, "amount": expense.amount,"percent":expense_percent})
self.total_employee_costs += expense.amount
if self.net_sales != 0.0:
self.total_employee_costs_percent = round(((self.total_employee_costs / self.net_sales) * 100),3)
self.total_indirect_expenses += self.total_employee_costs

#INDIRECT EXPENSES

self.total_indirect_expenses = 0
# Calculate and append Electricity
electricity_charges = electricity_reading * report_settings.electricity_charges
if self.net_sales != 0.0:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
"indirect_fixed_expenses",
"percentage_expenses",
"employee_costs_section",
"bonus",
"staff_accommodation_charges",
"staff_food_charges",
"employee_costs",
"section_break_4c2bz",
"depreciation"
],
Expand Down Expand Up @@ -109,31 +107,12 @@
"description": "<li>Daily Gross Salary Cost is calculated from employees attendance.</li>\n<br>",
"fieldname": "employee_costs_section",
"fieldtype": "Section Break",
"hidden": 1,
"label": "Employee Costs"
},
{
"fieldname": "bonus",
"fieldtype": "Currency",
"label": "Bonus",
"precision": "2"
},
{
"fieldname": "staff_food_charges",
"fieldtype": "Currency",
"label": "Staff Food Charges",
"precision": "2"
},
{
"fieldname": "section_break_4c2bz",
"fieldtype": "Section Break"
},
{
"fieldname": "staff_accommodation_charges",
"fieldtype": "Currency",
"label": "Staff Accommodation Charges",
"precision": "2"
},
{
"description": "Per Unit",
"fieldname": "electricity_charges",
Expand All @@ -145,11 +124,18 @@
"fieldtype": "Table",
"label": "Burning Materials (Other Consumables)",
"options": "URY Materials"
},
{
"description": "Daily Fixed",
"fieldname": "employee_costs",
"fieldtype": "Table",
"label": "Employee Costs",
"options": "URY Fixed Expenses"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2023-10-25 18:42:45.149783",
"modified": "2024-01-09 15:20:17.567008",
"modified_by": "Administrator",
"module": "URY Pulse",
"name": "URY Report Settings",
Expand Down

0 comments on commit 70c457e

Please sign in to comment.