Files
enterprise-addons/l10n_ch_hr_payroll/models/l10n_ch_swissdec_declaration.py
T

212 lines
12 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from ..api.swissdec_declarations import SwissdecDeclaration
from .hr_version import CANTONS
import json
import base64
import re
XSD_SKIP_VALUE = "XSDSKIP"
class L10nCHSwissdecDeclaration(models.Model):
_name = 'l10n.ch.swissdec.declaration'
_inherit = 'mail.thread'
_description = 'Swissdec Declaration'
_order = "transmission_date desc"
@api.model
def default_get(self, fields):
if self.env.company.country_id.code != "CH":
raise UserError(_('You must be logged in a Swiss company to use this feature'))
return super().default_get(fields)
res_model = fields.Char(
'Declaration Model Name', required=True, index=True)
res_id = fields.Many2oneReference(
'Declaration Model Id', index=True, model_field='res_model', required=True)
name = fields.Char(required=True, readonly=True)
state = fields.Selection(selection=[("waiting", "Waiting for Status"),
("plausibility", "Verifying Plausibility"),
("processing", "Processing"),
("finished", "Finished")], default="waiting", required=True)
year = fields.Integer(readonly=True)
month = fields.Char(readonly=True)
transmission_date = fields.Datetime(required=True, readonly=True)
test_transmission = fields.Boolean(string="Test Transmission")
swissdec_declaration_id = fields.Char(string="Declaration ID", required=True, readonly=True)
job_key = fields.Char(required=True, readonly=True)
general_warnings = fields.Json()
l10n_ch_swissdec_job_result_ids = fields.One2many('l10n.ch.swissdec.job.result', 'declaration_id', string="Results")
def _process_responses(self, vals):
self.ensure_one()
current_running_jobs = self.l10n_ch_swissdec_job_result_ids.grouped('institution_id_ref')
lines_to_create = []
for institution in vals:
existing_job = current_running_jobs.get(institution["institution_id_ref"], self.env["l10n.ch.swissdec.job.result"])
if existing_job:
existing_job.update(institution)
else:
lines_to_create.append((0, 0, institution))
self.update({'l10n_ch_swissdec_job_result_ids': lines_to_create})
def _match_foreign_canton(self, notifications):
"""
When salary certificates are for foreign employees, the canton it is sent to is not straightforward and has to be guessed from notifications
"""
pattern = re.compile(
r'\b(' + '|'.join(re.escape(code[0]) for code in CANTONS) + r')\b'
)
canton = False
for notification in notifications:
match = pattern.search(notification.get("Description", ""))
if match:
canton = match.group(1)
break
if not canton: # We have to fallback in case swissdec did not provide a notification
canton = self.env.company.l10n_ch_work_location_ids[0].canton
return canton
def get_status_from_declare_salary(self):
self.ensure_one()
if self.state != "finished":
swissdec_declaration = SwissdecDeclaration()
declaration = swissdec_declaration.create_get_status_from_declare_salary(
job_key=self.job_key,
)
result = self.env.company._l10n_ch_swissdec_request('get_status_from_declare_salary', data=declaration, is_test=self.test_transmission)
response = result['soap_response']
message_archive = result['request_xml']
response_archive = result['response_xml']
if response:
attachment_request = self.env['ir.attachment'].create({
'name': _("Get_Status_%s_request.xml", self.swissdec_declaration_id),
'datas': base64.encodebytes(message_archive.encode()),
'res_id': self.id,
'res_model': self._name,
})
attachment_response = self.env['ir.attachment'].create({
'name': _("Declaration_%s_response.xml", self.swissdec_declaration_id),
'datas': base64.encodebytes(response_archive.encode()),
'res_id': self.id,
'res_model': self._name,
})
self.message_post(attachment_ids=[attachment_request.id, attachment_response.id], body=_('Get Status Archive'))
# response = serialize_object(response)
corresponding_report = self.env[self.res_model].browse(self.res_id)
institution_descriptions = swissdec_declaration.get_mapped_institution_descriptions(institutions=corresponding_report._get_institutions(), skip_bvg_payroll_unit=True)
job_responses = []
plausiblity_state = response.get("PlausibilityState", {}).get("Plausible")
if not plausiblity_state:
self.state = "plausibility"
else:
if response.get("JobFinished", False):
self.state = "finished"
else:
self.state = "processing"
if plausiblity_state.get("Info", None) or plausiblity_state.get("Warning", None):
self.general_warnings = {
"Info": plausiblity_state.get("Info", None),
"Warning": plausiblity_state.get("Warning", None)
}
else:
self.general_warnings = False
job_state = plausiblity_state.get("JobState")
for domain, institutions in job_state.items():
if institutions:
for institution in iter([institutions] if not isinstance(institutions, list) else institutions):
if domain not in ["Tax", "Statistic"]:
institution_description = institution_descriptions.get(institution.get("institutionIDRef", False))
id_ref = institution.get("institutionIDRef", False)
elif domain == "Tax":
id_ref = institution.get("canton")
if id_ref == 'EX':
notifications_success = institution.get("Success", {})
notifications = []
if notifications_success:
notifications = notifications_success.get("ResponseState", {}).get("Info", {}).get("Notification", [])
canton = self._match_foreign_canton(notifications)
else:
canton = id_ref
institution_description = {
"CantonID": canton
}
else:
id_ref = "#BFS"
institution_description = False
meta_data = {
"institution_id_ref": id_ref,
"institution_description": institution_description,
}
job_vals = {
"domain": domain,
"declaration_id": self.id,
"institution_id_ref": id_ref
}
if institution.get("Ignored"):
job_vals.update({
"general_state": "Ignored",
})
if institution.get("NotSupported"):
job_vals.update({
"general_state": "NotSupported",
})
elif institution.get("Processing"):
job_vals.update({
"general_state": "Processing",
})
elif institution.get("Error"):
job_vals.update({
"general_state": "Error",
"status_response_json": json.loads(json.dumps(institution.get("Error"), default=str)),
})
elif institution.get("Success"):
job_vals.update({
"general_state": "Success",
})
if institution.get("Success").get("ResponseState", {}).get("Info", {}) or institution.get("Success").get("ResponseState", {}).get("Warning", {}):
job_vals.update({
"status_response_json": json.loads(json.dumps(institution.get("Success"), default=str)),
})
success_vals = institution.get("Success")
if success_vals.get("CompletionAndResult"):
completion_result = success_vals.get("CompletionAndResult")
job_vals.update({
"success_state": "CompletionAndResult",
"completion_url": completion_result.get("Completion", {}).get("Url"),
"credential_key": completion_result.get("Credentials", {}).get("Key"),
"credential_password": completion_result.get("Credentials", {}).get("Password")
})
elif success_vals.get("Result"):
institution_result = success_vals.get("Result")
job_vals.update({
"success_state": "Result",
"credential_key": institution_result.get("Credentials", {}).get("Key"),
"credential_password": institution_result.get("Credentials", {}).get("Password")
})
elif success_vals.get("DialogAndResult"):
dialog_result = success_vals.get("DialogAndResult")
job_vals.update({
"success_state": "DialogAndResult",
"credential_key": dialog_result.get("Credentials", {}).get("Key"),
"credential_password": dialog_result.get("Credentials", {}).get("Password")
})
job_vals.update({
"result_meta_data": meta_data
})
job_responses.append(job_vals)
self._process_responses(job_responses)