Skip to content

Commit

Permalink
[ADD]website_sale_partner_firstname: New module to set lastname from …
Browse files Browse the repository at this point in the history
…portal
  • Loading branch information
manuelregidor committed Sep 18, 2023
1 parent 1e6bec1 commit 00c93a3
Show file tree
Hide file tree
Showing 18 changed files with 451 additions and 0 deletions.
6 changes: 6 additions & 0 deletions setup/website_contact_lastname/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
5 changes: 5 additions & 0 deletions website_sale_partner_firstname/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import controllers
from . import models
22 changes: 22 additions & 0 deletions website_sale_partner_firstname/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "Website Contact Lastname",
"version": "15.0.1.0.0",
"category": "Website",
"website": "https://github.com/OCA/website",
"author": "Sygel Technology," "Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"website_account_fiscal_position_partner_type",
"partner_firstname",
],
"data": [
"views/templates.xml",
"views/auth_signup_login_templates.xml",
"views/portal_templates.xml",
],
}
5 changes: 5 additions & 0 deletions website_sale_partner_firstname/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import main
from . import portal
159 changes: 159 additions & 0 deletions website_sale_partner_firstname/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import _
from odoo.http import request

from odoo.addons.auth_signup.controllers.main import AuthSignupHome
from odoo.addons.website_sale.controllers.main import WebsiteSale


class WebsiteSale(WebsiteSale):
def _get_mandatory_fields_shipping(self, country_id=False):
req = super()._get_mandatory_fields_shipping(country_id)
req += ["firstname"]
if "name" in req:
req.remove("name")
return req

def _get_mandatory_fields_billing(self, country_id=False):
req = super()._get_mandatory_fields_billing(country_id)
req.append("firstname")
if request.env.context.get("fiscal_position_type") == "b2c":
req.append("lastname")
# Name is removed as this field cannot be explicitly edited
# It is edited in the backend through the fields first name
# and lastname
if "name" in req:
req.remove("name")
return req

def values_postprocess(self, order, mode, values, errors, error_msg):
new_values, errors, error_msg = super(WebsiteSale, self).values_postprocess(
order=order, mode=mode, values=values, errors=errors, error_msg=error_msg
)
new_values.update(
{
"firstname": values.get("firstname") or "",
"lastname": values.get("lastname") or "",
}
)
# Name is removed as this field cannot be explicitly edited
# It is edited in the backend through the fields first name
# and lastname
new_values.pop("name")
return new_values, errors, error_msg

def checkout_form_validate(self, mode, all_form_values, data):
required_fields = [
f for f in (all_form_values.get("field_required") or "").split(",") if f
]
# Name is removed as this field cannot be explicitly edited
# It is edited in the backend through the fields first name
# and lastname
if "name" in required_fields:
required_fields.remove("name")
all_form_values["field_required"] = ",".join(required_fields)
error, error_message = super().checkout_form_validate(
mode, all_form_values, data
)
if data.get("partner_id"):
partner_su = (
request.env["res.partner"]
.sudo()
.browse(int(data["partner_id"]))
.exists()
)
can_edit_vat = (
partner_su.parent_id.can_edit_vat()
if partner_su.parent_id
else partner_su.can_edit_vat()
)
firstname_change = (
partner_su
and "firstname" in data
and data["firstname"] != partner_su.firstname
)
if firstname_change and not can_edit_vat:
error["firstname"] = "error"
error_message.append(
_(
"Changing your name is not allowed once invoices have been"
" issued for your account. Please contact us directly for "
"this operation."
)
)
# When lastname field in form is empty, its values is False
# When lastname field in backend is empty, its values is ''
# In that case, if both are compared, they are considered to be
# different so data['lastname'] != partner_su.lastname would
# return True although no real change would have been applied.
lastname_change = (
partner_su
and "lastname" in data
and data["lastname"] != partner_su.lastname
and (data["lastname"] or partner_su.lastname not in ["", False])
)
if lastname_change and not can_edit_vat:
error["lastname"] = "error"
error_message.append(
_(
"Changing your last name is not allowed once invoices have"
" been issued for your account. Please contact us directly"
" for this operation."
)
)

# Prevent change the partner name, lastname if
# it is an internal user.
if (firstname_change or lastname_change) and not all(
partner_su.user_ids.mapped("share")
):
error.update(
{
"firstname": "error" if firstname_change else None,
"lastname": "error" if lastname_change else None,
}
)
error_message.append(
_(
"If you are ordering for an external person, please place "
"your order via the backend. If you wish to change your "
"name or last name, please do so in the account settings "
"or contact your administrator."
)
)
return error, error_message


class AuthSignupHome(AuthSignupHome):
def get_auth_signup_qcontext(self):
qcontext = super().get_auth_signup_qcontext()
qcontext.update(
{
k: v
for (k, v) in request.params.items()
if k
in {
"lastname",
}
}
)
if "name" in qcontext:
qcontext["firstname"] = qcontext["name"]
if (
"error" not in qcontext
and request.httprequest.method == "POST"
and qcontext.get("fiscal_position_type") == "b2c"
and not qcontext.get("lastname")
):
qcontext["error"] = _("Lastname is required for B2C users.")
return qcontext

