Files
enterprise-addons/l10n_us_hr_payroll/models/l10n_us_940.py
T

239 lines
9.5 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
import csv
import io
from datetime import date
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.tools import date_utils
class L10nUsForm940(models.Model):
_name = 'l10n.us.940'
_description = 'Form 940'
@api.model
def default_get(self, fields):
if self.env.company.country_id.code != "US":
raise UserError(_('You must be logged in a US company to use this feature'))
return super().default_get(fields)
single_state_payer_id = fields.Many2one(
'res.country.state',
domain=lambda self: [('country_id', '=', self.env.ref('base.us').id)],
string="Single State Payer",
help="Only select if you paid employees in only ONE State."
)
is_multi_state_employer = fields.Boolean("Multi State Employer", help="If you had to pay state unemployment tax in more than one state, you are a multi-state employer.")
has_paid_credit_reduction_state = fields.Boolean("Paid in Credit Reduction State", help='Check if you paid wages in a state that is subject to "Credit Reduction".')
irs_payment_option = fields.Selection([
('efw', 'EFW'),
('eftps', 'EFTPS'),
('check_money_order', 'Check/Money Order'),
('credit_card', 'Credit Card'),
], required=True, string="IRS Payment Option", help="""
Select the payment method you will use to file your form:
- Electronic Funds Withdrawal (EFW)
- Electronic Federal Tax Payment System (EFTPS)
- Check or Money order
- Credit Card""")
year = fields.Char(required=True, default=lambda self: fields.Date.today().year, string="Tax Year")
company_id = fields.Many2one(
'res.company',
default=lambda self: self.env.company,
domain=lambda self: [('id', 'in', self.env.companies.ids)],
required=True)
allowed_payslip_ids = fields.Many2many('hr.payslip', compute='_compute_allowed_payslip_ids')
payslip_ids = fields.Many2many(
'hr.payslip',
compute='_compute_payslips_ids',
store=True,
readonly=False,
domain="[('id', 'in', allowed_payslip_ids)]")
csv_file = fields.Binary("CSV file", readonly=True)
csv_filename = fields.Char()
@api.depends('year')
def _compute_display_name(self):
for form_940 in self:
form_940.display_name = f"Form 940 - {form_940.year}"
@api.depends('allowed_payslip_ids')
def _compute_payslips_ids(self):
for form_940 in self:
form_940.payslip_ids = form_940.allowed_payslip_ids
def _get_allowed_payslips_domain(self):
self.ensure_one()
return [
('state', 'in', ['validated', 'paid']),
('date_from', '>=', date(int(self.year), 1, 1)),
('date_to', '<=', date(int(self.year), 12, 31)),
('company_id', '=', self.company_id.id),
]
@api.depends('company_id', 'year')
def _compute_allowed_payslip_ids(self):
for form_940 in self:
allowed_payslips = self.env['hr.payslip'].search(form_940._get_allowed_payslips_domain())
form_940.allowed_payslip_ids = allowed_payslips
def action_generate_csv(self):
self.ensure_one()
header = (
"Form Type*",
"Tax Year*",
"Employer EIN*",
"Business name*",
"Business structure or classification*",
"Trade name (if any)",
"Is Foreign Address*",
"US Address 1*",
"US Address 2",
"US City/Town*",
"US State*",
"US ZIP code*",
"Foreign Address 1*",
"Foreign Address 2",
"Foreign City/Town*",
"Foreign State/Province*",
"ZIP code/Postal code*",
"Foreign Country*",
"Email address",
"Phone number",
"Signatory name*",
"Signatory Title*",
"Daytime phone*",
"Have you made any payments to employees in the Tax Year?*",
"1a)Select State, if you paid unemployment tax in one state only",
"1b) Are you a multi state employer? (Complete Schedule A)*",
"2) Paid wages in a state that is subject to CREDIT REDUCTION?*",
"3) Total payments to all employees",
"4) Payments exempt from FUTA tax",
"4a) Is the payments exempt include Fringe benefits?",
"4b) Is the payments exempt include Group-term life insurance?",
"4c) Is the payments exempt include Retirement/Pension?",
"4d) Is the payments exempt include Dependent care?",
"4e) Is the payments exempt for other reason?",
"5) Total payments made to each employee in excess of $7000",
"9) Were ALL the taxable FUTA wages you paid excluded from SUTA?",
"10) FUTA Tax Adjustment Amount (Calculated from Worksheet)",
"13) FUTA tax deposited for the year",
"15) Choose how to use your IRS Credit (Overpayment)",
"IRS Payment Option",
"EFW Account Type (Required only if the IRS payment type is EFW)",
"EFW US Bank Account Number",
"EFW US Bank Routing number",
"EFW Taxpayer day time Phone number",
"16a) Report the amt of your FUTA taxable liability for 1st quarter",
"16b) Report the amt of your FUTA taxable liability for 2nd quarter",
"16c) Report the amt of your FUTA taxable liability for 3rd quarter",
"16d) Report the amt of your FUTA taxable liability for 4th quarter",
"Are you a successor employer?",
"Is your business has closed or you stopped paying wages?",
"Recordkeeper Name",
"Recordkeeper Address 1",
"Recordkeeper Address 2",
"Recordkeeper City/Town",
"Record Keeper State",
"RecordKeeper ZIP code/Postal code",
"Designee name",
"Designee phone",
"Designee PIN",
"94x Online Signature PIN",
"RA PIN",
"Taxpayer PIN (For ERO)",
)
company = self.company_id
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(header)
def total(code):
return abs(line_values[code]['sum']['total'])
line_values = self.payslip_ids._get_line_values([
"401KMATCHING",
"COMMUTER",
"COMPANYFUTA",
"DENTAL",
"GROSS",
"MEDICAL",
"MEDICALFSA",
"MEDICALFSADC",
"MEDICALHSA",
"VISION",
], compute_sum=True)
quarter_to_payslips = self.payslip_ids.grouped(lambda payslip: date_utils.get_quarter_number(payslip.date_from))
quarter_to_futa = {
quarter: payslips._get_line_values(["COMPANYFUTA"], compute_sum=True)["COMPANYFUTA"]["sum"]["total"]
for quarter, payslips in sorted(quarter_to_payslips.items())
}
categ_pretax = abs(self.payslip_ids._get_category_data("PRETAX")["total"])
categ_matching = abs(self.payslip_ids._get_category_data("MATCHING")["total"])
bank_account = self.company_id.partner_id.bank_ids[:1]
row = [
"Form 940",
self.year,
company.vat,
company.name,
dict(company._fields['l10n_us_business_structure']._description_selection(self.env)).get(company.l10n_us_business_structure),
"",
"No",
company.street,
company.street2,
company.city,
company.state_id.code,
company.zip,
*[""] * 6,
company.email,
company.phone,
company.l10n_us_signatory_id.name,
company.l10n_us_signatory_id.job_title,
company.l10n_us_signatory_id.phone,
"Yes",
self.single_state_payer_id.name,
"Yes" if self.is_multi_state_employer else "No",
"Yes" if self.has_paid_credit_reduction_state else "No",
total("GROSS") + categ_pretax + categ_matching,
categ_pretax + total("401KMATCHING"),
"Yes" if any(total(code) > 0 for code in ("MEDICAL", "DENTAL", "VISION", "MEDICALFSA", "MEDICALHSA", "COMMUTER")) else "No",
"No",
"Yes" if total("401KMATCHING") > 0 else "No",
"Yes" if total("MEDICALFSADC") > 0 else "No",
"",
max(0, total("GROSS") - categ_pretax - total("401KMATCHING") - 7_000),
*[""] * 2,
total("COMPANYFUTA"),
"",
dict(self._fields['irs_payment_option']._description_selection(self.env)).get(self.irs_payment_option),
dict(bank_account._fields['l10n_us_bank_account_type']._description_selection(self.env)).get(bank_account.l10n_us_bank_account_type),
bank_account.acc_number,
bank_account.clearing_number,
company.phone,
quarter_to_futa.get(1),
quarter_to_futa.get(2),
quarter_to_futa.get(3),
quarter_to_futa.get(4),
"No",
"No",
"",
company.street,
company.street2,
company.city,
company.state_id.code,
company.zip,
*[""] * 6,
]
writer.writerow([col or "" for col in row]) # never write False
self.csv_file = base64.b64encode(output.getvalue().encode())
self.csv_filename = f"form_940_{self.year}.csv"