Payroll entries, salary slips, and the general ledger

I’m new to ERPNext and still trying to figure things out. Right now, I’m a bit confused about the intended relationship between the Payroll Entry doctype, Salary slips, and the general ledger.

I get that the Payroll Entry is a way to generate multiple salary slips at once, and that it also generates a Journal Entry to put payroll on the books, but the design doesn’t quite make sense to me (probably my own fault).

Specifically, I’m not quite clear on what the Payroll Entry document represents. If, for example, I later cancel the journal entry it creates, the Payroll Entry doesn’t reflect that in anyway. Likewise, once the salary slips have been created, they’re not linked to the Payroll Entry document.

Perhaps this is completely misguided, but I would expect the Payroll Entry document to contain a table of linked Salary Slips, and then I would expect it to write to the General Ledger directly rather than through an untethered journal entry. That would, to my use at least, be a lot cleaner and clearer. Is there a design reason behind all the unconnected documents?

Thanks in advance for the help!

Your observation and what you had in mind may relate thread discussion
Salary slip submitted, but no journal entries

and initiative https://github.com/frappe/erpnext/issues/8421

Could we not solve this with the current code by using something other than the “posting date” of the Payroll Entry to link to the Salary Slips posting date. An optional Payroll Entry reference could be added to the Salary Slip. Also you would be able to create a Payroll Entry from the Salary Slip form to allow for small business with only a couple of payslips to easily create the Payroll Entry. Also we would need to create the journal entries for each Salary Slip either individually or as an aggregate of the Payroll Entry (new hr payroll setting). The submission of a Salary slip would generate the journal entries for payroll. The Payroll entry could have an optional “Check #” reference field.

Thoughts??

It looks to me that the function submit_salary_slips in the payroll_entry.py file is the code that needs to be called to create the journal entries. It calls a make_accrual_jv_entry function that appears to me to be correct. It seems that the “Submit Salary Slips” button doesn’t get displayed via payroll_entry.js. I edited the code to always show the button but when pressed the message says there are no salary slips that are not submitted. Therefore maybe the Salary_slips are being created “Submitted”.

message I now have is “Row 3: Party Type and Party is required for Receivable / Payable account CPP Payable - BT” but I can’t seem to update this is the chart of accounts.

ok sorry for the rapid replies but I managed to get it to generate the Journal Entries for the Salary Slips for a Payroll entry. The issue with the Party Type error message was because the earnings and deduction salary structure need to have blank account type. Therefor we just need to display the Submit Salary Slips button appropriately (easy code fix).

fyi, here is the code I changed to make the “Submit Salary Slip” button show up. NOTE: If there are no salary slips or if they are already submitted then the function will just return with an error, so there is no harm in showing the button always. If someone would like to move the adding of the button into the if statement above that shows the “View Salary Slips” then I believe that would work as well. I would do the pull request but I am just new to github and would prefer this gets fixed for others in a more timely manner than waiting for me figure out all the details of the pull request.

before making the changes there was not a way to make the journal entries for the actual salary slips. My supposition is that the code I modified has a bug and therefor by modifying the code the “Submit Salary Slips” button appears, thus enabling the existing code that creates the journal entries to be executed. It may not solve the issue you brought up about what happens when the journal entries are cancelled (both the payroll payment entry and the payroll recording entry) but that could be resolved by putting a payroll entry reference on the Salary Slips and then “Cancelling” the Salary Slips and Payroll entry on “Cancelling” the journal entries. Perhaps reversing journal entries should be created when “Cancelling” the Payroll entries and/or Salary Slips and restricting “Cancelling” of Journal Entries that were created by another process.

In short my change to the code enables the creation of the Salary Slip journal entries to record the Salary and related expenses and payables.

Still new to ERPnext (we are more evaluating it currently). Can you point me in the right direction to get this installed? Looks exactly like what we are looking for in terms of payroll. Honestly, the current system surprises me, regardless of privacy concerns it’s an accounting nightmare.

1 Like

It’s been giving me a 500 internal server error. Need to take a look at the logs to see why.
Edit: Error attached. For some reason it can’t find the module after install.

So it installed in the ver 11 dev branch, but on 10.36 I couldn’t get it to install for the life of me. Not sure why.

Edit: I can find it via search. Where is it supposed to come up in erpnext?

Been getting the following error when trying to submit the voucher:

Traceback (most recent call last):
File “/home/bench/erpnext/apps/frappe/frappe/desk/form/save.py”, line 19, in savedocs
doc.submit()
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 841, in submit
self._submit()
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 830, in _submit
self.save()
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 260, in save
return self._save(*args, **kwargs)
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 311, in _save
self.run_post_save_methods()
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 901, in run_post_save_methods
self.run_method(“on_submit”)
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 765, in run_method
out = Document.hook(fn)(self, *args, **kwargs)
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 1040, in composer
return composed(self, method, *args, **kwargs)
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 1023, in runner
add_to_return_value(self, fn(self, *args, **kwargs))
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 759, in
fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs)
File “/home/bench/erpnext/apps/oi_custom/oi_custom/customizations/doctype/payroll_voucher/payroll_voucher.py”, line 46, in on_submit
self.submit_salary_slips()
File “/home/bench/erpnext/apps/oi_custom/oi_custom/customizations/doctype/payroll_voucher/payroll_voucher.py”, line 226, in submit_salary_slips
self.register_payroll_in_gl()
File “/home/bench/erpnext/apps/oi_custom/oi_custom/customizations/doctype/payroll_voucher/payroll_voucher.py”, line 338, in register_payroll_in_gl
credit=amt
UnboundLocalError: local variable ‘amt’ referenced before assignment

Traceback (most recent call last):
File “/home/bench/erpnext/apps/frappe/frappe/app.py”, line 62, in application
response = frappe.handler.handle()
File “/home/bench/erpnext/apps/frappe/frappe/handler.py”, line 22, in handle
data = execute_cmd(cmd)
File “/home/bench/erpnext/apps/frappe/frappe/handler.py”, line 53, in execute_cmd
return frappe.call(method, **frappe.form_dict)
File “/home/bench/erpnext/apps/frappe/frappe/init.py”, line 942, in call
return fn(*args, **newargs)
File “/home/bench/erpnext/apps/frappe/frappe/desk/form/save.py”, line 19, in savedocs
doc.submit()
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 841, in submit
self._submit()
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 830, in _submit
self.save()
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 260, in save
return self._save(*args, **kwargs)
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 311, in _save
self.run_post_save_methods()
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 901, in run_post_save_methods
self.run_method(“on_submit”)
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 765, in run_method
out = Document.hook(fn)(self, *args, **kwargs)
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 1040, in composer
return composed(self, method, *args, **kwargs)
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 1023, in runner
add_to_return_value(self, fn(self, *args, **kwargs))
File “/home/bench/erpnext/apps/frappe/frappe/model/document.py”, line 759, in
fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs)
File “/home/bench/erpnext/apps/oi_custom/oi_custom/customizations/doctype/payroll_voucher/payroll_voucher.py”, line 46, in on_submit
self.submit_salary_slips()
File “/home/bench/erpnext/apps/oi_custom/oi_custom/customizations/doctype/payroll_voucher/payroll_voucher.py”, line 226, in submit_salary_slips
self.register_payroll_in_gl()
File “/home/bench/erpnext/apps/oi_custom/oi_custom/customizations/doctype/payroll_voucher/payroll_voucher.py”, line 338, in register_payroll_in_gl
credit=amt
UnboundLocalError: local variable ‘amt’ referenced before assignment

Haven’t had time to check. I’ll update you by the weekend.