diff --git a/FEATURES.md b/FEATURES.md
index 95685d6..424a187 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -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.
diff --git a/SETUP.md b/SETUP.md
index cc2373b..b09324d 100644
--- a/SETUP.md
+++ b/SETUP.md
@@ -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.
\ No newline at end of file
+ - 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)
\ No newline at end of file
diff --git a/ury_pulse/fixtures/custom_field.json b/ury_pulse/fixtures/custom_field.json
new file mode 100644
index 0000000..18a1afc
--- /dev/null
+++ b/ury_pulse/fixtures/custom_field.json
@@ -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
+ }
+]
\ No newline at end of file
diff --git a/ury_pulse/hooks.py b/ury_pulse/hooks.py
index e235790..33d7aa5 100644
--- a/ury_pulse/hooks.py
+++ b/ury_pulse/hooks.py
@@ -215,3 +215,19 @@
# auth_hooks = [
# "ury_pulse.auth.validate"
# ]
+
+fixtures = [
+ {
+ "doctype": "Custom Field",
+ "filters": [
+ [
+ "name",
+ "in",
+ {
+ "Employee-payment_amount",
+ "Employee-payment_type",
+ },
+ ]
+ ],
+ }
+]
\ No newline at end of file
diff --git a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/profit_loss_details.html b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/profit_loss_details.html
index df55047..06c4857 100644
--- a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/profit_loss_details.html
+++ b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/profit_loss_details.html
@@ -88,11 +88,11 @@
Date: {{ data.date }}
{{ frappe.utils.fmt_money(data.gross_profit or '', currency=currency) }} |
{{ data.gross_profit_percent }}% |
-
+
{% for expense in data.indirect_expenses_breakup %}
{{ expense.breakup }} |
diff --git a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.json b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.json
index 9060098..63ba1b1 100644
--- a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.json
+++ b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.json
@@ -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
@@ -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
},
@@ -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",
diff --git a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.py b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.py
index 9252c89..983e838 100644
--- a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.py
+++ b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.py
@@ -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)
@@ -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:
diff --git a/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.json b/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.json
index f4a5211..2440ed6 100644
--- a/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.json
+++ b/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.json
@@ -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"
],
@@ -109,31 +107,12 @@
"description": "Daily Gross Salary Cost is calculated from employees attendance.\n
",
"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",
@@ -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",