def _prepare_signup_values(self, qcontext):
values = super()._prepare_signup_values(qcontext)
if "firstname" in qcontext:
values["firstname"] = qcontext["firstname"]
if "lastname" in qcontext:
values["lastname"] = qcontext["lastname"]
return values
63 changes: 63 additions & 0 deletions website_sale_partner_firstname/controllers/portal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import _
from odoo.http import request

from odoo.addons.portal.controllers.portal import CustomerPortal


class CustomerPortal(CustomerPortal):

CustomerPortal.OPTIONAL_BILLING_FIELDS += [
"firstname",
"lastname",
]

def details_form_validate(self, data):
context = dict(request.env.context)
# 'name' field cannont be updated as it would recompute fields
# firstname and lastname. That is why it is set in context
# that changes in field name need to be ignored.
context.update({"name_ignore": True})
request.env.context = context
error, error_message = super().details_form_validate(data)
partner = request.env.user.partner_id
if partner.can_edit_vat():
if "firstname" in data and not data.get("Name"):
error["firstname"] = "error"
error_message.append(_("Firstname is mandatory."))
if (
"lastname" in data
and not data.get("lastname")
and (
(data.get("fiscal_position_type") == "b2c")
or (
partner.fiscal_position_type == "b2c"
and not data.get("fiscal_position_type") == "b2b"
)
)
):
error["lastname"] = "error"
error["fiscal_position_type"] = "error"
error_message.append(_("Lastname is mandatory for B2C users."))
else:
if "firstname" in data and data.get("firstname") != partner.firstname:
error["firstname"] = "error"
error_message.append(
_(
"Changing Name is not allowed once document(s) have been "
"issued for your account. Please contact us directly for "
"this operation."
)
)
if "lastname" in data and data.get("lastname") != partner.lastname:
error["lastname"] = "error"
error_message.append(
_(
"Changing Lastname is not allowed once document(s) have "
"been issued for your account. Please contact us directly "
"for this operation."
)
)
return error, error_message
5 changes: 5 additions & 0 deletions website_sale_partner_firstname/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import res_users
from . import res_partner
26 changes: 26 additions & 0 deletions website_sale_partner_firstname/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl-3).

from odoo import api, models
from odoo.http import request


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

@api.model
def signup_retrieve_info(self, token):
res = super().signup_retrieve_info(token)
partner = self._signup_retrieve_partner(token, raise_exception=True)
res.update(
{
"name": partner.firstname,
"lastname": partner.lastname,
}
)
return res

def write(self, vals):
if vals.get("name") and request.env.context.get("name_ignore"):
vals.pop("name")
return super().write(vals)
37 changes: 37 additions & 0 deletions website_sale_partner_firstname/models/res_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl-3).

from odoo import api, models


class ResUsers(models.Model):
_inherit = "res.users"

@api.model
def signup(self, values, token=None):
if token:
partner = self.env["res.partner"]._signup_retrieve_partner(
token, check_validity=True, raise_exception=True
)
partner_user = partner.user_ids and partner.user_ids[0] or False
# Don't update firstname and lastname if partner
# related to user exists (i.e. when resetting password)
if partner_user:
values.pop("firstname", None)
values.pop("lastname", None)
return super().signup(values, token)

def _create_user_from_template(self, values):
user = super()._create_user_from_template(values)
# Because of the way the name is computed, it is important to
# reset the values so the final name is correct.
# It cannot be done before (the way would be setting the value of name
# if param. values to '') as the funcion _create_user_from_template
# checks that values contains a value for 'name'
user.write(
{
"firstname": values.get("firstname"),
"lastname": values.get("lastname"),
}
)
return user
1 change: 1 addition & 0 deletions website_sale_partner_firstname/readme/CONFIGURE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No configuration needed.
3 changes: 3 additions & 0 deletions website_sale_partner_firstname/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Sygel <https://www.sygel.es>`_:

* Manuel Regidor
2 changes: 2 additions & 0 deletions website_sale_partner_firstname/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This module allows users to introduce and edit their lastname
from the portal.
8 changes: 8 additions & 0 deletions website_sale_partner_firstname/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Lastname can be set from 3 differents places in the portal:

* Signup page
* User's details page
* Checkout billing address page
* Checkout shipping address page

In all cases but the checkout shipping address page, lastname field must be filled if the user is B2C. Otherwise, it can be left blank. In the checkout shipping address page, lastname can be left blank.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2023 Manuel Regidor <[email protected]>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<template id="website_contact_lastname_auth_signup" inherit_id="auth_signup.fields">
<xpath expr="//div[hasclass('field-name')]" position="after">
<div class="form-group field-lastname">
<label for="name">Last Name</label>
<input
type="text"
name="lastname"
t-att-value="lastname"
id="lastname"
class="form-control form-control-sm"
t-att-readonly="'readonly' if only_passwords else None"
t-att-autofocus="'autofocus' if login and not only_passwords else None"
/>
</div>
</xpath>
</template>
</odoo>
Loading

0 comments on commit 00c93a3

Please sign in to comment.