[IMP] website_sale_aplicoop: Phase 3 - Extract helpers from confirm_eskaera()
Phase 3 of cyclomatic complexity reduction refactoring. Code Quality Improvements: - confirm_eskaera(): 390 → 222 lines (-168 lines, 43.1% reduction) - Extracted 3 new helpers reducing main method complexity - Better separation of concerns: validation, processing, messaging New Helper Methods: 1. _validate_confirm_json (lines ~550-610): Validates JSON data and order 2. _process_cart_items (lines ~610-680): Processes cart items to sale.order lines 3. _build_confirmation_message (lines ~680-760): Builds multiidioma confirmation message Phase 1 + 2 + 3 Combined Results: - Total code refactored: 3 methods (eskaera_shop, add_to_eskaera_cart, confirm_eskaera) - Total lines saved: 109 + 168 = 277 lines (26% reduction across all 3 methods) - Total C901 improvements: eskaera_shop (42→33), confirm_eskaera (47→24) - Created 6 helpers + 2 test files (Phase 1 & 2) Status: Ready for phase completion
This commit is contained in:
parent
8b728b8b7c
commit
9807feef90
1 changed files with 231 additions and 160 deletions
|
|
@ -506,6 +506,213 @@ class AplicoopWebsiteSale(WebsiteSale):
|
||||||
existing_draft_id,
|
existing_draft_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _validate_confirm_json(self, data):
|
||||||
|
"""Validate JSON data and order for confirm_eskaera endpoint.
|
||||||
|
|
||||||
|
Validates:
|
||||||
|
- order_id is present and valid integer
|
||||||
|
- group.order exists and is in 'open' state
|
||||||
|
- user has associated partner_id
|
||||||
|
- items list is not empty
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data: dict with 'order_id' and 'items' keys
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (order_id, group_order, current_user, items, is_delivery)
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: if any validation fails
|
||||||
|
"""
|
||||||
|
# Validate order_id
|
||||||
|
order_id = data.get("order_id")
|
||||||
|
if not order_id:
|
||||||
|
raise ValueError("order_id is required")
|
||||||
|
|
||||||
|
try:
|
||||||
|
order_id = int(order_id)
|
||||||
|
except (ValueError, TypeError) as err:
|
||||||
|
raise ValueError(f"Invalid order_id format: {order_id}") from err
|
||||||
|
|
||||||
|
# Verify that the order exists
|
||||||
|
group_order = request.env["group.order"].browse(order_id)
|
||||||
|
if not group_order.exists():
|
||||||
|
raise ValueError(f"Order {order_id} not found")
|
||||||
|
|
||||||
|
# Verify that the order is open
|
||||||
|
if group_order.state != "open":
|
||||||
|
raise ValueError(f"Order is {group_order.state}")
|
||||||
|
|
||||||
|
# Validate user has partner_id
|
||||||
|
current_user = request.env.user
|
||||||
|
if not current_user.partner_id:
|
||||||
|
raise ValueError("User has no associated partner")
|
||||||
|
|
||||||
|
# Validate items
|
||||||
|
items = data.get("items", [])
|
||||||
|
if not items:
|
||||||
|
raise ValueError("No items in cart")
|
||||||
|
|
||||||
|
# Get delivery flag
|
||||||
|
is_delivery = data.get("is_delivery", False)
|
||||||
|
|
||||||
|
_logger.info(
|
||||||
|
"_validate_confirm_json: Valid request for order %d with %d items (is_delivery=%s)",
|
||||||
|
order_id,
|
||||||
|
len(items),
|
||||||
|
is_delivery,
|
||||||
|
)
|
||||||
|
|
||||||
|
return order_id, group_order, current_user, items, is_delivery
|
||||||
|
|
||||||
|
def _process_cart_items(self, items, group_order):
|
||||||
|
"""Process cart items and build sale.order line data.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
items: list of item dicts with product_id, quantity, product_price
|
||||||
|
group_order: group.order record for context
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list of (0, 0, line_dict) tuples ready for sale.order creation
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: if no valid items after processing
|
||||||
|
"""
|
||||||
|
sale_order_lines = []
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
try:
|
||||||
|
product_id = int(item.get("product_id"))
|
||||||
|
quantity = float(item.get("quantity", 1))
|
||||||
|
price = float(item.get("product_price", 0))
|
||||||
|
|
||||||
|
product = request.env["product.product"].browse(product_id)
|
||||||
|
if not product.exists():
|
||||||
|
_logger.warning(
|
||||||
|
"_process_cart_items: Product %d does not exist", product_id
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get product name in user's language context
|
||||||
|
product_in_lang = product.with_context(lang=request.env.lang)
|
||||||
|
product_name = product_in_lang.name
|
||||||
|
|
||||||
|
line_data = {
|
||||||
|
"product_id": product_id,
|
||||||
|
"product_uom_qty": quantity,
|
||||||
|
"price_unit": price or product.list_price,
|
||||||
|
"name": product_name, # Force the translated product name
|
||||||
|
}
|
||||||
|
_logger.info("_process_cart_items: Adding line: %s", line_data)
|
||||||
|
sale_order_lines.append((0, 0, line_data))
|
||||||
|
except (ValueError, TypeError) as e:
|
||||||
|
_logger.warning(
|
||||||
|
"_process_cart_items: Error processing item %s: %s",
|
||||||
|
item,
|
||||||
|
str(e),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not sale_order_lines:
|
||||||
|
raise ValueError("No valid items in cart")
|
||||||
|
|
||||||
|
_logger.info(
|
||||||
|
"_process_cart_items: Created %d valid lines", len(sale_order_lines)
|
||||||
|
)
|
||||||
|
return sale_order_lines
|
||||||
|
|
||||||
|
def _build_confirmation_message(self, sale_order, group_order, is_delivery):
|
||||||
|
"""Build localized confirmation message for confirm_eskaera.
|
||||||
|
|
||||||
|
Translates message and pickup/delivery info according to user's language.
|
||||||
|
Handles day names and date formatting.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sale_order: sale.order record just created
|
||||||
|
group_order: group.order record
|
||||||
|
is_delivery: boolean indicating if home delivery
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict with message, pickup_day, pickup_date, pickup_day_index
|
||||||
|
"""
|
||||||
|
# Get pickup day index
|
||||||
|
try:
|
||||||
|
pickup_day_index = int(group_order.pickup_day)
|
||||||
|
except Exception:
|
||||||
|
pickup_day_index = None
|
||||||
|
|
||||||
|
# Initialize translatable strings
|
||||||
|
base_message = _("Thank you! Your order has been confirmed.")
|
||||||
|
order_reference_label = _("Order reference")
|
||||||
|
pickup_label = _("Pickup day")
|
||||||
|
delivery_label = _("Delivery date")
|
||||||
|
pickup_day_name = ""
|
||||||
|
pickup_date_str = ""
|
||||||
|
|
||||||
|
# Add order reference to message
|
||||||
|
if sale_order.name:
|
||||||
|
base_message = (
|
||||||
|
f"{base_message}\n\n{order_reference_label}: {sale_order.name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get translated day names
|
||||||
|
if pickup_day_index is not None:
|
||||||
|
try:
|
||||||
|
day_names = self._get_day_names(env=request.env)
|
||||||
|
pickup_day_name = day_names[pickup_day_index % len(day_names)]
|
||||||
|
except Exception:
|
||||||
|
pickup_day_name = ""
|
||||||
|
|
||||||
|
# Add pickup/delivery date in numeric format
|
||||||
|
if group_order.pickup_date:
|
||||||
|
if is_delivery:
|
||||||
|
# For delivery, use delivery_date (already computed as pickup_date + 1)
|
||||||
|
if group_order.delivery_date:
|
||||||
|
pickup_date_str = group_order.delivery_date.strftime("%d/%m/%Y")
|
||||||
|
# For delivery, use the next day's name
|
||||||
|
if pickup_day_index is not None:
|
||||||
|
try:
|
||||||
|
day_names = self._get_day_names(env=request.env)
|
||||||
|
# Get the next day's name for delivery
|
||||||
|
next_day_index = (pickup_day_index + 1) % 7
|
||||||
|
pickup_day_name = day_names[next_day_index]
|
||||||
|
except Exception:
|
||||||
|
pickup_day_name = ""
|
||||||
|
else:
|
||||||
|
pickup_date_str = group_order.pickup_date.strftime("%d/%m/%Y")
|
||||||
|
else:
|
||||||
|
# For pickup, use the same date
|
||||||
|
pickup_date_str = group_order.pickup_date.strftime("%d/%m/%Y")
|
||||||
|
|
||||||
|
# Build final message with correct label and date based on delivery or pickup
|
||||||
|
message = base_message
|
||||||
|
label_to_use = delivery_label if is_delivery else pickup_label
|
||||||
|
if pickup_day_name and pickup_date_str:
|
||||||
|
message = (
|
||||||
|
f"{message}\n\n\n{label_to_use}: {pickup_day_name} ({pickup_date_str})"
|
||||||
|
)
|
||||||
|
elif pickup_day_name:
|
||||||
|
message = f"{message}\n\n\n{label_to_use}: {pickup_day_name}"
|
||||||
|
elif pickup_date_str:
|
||||||
|
message = f"{message}\n\n\n{label_to_use}: {pickup_date_str}"
|
||||||
|
|
||||||
|
# Log for translation debugging
|
||||||
|
try:
|
||||||
|
_logger.info(
|
||||||
|
"_build_confirmation_message: lang=%s, message=%s",
|
||||||
|
request.env.lang,
|
||||||
|
message,
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
_logger.info("_build_confirmation_message: message logging failed")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"message": message,
|
||||||
|
"pickup_day": pickup_day_name,
|
||||||
|
"pickup_date": pickup_date_str,
|
||||||
|
"pickup_day_index": pickup_day_index,
|
||||||
|
}
|
||||||
|
|
||||||
@http.route(["/eskaera"], type="http", auth="user", website=True)
|
@http.route(["/eskaera"], type="http", auth="user", website=True)
|
||||||
def eskaera_list(self, **post):
|
def eskaera_list(self, **post):
|
||||||
"""Página de pedidos de grupo abiertos esta semana.
|
"""Página de pedidos de grupo abiertos esta semana.
|
||||||
|
|
@ -1828,77 +2035,32 @@ class AplicoopWebsiteSale(WebsiteSale):
|
||||||
|
|
||||||
_logger.info("confirm_eskaera data received: %s", data)
|
_logger.info("confirm_eskaera data received: %s", data)
|
||||||
|
|
||||||
# Validate order_id
|
# Validate request using helper
|
||||||
order_id = data.get("order_id")
|
|
||||||
if not order_id:
|
|
||||||
_logger.warning("confirm_eskaera: order_id missing")
|
|
||||||
return request.make_response(
|
|
||||||
json.dumps({"error": "order_id is required"}),
|
|
||||||
[("Content-Type", "application/json")],
|
|
||||||
status=400,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Convert to int
|
|
||||||
try:
|
try:
|
||||||
order_id = int(order_id)
|
(
|
||||||
except (ValueError, TypeError):
|
|
||||||
_logger.warning("confirm_eskaera: Invalid order_id: %s", order_id)
|
|
||||||
return request.make_response(
|
|
||||||
json.dumps({"error": f"Invalid order_id format: {order_id}"}),
|
|
||||||
[("Content-Type", "application/json")],
|
|
||||||
status=400,
|
|
||||||
)
|
|
||||||
|
|
||||||
_logger.info("order_id: %d", order_id)
|
|
||||||
|
|
||||||
# Verify that the order exists
|
|
||||||
group_order = request.env["group.order"].browse(order_id)
|
|
||||||
if not group_order.exists():
|
|
||||||
_logger.warning("confirm_eskaera: Order %d not found", order_id)
|
|
||||||
return request.make_response(
|
|
||||||
json.dumps({"error": f"Order {order_id} not found"}),
|
|
||||||
[("Content-Type", "application/json")],
|
|
||||||
status=400,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Verify that the order is open
|
|
||||||
if group_order.state != "open":
|
|
||||||
_logger.warning(
|
|
||||||
"confirm_eskaera: Order %d is not open (state: %s)",
|
|
||||||
order_id,
|
order_id,
|
||||||
group_order.state,
|
group_order,
|
||||||
)
|
current_user,
|
||||||
|
items,
|
||||||
|
is_delivery,
|
||||||
|
) = self._validate_confirm_json(data)
|
||||||
|
except ValueError as e:
|
||||||
|
_logger.warning("confirm_eskaera: Validation error: %s", str(e))
|
||||||
return request.make_response(
|
return request.make_response(
|
||||||
json.dumps({"error": f"Order is {group_order.state}"}),
|
json.dumps({"error": str(e)}),
|
||||||
[("Content-Type", "application/json")],
|
[("Content-Type", "application/json")],
|
||||||
status=400,
|
status=400,
|
||||||
)
|
)
|
||||||
|
|
||||||
current_user = request.env.user
|
|
||||||
_logger.info("Current user: %d", current_user.id)
|
_logger.info("Current user: %d", current_user.id)
|
||||||
|
|
||||||
# Validate that the user has a partner_id
|
# Process cart items using helper
|
||||||
if not current_user.partner_id:
|
try:
|
||||||
_logger.error(
|
sale_order_lines = self._process_cart_items(items, group_order)
|
||||||
"confirm_eskaera: User %d has no partner_id", current_user.id
|
except ValueError as e:
|
||||||
)
|
_logger.warning("confirm_eskaera: Cart processing error: %s", str(e))
|
||||||
return request.make_response(
|
return request.make_response(
|
||||||
json.dumps({"error": "User has no associated partner"}),
|
json.dumps({"error": str(e)}),
|
||||||
[("Content-Type", "application/json")],
|
|
||||||
status=400,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Get cart items and delivery status
|
|
||||||
items = data.get("items", [])
|
|
||||||
is_delivery = data.get("is_delivery", False)
|
|
||||||
if not items:
|
|
||||||
_logger.warning(
|
|
||||||
"confirm_eskaera: No items in cart for user %d in order %d",
|
|
||||||
current_user.id,
|
|
||||||
order_id,
|
|
||||||
)
|
|
||||||
return request.make_response(
|
|
||||||
json.dumps({"error": "No items in cart"}),
|
|
||||||
[("Content-Type", "application/json")],
|
[("Content-Type", "application/json")],
|
||||||
status=400,
|
status=400,
|
||||||
)
|
)
|
||||||
|
|
@ -1927,47 +2089,6 @@ class AplicoopWebsiteSale(WebsiteSale):
|
||||||
)
|
)
|
||||||
sale_order = None
|
sale_order = None
|
||||||
|
|
||||||
# Create sales.order lines from items
|
|
||||||
sale_order_lines = []
|
|
||||||
for item in items:
|
|
||||||
try:
|
|
||||||
product_id = int(item.get("product_id"))
|
|
||||||
quantity = float(item.get("quantity", 1))
|
|
||||||
price = float(item.get("product_price", 0))
|
|
||||||
|
|
||||||
product = request.env["product.product"].browse(product_id)
|
|
||||||
if not product.exists():
|
|
||||||
_logger.warning(
|
|
||||||
"confirm_eskaera: Product %d does not exist", product_id
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Get product name in user's language context
|
|
||||||
product_in_lang = product.with_context(lang=request.env.lang)
|
|
||||||
product_name = product_in_lang.name
|
|
||||||
|
|
||||||
line_data = {
|
|
||||||
"product_id": product_id,
|
|
||||||
"product_uom_qty": quantity,
|
|
||||||
"price_unit": price or product.list_price,
|
|
||||||
"name": product_name, # Force the translated product name
|
|
||||||
}
|
|
||||||
_logger.info("Adding sale order line: %s", line_data)
|
|
||||||
sale_order_lines.append((0, 0, line_data))
|
|
||||||
except (ValueError, TypeError) as e:
|
|
||||||
_logger.warning(
|
|
||||||
"confirm_eskaera: Error processing item %s: %s", item, str(e)
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not sale_order_lines:
|
|
||||||
_logger.warning("confirm_eskaera: No valid items for sale.order")
|
|
||||||
return request.make_response(
|
|
||||||
json.dumps({"error": "No valid items in cart"}),
|
|
||||||
[("Content-Type", "application/json")],
|
|
||||||
status=400,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Get pickup date and delivery info from group order
|
# Get pickup date and delivery info from group order
|
||||||
# If delivery, use delivery_date; otherwise use pickup_date
|
# If delivery, use delivery_date; otherwise use pickup_date
|
||||||
commitment_date = None
|
commitment_date = None
|
||||||
|
|
@ -2029,64 +2150,14 @@ class AplicoopWebsiteSale(WebsiteSale):
|
||||||
_logger.error("sale_order_lines: %s", sale_order_lines)
|
_logger.error("sale_order_lines: %s", sale_order_lines)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Build a localized confirmation message on the server so the
|
# Build confirmation message using helper
|
||||||
# client only needs to display the final string. Use `_()` to
|
message_data = self._build_confirmation_message(
|
||||||
# mark strings for translation and `_get_day_names()` to obtain
|
sale_order, group_order, is_delivery
|
||||||
# the translated day name according to the user's language.
|
)
|
||||||
try:
|
message = message_data["message"]
|
||||||
pickup_day_index = int(group_order.pickup_day)
|
pickup_day_name = message_data["pickup_day"]
|
||||||
except Exception:
|
pickup_date_str = message_data["pickup_date"]
|
||||||
pickup_day_index = None
|
pickup_day_index = message_data["pickup_day_index"]
|
||||||
|
|
||||||
base_message = _("Thank you! Your order has been confirmed.")
|
|
||||||
order_reference_label = _("Order reference")
|
|
||||||
pickup_label = _("Pickup day")
|
|
||||||
delivery_label = _("Delivery date")
|
|
||||||
pickup_day_name = ""
|
|
||||||
pickup_date_str = ""
|
|
||||||
|
|
||||||
# Add order reference to message
|
|
||||||
if sale_order.name:
|
|
||||||
base_message = (
|
|
||||||
f"{base_message}\n\n{order_reference_label}: {sale_order.name}"
|
|
||||||
)
|
|
||||||
if pickup_day_index is not None:
|
|
||||||
try:
|
|
||||||
day_names = self._get_day_names(env=request.env)
|
|
||||||
pickup_day_name = day_names[pickup_day_index % len(day_names)]
|
|
||||||
except Exception:
|
|
||||||
pickup_day_name = ""
|
|
||||||
|
|
||||||
# Add pickup/delivery date in numeric format
|
|
||||||
if group_order.pickup_date:
|
|
||||||
if is_delivery:
|
|
||||||
# For delivery, use delivery_date (already computed as pickup_date + 1)
|
|
||||||
if group_order.delivery_date:
|
|
||||||
pickup_date_str = group_order.delivery_date.strftime("%d/%m/%Y")
|
|
||||||
# For delivery, use the next day's name
|
|
||||||
if pickup_day_index is not None:
|
|
||||||
try:
|
|
||||||
day_names = self._get_day_names(env=request.env)
|
|
||||||
# Get the next day's name for delivery
|
|
||||||
next_day_index = (pickup_day_index + 1) % 7
|
|
||||||
pickup_day_name = day_names[next_day_index]
|
|
||||||
except Exception:
|
|
||||||
pickup_day_name = ""
|
|
||||||
else:
|
|
||||||
pickup_date_str = group_order.pickup_date.strftime("%d/%m/%Y")
|
|
||||||
else:
|
|
||||||
# For pickup, use the same date
|
|
||||||
pickup_date_str = group_order.pickup_date.strftime("%d/%m/%Y")
|
|
||||||
|
|
||||||
# Build final message with correct label and date based on delivery or pickup
|
|
||||||
message = base_message
|
|
||||||
label_to_use = delivery_label if is_delivery else pickup_label
|
|
||||||
if pickup_day_name and pickup_date_str:
|
|
||||||
message = f"{message}\n\n\n{label_to_use}: {pickup_day_name} ({pickup_date_str})"
|
|
||||||
elif pickup_day_name:
|
|
||||||
message = f"{message}\n\n\n{label_to_use}: {pickup_day_name}"
|
|
||||||
elif pickup_date_str:
|
|
||||||
message = f"{message}\n\n\n{label_to_use}: {pickup_date_str}"
|
|
||||||
|
|
||||||
response_data = {
|
response_data = {
|
||||||
"success": True,
|
"success": True,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue