Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0][ADD][WIP] account_avatax_exemption_sign_oca #79

Open
wants to merge 3 commits into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions account_avatax_exemption_sign_oca/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
============================
Avatax Exemptions - Sign OCA
============================

This application allows you to add Avatax exemptions with Sign OCA module.

Authors
~~~~~~~

* Bernat Puig <bernat.puig@forgeflow.com>

Contributors
------------

* ForgeFlow

This module is maintained by Forgeflow.
1 change: 1 addition & 0 deletions account_avatax_exemption_sign_oca/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
27 changes: 27 additions & 0 deletions account_avatax_exemption_sign_oca/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2023 ForgeFlow S.L. (http://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

{
"name": "Avatax Exemptions with Sign OCA extension",
"version": "16.0.1.0.0",
"category": "Sales",
"summary": """
This application allows you to add Avatax exemptions with Sign OCA module
""",
"author": "Kencove,ForgeFlow,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/sign",
"license": "AGPL-3",
"depends": [
"account_avatax_oca",
"account_avatax_sale_oca",
"account_avatax_exemption",
"sign_oca",
],
"data": [
"data/data.xml",
"views/sign_oca_template.xml",
"views/sign_oca_request.xml",
],
"installable": True,
"application": False,
}
8 changes: 8 additions & 0 deletions account_avatax_exemption_sign_oca/data/data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="sign_field_text" model="sign.oca.field">
<field name="name">Tax Exemption Number</field>
<field name="field_type">text</field>
<field name="is_exemption_number">True</field>
</record>
</odoo>
5 changes: 5 additions & 0 deletions account_avatax_exemption_sign_oca/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import avalara_salestax
from . import exemption
from . import sign_oca_field
from . import sign_oca_request
from . import sign_oca_template
21 changes: 21 additions & 0 deletions account_avatax_exemption_sign_oca/models/avalara_salestax.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2023 ForgeFlow S.L. (http://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import models


class AvalaraSalestax(models.Model):
_inherit = "avalara.salestax"

def link_certificates_to_customer(self, exemption_line):
res = super().link_certificates_to_customer(exemption_line)
if all(
exemption_line.exemption_id.exemption_line_ids.mapped("linked_to_customer")
):
if exemption_line.exemption_id.sign_oca_request_id:
exemption_line.exemption_id.sign_oca_request_id.write(
{
"is_exemption_synchronized": True,
}
)
return res
16 changes: 16 additions & 0 deletions account_avatax_exemption_sign_oca/models/exemption.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2023 ForgeFlow S.L. (http://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class ResPartnerExemption(models.Model):
_inherit = "res.partner.exemption"

sign_oca_request_id = fields.Many2one("sign.oca.request")

def write(self, vals):
if vals.get("state") == "cancel":
for record in self:
record.sign_oca_request_id.cancel()
return super().write(vals)
10 changes: 10 additions & 0 deletions account_avatax_exemption_sign_oca/models/sign_oca_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2023 ForgeFlow S.L. (http://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class SignOcaField(models.Model):
_inherit = "sign.oca.field"

is_exemption_number = fields.Boolean()
82 changes: 82 additions & 0 deletions account_avatax_exemption_sign_oca/models/sign_oca_request.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright 2023 ForgeFlow S.L. (http://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class SignOcaRequest(models.Model):
_inherit = "sign.oca.request"

is_exemption = fields.Boolean(related="template_id.is_exemption")
is_exemption_synchronized = fields.Boolean(
string="Exemption synchronized with AvaTax?", readonly=True, copy=False
)
exemption_ids = fields.One2many(
comodel_name="res.partner.exemption",
inverse_name="sign_oca_request_id",
string="Exemptions",
)

def _get_partner_id(self):
role_customer = self.env.ref("sign_oca.sign_role_customer")
customer_signers = self.signer_ids.filtered(
lambda x: x.role_id == role_customer
).partner_id
return customer_signers[0] if customer_signers else None

def _prepare_exemption_data(self):
avalara_salestax = (
self.env["avalara.salestax"]
.sudo()
.search([("exemption_export", "=", True)], limit=1)
)
use_commercial_entity = avalara_salestax.use_commercial_entity
partner_id = self._get_partner_id()

data = {
"partner_id": partner_id.commercial_partner_id.id
if use_commercial_entity
else partner_id.id,
"exemption_type": self.template_id.exemption_type.id,
"sign_oca_request_id": self.id,
}
exemption_number_field_id = (
self.template_id.item_ids.mapped("field_id")
.filtered(lambda x: x.is_exemption_number)
.ids
)
if exemption_number_field_id:
for item_id in self.signatory_data:
item = self.signatory_data[item_id]
if item["field_id"] == exemption_number_field_id[0]:
data["exemption_number"] = item["value"]
break
return data

def _check_signed(self):
res = super()._check_signed()
if self.state == "signed" and self.is_exemption:
exemption_data = self._prepare_exemption_data()
exemption = self.env["res.partner.exemption"].create(exemption_data)
exemption.onchange_exemption_type()
exemption.onchange_effective_date()
exemption.onchange_state_ids()
if exemption.exemption_number:
exemption.exemption_line_ids.write(
{
"add_exemption_number": True,
"exemption_number": exemption.exemption_number,
}
)
exemption.export_exemption()
return res

def open_exemptions(self):
self.ensure_one()
return {
"name": "Exemptions",
"type": "ir.actions.act_window",
"res_model": "res.partner.exemption",
"view_mode": "tree,form",
"domain": [("sign_oca_request_id", "=", self.id)],
}
11 changes: 11 additions & 0 deletions account_avatax_exemption_sign_oca/models/sign_oca_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2023 ForgeFlow S.L. (http://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class SignOcaTemplate(models.Model):
_inherit = "sign.oca.template"

is_exemption = fields.Boolean(copy=False)
exemption_type = fields.Many2one("res.partner.exemption.type", copy=False)
1 change: 1 addition & 0 deletions account_avatax_exemption_sign_oca/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_account_avatax_exemption_sign_oca
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
from odoo.tests.common import TransactionCase


class TestACcountAvataxExemptionSignOca(TransactionCase):
def setUp(self):
super(TestACcountAvataxExemptionSignOca, self).setUp()
self.exemption_model = self.env["res.partner.exemption"]
self.sign_oca_request_model = self.env["sign.oca.request"]
self.sign_oca_template_model = self.env["sign.oca.template"]
self.sign_oca_exemption_type_model = self.env["res.partner.exemption.type"]
self.partner_model = self.env["res.partner"]
self.avalara_salestax_model = self.env["avalara.salestax"]
self.sign_oca_field_model = self.env["sign.oca.field"]

self.partner = self.partner_model.create(
{
"name": "Test Partner",
}
)
self.sign_oca_exemption_type = self.sign_oca_exemption_type_model.create(
{
"name": "Test Exemption Type",
"state_ids": [(6, 0, [self.env.ref("base.state_us_1").id])],
}
)
self.sign_oca_template = self.sign_oca_template_model.create(
{
"name": "Test Sign Template",
"data": "Test",
"filename": "empty.pdf",
"is_exemption": True,
"exemption_type": self.sign_oca_exemption_type.id,
}
)
self.sign_oca_field = self.sign_oca_field_model.search(
[("name", "=", "Tax Exemption Number")], limit=1
)
self.sign_oca_template.item_ids.create(
{
"template_id": self.sign_oca_template.id,
"role_id": self.env.ref("sign_oca.sign_role_customer").id,
"page": 1,
"position_x": 10,
"position_y": 10,
"width": 10,
"height": 10,
"required": True,
"field_id": self.sign_oca_field.id,
}
)
self.sign_oca_request = self.sign_oca_request_model.create(
{
"name": "Test Sign Request",
"template_id": self.sign_oca_template.id,
"signatory_data": self.sign_oca_template._get_signatory_data(),
"data": "Test",
"signer_ids": [
(
0,
0,
{
"partner_id": self.partner.id,
"role_id": self.env.ref("sign_oca.sign_role_customer").id,
},
)
],
}
)
self.exemption = self.exemption_model.create(
{
"name": "Test Exemption",
"partner_id": self.partner.id,
"state": "draft",
"sign_oca_request_id": self.sign_oca_request.id,
"exemption_number": "12345",
}
)
self.avalara_salestax = self.avalara_salestax_model.create(
{
"account_number": "12345",
"license_key": "12345",
"exemption_export": True,
"exemption_rule_export": True,
"use_commercial_entity": True,
}
)

def test_01_check_exemption_and_sign_oca_request(self):
self.assertTrue(self.sign_oca_request.is_exemption)
self.assertIn(self.exemption, self.sign_oca_request.exemption_ids)
self.assertEqual(self.exemption.sign_oca_request_id, self.sign_oca_request)
self.assertEqual(self.exemption.state, "draft")

def test_02_test_cancel_sign_request_id(self):
self.assertEqual(self.exemption.state, "draft")
self.assertEqual(self.exemption.sign_oca_request_id.state, "draft")
self.exemption.write({"state": "cancel"})
self.exemption._cancel_sign_request_id()
self.assertEqual(self.exemption.state, "cancel")
self.assertEqual(self.exemption.sign_oca_request_id.state, "cancel")

def test_03_get_partner_id(self):
partner_id = self.sign_oca_request._get_partner_id()
self.assertEqual(
partner_id, self.partner, "The partner ID should match the created partner"
)

def test_04_prepare_exemption_data(self):
self.sign_oca_request.state = "signed"
exemption_data = self.sign_oca_request._prepare_exemption_data()
self.assertIn("partner_id", exemption_data)
self.assertIn("exemption_type", exemption_data)
self.assertIn("sign_oca_request_id", exemption_data)

def test_05_check_signed(self):
self.sign_oca_request.state = "signed"
self.sign_oca_request.is_exemption = True
signatory_data = self.sign_oca_request.signatory_data
next(
item.update({"value": "12345"})
for item in signatory_data.values()
if item.get("name") == "Tax Exemption Number"
)
self.sign_oca_request.write({"signatory_data": signatory_data})
self.sign_oca_request._check_signed()
exemption = self.env["res.partner.exemption"].search(
[("sign_oca_request_id", "=", self.sign_oca_request.id)], limit=1
)

self.assertEqual(exemption.exemption_number, "12345")
self.assertEqual(exemption.state, "draft")
self.assertEqual(exemption.exemption_validity_duration, 30)
self.assertEqual(exemption.sign_oca_request_id.state, "signed")

def test_06_open_exemptions(self):
action = self.sign_oca_request.open_exemptions()
self.assertEqual(action["res_model"], "res.partner.exemption")
self.assertEqual(action["view_mode"], "tree,form")
self.assertIn(
("sign_oca_request_id", "=", self.sign_oca_request.id), action["domain"]
)
41 changes: 41 additions & 0 deletions account_avatax_exemption_sign_oca/views/sign_oca_request.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<odoo>
<record id="sign_oca_request_form_view" model="ir.ui.view">
<field
name="name"
>sign.oca.request.form (in account_avatax_exemption_sign_oca)</field>
<field name="model">sign.oca.request</field>
<field name="inherit_id" ref="sign_oca.sign_oca_request_form_view" />
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button
type="object"
name="open_exemptions"
string="Exemptions"
class="oe_stat_button"
icon="fa-file-o"
/>
</xpath>
<xpath expr="//group" position="after">
<group>
<field name="is_exemption_synchronized" />
</group>
</xpath>
</field>
</record>
<record id="sign_oca_request_search_view" model="ir.ui.view">
<field
name="name"
>sign.oca.request.search (in account_avatax_exemption_sign_oca)</field>
<field name="model">sign.oca.request</field>
<field name="inherit_id" ref="sign_oca.sign_oca_request_search_view" />
<field name="arch" type="xml">
<xpath expr="//filter[@name='sign_by_me']" position="after">
<filter
name="request_to_review"
string="Exemptions to Review"
domain="[('state', '=', 'signed'),('is_exemption','=',True),('is_exemption_synchronized','=',False)]"
/>
</xpath>
</field>
</record>
</odoo>
Loading
Loading