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

[14.0][ADD] partner_usps_address_validation #89

Open
wants to merge 3 commits into
base: 14.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
2 changes: 1 addition & 1 deletion account_banking_ach_base/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
"views/res_bank.xml",
"views/res_company.xml",
],
"external_dependencies": {"python": ["python-stdnum", "ach"]},
"external_dependencies": {"python": ["stdnum", "ach"]},
"installable": True,
}
1 change: 1 addition & 0 deletions l10n_us_partner_legal_number/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"category": "Banking addons",
"depends": ["account"],
"data": ["views/res_partner.xml"],
"external_dependencies": {"python": ["stdnum"]},
"installable": True,
}
80 changes: 80 additions & 0 deletions partner_usps_address_validation/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
=======================
USPS Address Validation
=======================


.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3

|badge1| |badge2|

This module adds a tool to the Contacts page which validates the contact's address. Simply click the 'Validate' button, and the address of the contact will be compared to the USPS address database. The result will be a cleaned address, including the full 9 digit zipcode, in the exact format recognized by USPS

**Table of contents**

.. contents::
:local:

Configuration
=============

In the *General Settings* menu, enter your USPS API credentials under USPS Address Validation Settings


Usage
=====

On a contact, enter as much of the address as possible to ensure an accurate match. Required are address, and either city/state or zipcode. Click the Validate button to bring up the wizard. User entered text appears on the left as the original address, and the right displays the USPS cleansed address, which may be edited as needed. Either accept or cancel the changes to return to the contact page.


Known issues / Roadmap
======================

* There are no knows issues at this time
* USPS will always return the address in all caps. CamelCase support is not planned for future releases.

Bug Tracker
===========


Credits
=======

Authors
~~~~~~~

* ckolobow

Contributors
~~~~~~~~~~~~

* Craig Kolobow <[email protected]>

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-ckolobow| image:: https://github.com/ckolobow.png?size=40px
:target: https://github.com/ckolobow
:alt: ckolobow

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-ckolobow|

