[FIX] website_sale_aplicoop: Add portal user support for sale.order creation

Portal users don't have write/create permissions on sale.order by default.
This causes errors when trying to create orders during checkout or draft save.

Changes:
- Add _get_salesperson_for_order() helper to retrieve partner's salesperson
- Use sudo() for all sale.order create() operations
- Automatically assign user_id (salesperson) when creating orders
- Use sudo() for order updates and line modifications
- Add fallback to commercial_partner_id.user_id for salesperson

This ensures orders are created with proper permissions while maintaining
traceability through the assigned salesperson.

Test coverage:
- Add test_portal_sale_order_creation.py with 3 tests
- Test portal user creates sale.order
- Test salesperson fallback logic
- Test portal user updates order lines
This commit is contained in:
snt 2026-02-21 14:09:57 +01:00
parent cf9ea887c1
commit ed8c6acd92
3 changed files with 243 additions and 28 deletions

View file

@ -831,6 +831,30 @@ class AplicoopWebsiteSale(WebsiteSale):
)
return sale_order_lines
def _get_salesperson_for_order(self, partner):
"""Get the salesperson (user_id) for creating sale orders.
For portal users without write access to sale.order, we need to create
the order as the assigned salesperson or with sudo().
Args:
partner: res.partner record
Returns:
res.users record (salesperson) or False
"""
# First check if partner has an assigned salesperson
if partner.user_id and not partner.user_id._is_public():
return partner.user_id
# Fallback to commercial partner's salesperson
commercial_partner = partner.commercial_partner_id
if commercial_partner.user_id and not commercial_partner.user_id._is_public():
return commercial_partner.user_id
# No salesperson found
return False
def _create_or_update_sale_order(
self,
group_order,
@ -846,14 +870,16 @@ class AplicoopWebsiteSale(WebsiteSale):
"""
if existing_order:
# Update existing order with new lines and propagate fields
existing_order.order_line = sale_order_lines
if not existing_order.group_order_id:
existing_order.group_order_id = group_order.id
existing_order.pickup_day = group_order.pickup_day
existing_order.pickup_date = group_order.pickup_date
existing_order.home_delivery = is_delivery
# Use sudo() to avoid permission issues with portal users
existing_order_sudo = existing_order.sudo()
existing_order_sudo.order_line = sale_order_lines
if not existing_order_sudo.group_order_id:
existing_order_sudo.group_order_id = group_order.id
existing_order_sudo.pickup_day = group_order.pickup_day
existing_order_sudo.pickup_date = group_order.pickup_date
existing_order_sudo.home_delivery = is_delivery
if commitment_date:
existing_order.commitment_date = commitment_date
existing_order_sudo.commitment_date = commitment_date
_logger.info(
"Updated existing sale.order %d: commitment_date=%s, home_delivery=%s",
existing_order.id,
@ -874,7 +900,18 @@ class AplicoopWebsiteSale(WebsiteSale):
if commitment_date:
order_vals["commitment_date"] = commitment_date
sale_order = request.env["sale.order"].create(order_vals)
# Get salesperson for order creation (portal users need this)
salesperson = self._get_salesperson_for_order(current_user.partner_id)
if salesperson:
order_vals["user_id"] = salesperson.id
_logger.info(
"Creating sale.order with salesperson %s (%d)",
salesperson.name,
salesperson.id,
)
# Create order with sudo to avoid permission issues with portal users
sale_order = request.env["sale.order"].sudo().create(order_vals)
_logger.info(
"sale.order created successfully: %d with group_order_id=%d, pickup_day=%s, home_delivery=%s",
sale_order.id,
@ -912,7 +949,18 @@ class AplicoopWebsiteSale(WebsiteSale):
elif group_order.pickup_date:
order_vals["commitment_date"] = group_order.pickup_date
sale_order = request.env["sale.order"].create(order_vals)
# Get salesperson for order creation (portal users need this)
salesperson = self._get_salesperson_for_order(current_user.partner_id)
if salesperson:
order_vals["user_id"] = salesperson.id
_logger.info(
"Creating draft sale.order with salesperson %s (%d)",
salesperson.name,
salesperson.id,
)
# Create order with sudo to avoid permission issues with portal users
sale_order = request.env["sale.order"].sudo().create(order_vals)
# Ensure the order has a name (sequence)
try:
@ -1158,7 +1206,8 @@ class AplicoopWebsiteSale(WebsiteSale):
lambda line, pid=product_id: line.product_id.id == pid
)
if existing_line:
existing_line.write(
# Use sudo() to avoid permission issues with portal users
existing_line.sudo().write(
{
"product_uom_qty": existing_line.product_uom_qty
+ new_quantity
@ -1170,7 +1219,8 @@ class AplicoopWebsiteSale(WebsiteSale):
existing_line.product_uom_qty,
)
else:
existing_draft.order_line.create(
# Use sudo() to avoid permission issues with portal users
existing_draft.order_line.sudo().create(
{
"order_id": existing_draft.id,
"product_id": product_id,
@ -1193,22 +1243,7 @@ class AplicoopWebsiteSale(WebsiteSale):
"Deleted existing draft(s) for replace: %s",
existing_drafts.mapped("id"),
)
sale_order = request.env["sale.order"].create(
{
"partner_id": current_user.partner_id.id,
"order_line": sale_order_lines,
"state": "draft",
"group_order_id": order_id,
"pickup_day": group_order.pickup_day,
"pickup_date": group_order.pickup_date,
"home_delivery": group_order.home_delivery,
}
)
return sale_order, False
# Default: create new draft
sale_order = request.env["sale.order"].create(
{
order_vals = {
"partner_id": current_user.partner_id.id,
"order_line": sale_order_lines,
"state": "draft",
@ -1217,7 +1252,30 @@ class AplicoopWebsiteSale(WebsiteSale):
"pickup_date": group_order.pickup_date,
"home_delivery": group_order.home_delivery,
}
)
# Get salesperson for order creation (portal users need this)
salesperson = self._get_salesperson_for_order(current_user.partner_id)
if salesperson:
order_vals["user_id"] = salesperson.id
sale_order = request.env["sale.order"].sudo().create(order_vals)
return sale_order, False
# Default: create new draft
order_vals = {
"partner_id": current_user.partner_id.id,
"order_line": sale_order_lines,
"state": "draft",
"group_order_id": order_id,
"pickup_day": group_order.pickup_day,
"pickup_date": group_order.pickup_date,
"home_delivery": group_order.home_delivery,
}
# Get salesperson for order creation (portal users need this)
salesperson = self._get_salesperson_for_order(current_user.partner_id)
if salesperson:
order_vals["user_id"] = salesperson.id
sale_order = request.env["sale.order"].sudo().create(order_vals)
return sale_order, False
def _decode_json_body(self):