W2s, 941s, and EFTPS Reports - Oh My!
Using Server Actions to Simplify Reporting
14 February, 2021 by
W2s, 941s, and EFTPS Reports - Oh My!
Kaylie Kipe

As a remote company, Hibou has dealt with many a state and federal remittance for payroll. How many, you may ask? Well, we currently have employees in nine different states and each state has different reporting requirements.

Some states - like Florida - are as easy going as can be. An RT-6 (Re-Employment Tax) once per quarter and you're set! Illinois, on the other hand, requires no less than 21 interactions with withholding agencies - more if you're on a semi-weekly payment schedule - per year:

  • Monthly tax withholding payments

  • Quarterly reports for tax withholding

  • Quarterly reports for unemployment

  • Annual submission of the W-2 to the state

All of this to say that we know our way around payroll reporting. I used payslip line reporting for years to determine the values needed to process each report or remittance and that's worked wonderfully. Just a few clicks and knowing what records would have the data I needed allowed me to easily capture the information and each report typically only takes a few minutes to file. However, we recently started to ponder: "If we spent a bit of time using the tools available to any Odoo user, could we simplify the process?"

The answer, naturally, was a resounding "YES!"

Let's take the W2, for example. If you work in payroll, you likely know that you can enter W2s on ssa.gov. The below server action makes it super simple to quickly copy and paste your values per W2, at which point you can submit he W2s to the IRS and print them for mailing to employees. (Note that the codes to sum this data comes from Hibou's USA Payroll localization and that this server action can - and should - be modified to meet your company's unique codes and/or withholding options.)

  • Name: Generate W2

  • Model: Pay Slip

  • Action to Do: Execute Python Code

  • Python Code:

employee_w2_data = {}
for payslip in records:
  employee = payslip.employee_id
  if employee not in employee_w2_data:
    address = employee.address_home_id
    employee_w2_data[employee] = {
      '00.box_a': employee.identification_id or '',
      '00.box_e': employee.name,
      '00.box_f': address.contact_address,
      '01.box_1': 0.0, # Wages Tips (taxable gross)
      '02.box_2': 0.0, # FIT
      '03.box_3': 0.0, # SS Wages
      '04.box_4': 0.0, # SS
      '05.box_5': 0.0, # Med Wages
      '06.box_6': 0.0, # Med
      '12.box_12_d': 0.0, # 401k Contribution
      '12.box_12_aa': 0.0, # Roth 401k Contribution
      '12.box_12_dd': 0.0, # Employee Medical Costs
  w2_data = employee_w2_data[employee]
  for line in payslip.line_ids:
    if line.code == 'EE_US_941_FIT':
      w2_data['01.box_1'] += line.amount
      w2_data['02.box_2'] -= line.total
    elif line.code == 'EE_US_941_FICA_SS':
      w2_data['03.box_3'] += line.amount
      w2_data['04.box_4'] -= line.total
    elif line.code == 'EE_US_941_FICA_M':
      w2_data['05.box_5'] += line.amount
      w2_data['06.box_6'] -= line.total
    elif line.code == 'EE_IRA':
      w2_data['12.box_12_d'] -= line.amount
    elif line.code == 'EE_IRA_ROTH':
      w2_data['12.box_12_aa'] -= line.amount
    elif line.code == 'EE_MED':
      w2_data['12.box_12_dd'] -= line.amount
      # states possible...
      code_pieces = line.code.split('_')
      if len(code_pieces) >= 4 and (code_pieces[0], code_pieces[1], code_pieces[3]) == ('EE', 'US', 'SIT'):
        state_code = code_pieces[2]
        if ('15.box_15_' + state_code) not in w2_data:
          w2_data[('15.box_15_' + state_code)] = state_code
          w2_data[('16.box_16_' + state_code)] = 0.0
          w2_data[('17.box_17_' + state_code)] = 0.0
          w2_data[('18.box_18_' + state_code)] = 0.0
          w2_data[('19.box_19_' + state_code)] = 0.0
          w2_data[('20.box_20_' + state_code)] = ''
        w2_data[('16.box_16_' + state_code)] += line.amount
        w2_data[('17.box_17_' + state_code)] -= line.total
        w2_data[('18.box_18_' + state_code)] += 0.0
        w2_data[('19.box_19_' + state_code)] += 0.0
message = ''
for employee, w2_data in employee_w2_data.items():
  employee_message = '\n\n%s ::\n' % (employee.name, )
  for box_key in sorted(w2_data.keys()):
    value = w2_data[box_key]
    if isinstance(value, float):
      employee_message += '  %s: %0.2f\n' % (box_key, value)
      employee_message += '  %s: %s\n' % (box_key, value)
  message += employee_message
raise Warning(message)
report_data = [{'employee_id': e.id, 'employee_data': w2_data} for employee, w2_data in employee_w2_data.items()]
action = ''

After saving, don't forget to Create Contextual Action.

To use this server action, navigate to Employee Payslips then add a filter for Date Account to cover the reporting period. Select all payslips then use your Action to Generate W2. The result is a popup that displays all necessary information for filing (listing all employees and all values for selected payslips)!

Ready to Learn More About Server Actions?

Simplify everyday tasks with server actions and automated actions, which you can learn more about with the free preview videos in our Advanced Development in Odoo 13 course!

W2s, 941s, and EFTPS Reports - Oh My!
Kaylie Kipe 14 February, 2021
Share this post
Sign in to leave a comment