This module is part of the `OCA/partner-contact <https://github.com/OCA/sale-workflow/tree/15.0/partner_usps_address_validation>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
4 changes: 4 additions & 0 deletions partner_usps_address_validation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2022 Open Source Integrators
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import models
from . import wizard
24 changes: 24 additions & 0 deletions partner_usps_address_validation/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2022 Open Source Integrators
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "USPS Address Validation",
"category": "Contact",
"version": "14.0.1.0.0",
"summary": """Utilize the USPS open API for address validation""",
"depends": ["contacts"],
"external_dependencies": {"python": ["xmltodict", "requests"]},
"data": [
"security/ir.model.access.csv",
"wizard/usps_address_validation.xml",
"views/res_partner.xml",
"views/config.xml",
],
"author": "Open Source Integrators, Odoo Community Association (OCA)",
"maintainer": ["ckolobow"],
"website": "https://github.com/OCA/l10n-usa",
"demo": [],
"installable": True,
"application": True,
"auto_install": False,
"license": "AGPL-3",
}
4 changes: 4 additions & 0 deletions partner_usps_address_validation/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2022 Open Source Integrators
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import res_partner
from . import usps_credential_configuration
132 changes: 132 additions & 0 deletions partner_usps_address_validation/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Copyright 2022 Open Source Integrators
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

import requests
import xmltodict

from odoo import _, fields, models
from odoo.exceptions import ValidationError


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

usps_date_validation = fields.Date(
"Last Validation Date",
readonly=True,
copy=False,
help="The date the address was last validated by USPS and accepted",
)

def button_usps_address_validation(self):
view_ref = self.env.ref(
"partner_usps_address_validation.usps_address_validation_view_form"
)
ctx = self.env.context.copy()
ctx.update({"active_ids": self.ids, "active_id": self.id})
return {
"type": "ir.actions.act_window",
"name": "USPS Address Validation",
"binding_view_types": "form",
"view_mode": "form",
"view_id": view_ref.id,
"res_model": "usps.address.validation",
"nodestroy": True,
"res_id": False,
"target": "new",
"context": ctx,
}

def cleanse_address(self, response_data):
response_data = response_data.get("AddressValidateResponse").get("Address")
if response_data.get("Address1") != "FALSE":
a1 = response_data.get("Address1")
else:
a1 = " "
if response_data.get("Address2") != "FALSE":
a2 = response_data.get("Address2")
else:
a2 = " "
if response_data.get("City") != "FALSE":
city = response_data.get("City")
else:
city = " "
if response_data.get("State") != "FALSE":
state = response_data.get("State")
else:
state = " "
if response_data.get("Zip5") != "FALSE":
z5 = response_data.get("Zip5")
else:
z5 = " "
if response_data.get("Zip4") != "FALSE":
z4 = response_data.get("Zip4")
else:
z4 = " "
if z4 != " " and z5 != " " and z4 and z5:
z = z5 + " - " + z4
ok = "true"
elif z5:
z = z5
ok = "false"
else:
raise ValidationError(response_data.get("Error").get("Description"))
if a2 != " " or a1 != " ":
am = "true"
else:
am = "false"
cleanse_address_res = {
"Address2": a1,
"Address1": a2,
"City": city,
"State": state,
"ZIPCode": z,
"AddressMatch": am,
"CityStateZipOK": ok,
}
return cleanse_address_res

def usps_xml_request(self):
"""
prepare xml data for address validation api
"""
# Default address as of 6/22: "https://secure.shippingapis.com/ShippingAPI.dll"
try:
web = self.env["ir.config_parameter"].sudo().get_param("usps_api_url")
user_id = self.env["ir.config_parameter"].sudo().get_param("usps_username")
except Exception:
raise ValidationError(
_(
"Your credentials are not configured,\
please ensure you have a username, password,\
and API URL set under Contacts/Configuration/USPS\
Credential Configuration"
)
)
address1 = str(self.street).replace("&", "%26amp;").replace("#", "%23")
address2 = str(self.street2).replace("&", "%26amp;").replace("#", "%23")
city = str(self.city).replace("&", "%26amp;").replace("#", "%23")
state = str(self.state_id.code).replace("&", "%26amp;").replace("#", "%23")
zipcode = str(self.zip).replace("&", "%26amp;").replace("#", "%23")
request = (
'%s+?API=Verify&XML=<AddressValidateRequest USERID="%s">\
<Address ID="0"><Address1>%s</Address1><Address2>%s\
</Address2><City>%s</City><State>%s</State><Zip5>\
%s</Zip5><Zip4></Zip4></Address></AddressValidateRequest>'
% (web, user_id, address1, address2, city, state, zipcode)
)
try:
response = requests.post(request)
response_data = xmltodict.parse(response.text)
except Exception as error:
raise ValidationError(error)
if response_data.get("Error"):
raise ValidationError(response_data.get("Error").get("Description"))
try:
cleanse_address_res = self.env["res.partner"].cleanse_address(response_data)
if cleanse_address_res:
return cleanse_address_res
else:
raise ValidationError(_(response_data))
except Exception as error:
raise ValidationError(_(error))
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright 2022 Open Source Integrators
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

usps_api_url = fields.Char(
string="API URL",
default="https://secure.shippingapis.com/ShippingAPI.dll",
config_parameter="usps_api_url",
)
usps_username = fields.Char(string="Username", config_parameter="usps_username")
usps_password = fields.Char(string="Password", config_parameter="usps_password")

def get_values(self):
res = super(ResConfigSettings, self).get_values()
res.update(
usps_api_url=self.env["ir.config_parameter"]
.sudo()
.get_param("usps_api_url"),
usps_username=self.env["ir.config_parameter"]
.sudo()
.get_param("usps_username"),
usps_password=self.env["ir.config_parameter"]
.sudo()
.get_param("usps_password"),
)
return res

def set_values(self):
super(ResConfigSettings, self).set_values()
param = self.env["ir.config_parameter"].sudo()
usps_api_url = self.usps_api_url
usps_username = self.usps_username
usps_password = self.usps_password
param.set_param("usps_api_url", usps_api_url)
param.set_param("usps_username", usps_username)
param.set_param("usps_password", usps_password)
2 changes: 2 additions & 0 deletions partner_usps_address_validation/readme/CONFIGURATION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Create a USPS account at https://www.usps.com/business/web-tools-apis/ and get API credentials.
- In the *General Settings* menu, enter your USPS API credentials under USPS Address Validation Settings
2 changes: 2 additions & 0 deletions partner_usps_address_validation/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Craig Kolobow <[email protected]>
* Patrick Wilson <[email protected]>
3 changes: 3 additions & 0 deletions partner_usps_address_validation/readme/CREDITS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Financial support**

* Open Source Integrators
3 changes: 3 additions & 0 deletions partner_usps_address_validation/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This module adds a tool to the Contacts page which validates the contact's address.
Simply click the 'Validate' button, and the address of the contact will be compared to the USPS address database.
The result will be a cleaned address, including the full 9 digit zipcode, in the exact format recognized by USPS.
1 change: 1 addition & 0 deletions partner_usps_address_validation/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
xmltodict
3 changes: 3 additions & 0 deletions partner_usps_address_validation/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_usps_address_validation,usps_address_validation,model_usps_address_validation,base.group_user,1,1,1,0
access_usps_address_validation_manager,manager_usps_address_validation,model_usps_address_validation,base.group_user,1,1,1,1
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions partner_usps_address_validation/views/config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.base.setup</field>
<field name="model">res.config.settings</field>
<field name="priority" eval="0" />
<field name="inherit_id" ref="base.res_config_settings_view_form" />
<field name="arch" type="xml">
<xpath expr="//*[@name='integration']" position="inside">
<div class="col-12 col-lg-6 o_setting_box" id="usps_address"><div
class="o_setting_right_pane"
id="usps_settings"
>
<div class="o_form_label">USPS Address Validation Settings</div>
<div class="content-group" id="usps_configuration_settings">
<div class="mt16 row">
<label
class="o_form_label col-3 o_light_label"
for="usps_username"
>Username</label>
<field name="usps_username" />
<label
class="o_form_label col-3 o_light_label"
for="usps_password"
>Password</label>
<field name="usps_password" />
<label
class="o_form_label col-3 o_light_label"
for="usps_api_url"
>API URL</label>
<field name="usps_api_url" />
</div>
<div>
<a
href="https://www.usps.com/business/web-tools-apis/"
class="oe_link"
target="_blank"
>
<i class="fa fa-arrow-right">
</i> Create USPS API account
</a></div></div></div></div>
</xpath>
</field>
</record>
</odoo>
Loading
Loading