Compare commits
2 commits
26bfa028d1
...
135967019e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
135967019e | ||
|
|
0eb7957a70 |
7 changed files with 244 additions and 9 deletions
|
|
@ -268,6 +268,13 @@ class AplicoopWebsiteSale(WebsiteSale):
|
|||
"items": env_lang._("items"),
|
||||
"added_to_cart": env_lang._("added to cart"),
|
||||
"out_of_stock": env_lang._("Out of stock"),
|
||||
# ============ CLEAR CART ============
|
||||
"clear_cart": env_lang._("Clear Cart"),
|
||||
"clear_cart_confirm": env_lang._(
|
||||
"Are you sure you want to clear the cart? This will also cancel any saved draft order."
|
||||
),
|
||||
"cart_cleared": env_lang._("Cart cleared"),
|
||||
"draft_cancelled": env_lang._("draft order cancelled"),
|
||||
}
|
||||
|
||||
return labels
|
||||
|
|
@ -2415,6 +2422,107 @@ class AplicoopWebsiteSale(WebsiteSale):
|
|||
status=500,
|
||||
)
|
||||
|
||||
@http.route(
|
||||
["/eskaera/clear-cart"],
|
||||
type="http",
|
||||
auth="user",
|
||||
website=True,
|
||||
methods=["POST"],
|
||||
csrf=False,
|
||||
)
|
||||
def clear_cart(self, **post):
|
||||
"""Clear the user's cart and cancel any existing draft sale.order.
|
||||
|
||||
Receives: JSON body with 'order_id'
|
||||
Returns: JSON with success status and cancelled_order_id if applicable.
|
||||
"""
|
||||
try:
|
||||
data = self._decode_json_body()
|
||||
except ValueError as e:
|
||||
return request.make_response(
|
||||
json.dumps({"error": str(e)}),
|
||||
[("Content-Type", "application/json")],
|
||||
status=400,
|
||||
)
|
||||
|
||||
order_id = data.get("order_id")
|
||||
if not order_id:
|
||||
return request.make_response(
|
||||
json.dumps({"error": "order_id is required"}),
|
||||
[("Content-Type", "application/json")],
|
||||
status=400,
|
||||
)
|
||||
try:
|
||||
order_id = int(order_id)
|
||||
except (ValueError, TypeError):
|
||||
return request.make_response(
|
||||
json.dumps({"error": f"Invalid order_id format: {order_id}"}),
|
||||
[("Content-Type", "application/json")],
|
||||
status=400,
|
||||
)
|
||||
|
||||
group_order = request.env["group.order"].sudo().browse(order_id)
|
||||
if not group_order.exists():
|
||||
return request.make_response(
|
||||
json.dumps({"error": f"Order {order_id} not found"}),
|
||||
[("Content-Type", "application/json")],
|
||||
status=404,
|
||||
)
|
||||
|
||||
current_user = request.env.user
|
||||
if not current_user.partner_id:
|
||||
return request.make_response(
|
||||
json.dumps({"error": "User has no associated partner"}),
|
||||
[("Content-Type", "application/json")],
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Find and cancel any existing draft sale.order for this period
|
||||
cancelled_order_id = None
|
||||
try:
|
||||
draft_orders = self._find_recent_draft_order(
|
||||
current_user.partner_id.id, group_order
|
||||
)
|
||||
if draft_orders:
|
||||
draft_order = draft_orders[0]
|
||||
cancelled_order_id = draft_order.id
|
||||
# Use action_cancel if available, otherwise unlink
|
||||
if draft_order.state == "draft":
|
||||
draft_order.sudo().action_cancel()
|
||||
_logger.info(
|
||||
"clear_cart: Cancelled draft sale.order %d for partner %d",
|
||||
draft_order.id,
|
||||
current_user.partner_id.id,
|
||||
)
|
||||
else:
|
||||
_logger.info(
|
||||
"clear_cart: Draft order %d already in state '%s', skipping cancel",
|
||||
draft_order.id,
|
||||
draft_order.state,
|
||||
)
|
||||
except Exception as e:
|
||||
_logger.warning(
|
||||
"clear_cart: Error cancelling draft order for partner %d: %s",
|
||||
current_user.partner_id.id,
|
||||
str(e),
|
||||
)
|
||||
|
||||
response_data = {
|
||||
"success": True,
|
||||
"message": request.env._("Cart cleared"),
|
||||
"cancelled_order_id": cancelled_order_id,
|
||||
}
|
||||
_logger.info(
|
||||
"clear_cart: Cart cleared for partner %d, order %d (cancelled_sale_order: %s)",
|
||||
current_user.partner_id.id,
|
||||
order_id,
|
||||
cancelled_order_id,
|
||||
)
|
||||
return request.make_response(
|
||||
json.dumps(response_data),
|
||||
[("Content-Type", "application/json")],
|
||||
)
|
||||
|
||||
@http.route(
|
||||
["/eskaera/save-order"],
|
||||
type="http",
|
||||
|
|
|
|||
|
|
@ -1243,12 +1243,12 @@ msgstr "Guardar como Borrador"
|
|||
#. odoo-python
|
||||
#: code:addons/website_sale_aplicoop/models/js_translations.py:0
|
||||
msgid "Save Draft"
|
||||
msgstr "Guardar borrador"
|
||||
msgstr "Confirmar Pedido"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_checkout
|
||||
msgid "Save order as draft"
|
||||
msgstr "Guardar pedido como borrador"
|
||||
msgstr "Confirmar Pedido"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
#. odoo-python
|
||||
|
|
@ -2278,3 +2278,22 @@ msgstr "Semanal"
|
|||
msgid "Whether this picking includes home delivery (from sale order)"
|
||||
msgstr "Si este albarán incluye entrega a domicilio (del pedido de venta)"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
msgid "Clear Cart"
|
||||
msgstr "Vaciar carrito"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
msgid ""
|
||||
"Are you sure you want to clear the cart? This will also cancel any saved "
|
||||
"draft order."
|
||||
msgstr ""
|
||||
"¿Estás seguro de que quieres vaciar el carrito? Esto también cancelará "
|
||||
"cualquier pedido borrador guardado."
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
msgid "Cart cleared"
|
||||
msgstr "Carrito vaciado"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
msgid "draft order cancelled"
|
||||
msgstr "pedido borrador cancelado"
|
||||
|
|
|
|||
|
|
@ -1242,12 +1242,12 @@ msgstr "Zirriborro Gisa Gorde"
|
|||
#. odoo-python
|
||||
#: code:addons/website_sale_aplicoop/models/js_translations.py:0
|
||||
msgid "Save Draft"
|
||||
msgstr "Zirriborroa gorde"
|
||||
msgstr "Eskaera Konfirmatu"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_checkout
|
||||
msgid "Save order as draft"
|
||||
msgstr "Gorde enparatzea zirriborro gisa"
|
||||
msgstr "Eskaera Zirriborro Gisa Gorde"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
#. odoo-python
|
||||
|
|
@ -2272,3 +2272,21 @@ msgstr ""
|
|||
"eskaeraren)"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
msgid "Clear Cart"
|
||||
msgstr "Saskia garbitu"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
msgid ""
|
||||
"Are you sure you want to clear the cart? This will also cancel any saved "
|
||||
"draft order."
|
||||
msgstr ""
|
||||
"Ziur zaude saskia garbitu nahi duzula? Honek gordetako zirriborro-eskaera "
|
||||
"ere ezeztatuko du."
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
msgid "Cart cleared"
|
||||
msgstr "Saskia garbituta"
|
||||
|
||||
#. module: website_sale_aplicoop
|
||||
msgid "draft order cancelled"
|
||||
msgstr "zirriborro-eskaera ezeztatu da"
|
||||
|
|
|
|||
|
|
@ -173,3 +173,13 @@ def _register_translations():
|
|||
_("Friday")
|
||||
_("Saturday")
|
||||
_("Sunday")
|
||||
|
||||
# ========================
|
||||
# Clear Cart
|
||||
# ========================
|
||||
_("Clear Cart")
|
||||
_(
|
||||
"Are you sure you want to clear the cart? This will also cancel any saved draft order."
|
||||
)
|
||||
_("Cart cleared")
|
||||
_("draft order cancelled")
|
||||
|
|
|
|||
|
|
@ -20,14 +20,12 @@ class ProductProduct(models.Model):
|
|||
)
|
||||
|
||||
is_out_of_stock = fields.Boolean(
|
||||
string="Is Out of Stock",
|
||||
compute="_compute_stock_ribbons",
|
||||
store=False,
|
||||
help="True if virtual_available <= 0",
|
||||
)
|
||||
|
||||
is_low_stock = fields.Boolean(
|
||||
string="Is Low Stock",
|
||||
compute="_compute_stock_ribbons",
|
||||
store=False,
|
||||
help="True if 0 < virtual_available <= threshold",
|
||||
|
|
|
|||
|
|
@ -748,6 +748,22 @@
|
|||
});
|
||||
}
|
||||
|
||||
// Buttons to clear cart (header + footer)
|
||||
var clearCartBtns = [
|
||||
document.getElementById("clear-cart-btn"),
|
||||
document.getElementById("clear-cart-btn-footer"),
|
||||
];
|
||||
clearCartBtns.forEach(function (btn) {
|
||||
if (btn) {
|
||||
console.log("[_attachEventListeners] clear-cart-btn found:", btn.id);
|
||||
btn.addEventListener("click", function (e) {
|
||||
console.log("[CLICK] clear-cart-btn clicked");
|
||||
e.preventDefault();
|
||||
self._clearCart();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this._cartCheckoutListenersAttached = true;
|
||||
console.log("[_attachEventListeners] Checkout listeners attached (one-time)");
|
||||
}
|
||||
|
|
@ -1029,6 +1045,12 @@
|
|||
draft_replace_warning: "The existing draft will be permanently deleted.",
|
||||
draft_merge_btn: "Merge",
|
||||
draft_replace_btn: "Replace",
|
||||
// Clear cart labels
|
||||
clear_cart: "Clear Cart",
|
||||
clear_cart_confirm:
|
||||
"Are you sure you want to clear the cart? This will also cancel any saved draft order.",
|
||||
cart_cleared: "Cart cleared",
|
||||
draft_cancelled: "draft order cancelled",
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -1636,6 +1658,60 @@
|
|||
xhr.send(JSON.stringify(orderData));
|
||||
},
|
||||
|
||||
_clearCart: function () {
|
||||
var self = this;
|
||||
var labels = this._getLabels();
|
||||
var confirmMsg =
|
||||
labels.clear_cart_confirm ||
|
||||
"Are you sure you want to clear the cart? This will also cancel any saved draft order.";
|
||||
|
||||
if (!window.confirm(confirmMsg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear localStorage immediately
|
||||
this._clearCurrentOrderCartSilently();
|
||||
this._updateCartDisplay();
|
||||
|
||||
// Cancel draft sale.order on the server
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/eskaera/clear-cart", true);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
xhr.onload = function () {
|
||||
var labels2 = self._getLabels();
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
var data = JSON.parse(xhr.responseText);
|
||||
if (data.success) {
|
||||
var msg = labels2.cart_cleared || "Cart cleared";
|
||||
if (data.cancelled_order_id) {
|
||||
msg +=
|
||||
" (" +
|
||||
(labels2.draft_cancelled || "draft order cancelled") +
|
||||
")";
|
||||
}
|
||||
self._showNotification("✓ " + msg, "success", 4000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[_clearCart] Error parsing response:", e);
|
||||
}
|
||||
} else {
|
||||
console.warn("[_clearCart] Server error:", xhr.status, xhr.responseText);
|
||||
// Cart is already cleared locally, server error is non-critical
|
||||
self._showNotification(labels2.cart_cleared || "Cart cleared", "success", 3000);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function () {
|
||||
console.warn("[_clearCart] Network error, but cart already cleared locally");
|
||||
var labels2 = self._getLabels();
|
||||
self._showNotification(labels2.cart_cleared || "Cart cleared", "success", 3000);
|
||||
};
|
||||
|
||||
xhr.send(JSON.stringify({ order_id: this.orderId }));
|
||||
},
|
||||
|
||||
_saveOrderDraft: function () {
|
||||
console.log("[_saveOrderDraft] Starting - this.orderId:", this.orderId);
|
||||
|
||||
|
|
|
|||
|
|
@ -283,15 +283,21 @@
|
|||
<a t-attf-href="/eskaera/{{ group_order.id }}/checkout" class="btn btn-success cart-btn-compact" aria-label="Proceed to checkout" data-bs-title="Proceed to Checkout" data-bs-toggle="tooltip">
|
||||
<i class="fa fa-check cart-icon-size" aria-hidden="true" />
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-danger cart-btn-compact" id="clear-cart-btn" t-attf-data-order-id="{{ group_order.id }}" data-bs-title="Clear Cart" data-bs-toggle="tooltip" aria-label="Clear Cart">
|
||||
<i class="fa fa-trash cart-icon-size" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body cart-body-lg" id="cart-items-container" t-attf-data-order-id="{{ group_order.id }}" aria-labelledby="cart-title" aria-live="polite" aria-relevant="additions removals">
|
||||
<p class="text-muted">This order's cart is empty</p>
|
||||
</div>
|
||||
<div class="card-footer bg-white text-center">
|
||||
<div class="card-footer bg-white d-flex justify-content-between align-items-center gap-2">
|
||||
<button type="button" class="btn btn-outline-danger btn-sm" id="clear-cart-btn-footer" t-attf-data-order-id="{{ group_order.id }}" data-bs-title="Clear Cart" data-bs-toggle="tooltip" aria-label="Clear Cart">
|
||||
<i class="fa fa-trash me-1" aria-hidden="true" />Clear Cart
|
||||
</button>
|
||||
<a t-attf-href="/eskaera/{{ group_order.id }}/checkout" class="btn btn-success checkout-btn-lg" data-bs-title="Proceed to Checkout" data-bs-toggle="tooltip">
|
||||
Proceed to Checkout
|
||||
</a>
|
||||
Proceed to Checkout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue