mirror of
https://github.com/bringout/oca-ocb-sale.git
synced 2026-04-27 12:32:02 +02:00
19.0 vanilla
This commit is contained in:
parent
79f83631d5
commit
73afc09215
6267 changed files with 1534193 additions and 1130106 deletions
|
|
@ -1,4 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import cart
|
||||
from . import delivery
|
||||
from . import main
|
||||
from . import payment
|
||||
from . import portal
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import request, route
|
||||
|
||||
from odoo.addons.website_sale.controllers.cart import Cart as WebsiteSaleCart
|
||||
|
||||
|
||||
class Cart(WebsiteSaleCart):
|
||||
|
||||
@route()
|
||||
def cart(self, **post):
|
||||
if order_sudo := request.cart:
|
||||
order_sudo._update_programs_and_rewards()
|
||||
order_sudo._auto_apply_rewards()
|
||||
return super().cart(**post)
|
||||
|
||||
@route('/wallet/top_up', type='http', auth='user', website=True, sitemap=False)
|
||||
def wallet_top_up(self, **kwargs):
|
||||
product = self.env['product.product'].browse(int(kwargs['trigger_product_id']))
|
||||
self.add_to_cart(product.product_tmpl_id.id, product.id, 1)
|
||||
return request.redirect('/shop/cart')
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from functools import partial
|
||||
|
||||
from odoo.http import request, route
|
||||
|
||||
from odoo.addons.payment import utils as payment_utils
|
||||
from odoo.addons.website_sale.controllers.delivery import Delivery
|
||||
|
||||
|
||||
class WebsiteSaleLoyaltyDelivery(Delivery):
|
||||
|
||||
@route()
|
||||
def express_checkout_process_delivery_address(self, partial_delivery_address):
|
||||
"""Override of `website.sale` to include delivery discount if any."""
|
||||
res = super().express_checkout_process_delivery_address(partial_delivery_address)
|
||||
order_sudo = request.cart
|
||||
if free_shipping_lines := order_sudo._get_free_shipping_lines():
|
||||
res['delivery_discount_minor_amount'] = payment_utils.to_minor_currency_units(
|
||||
sum(free_shipping_lines.mapped('price_total')), order_sudo.currency_id
|
||||
)
|
||||
return res
|
||||
|
||||
def _order_summary_values(self, order, **post):
|
||||
to_html = partial(
|
||||
request.env['ir.qweb.field.monetary'].value_to_html,
|
||||
options={'display_currency': order.currency_id},
|
||||
)
|
||||
res = super()._order_summary_values(order, **post)
|
||||
free_shipping_lines = order._get_free_shipping_lines()
|
||||
if free_shipping_lines:
|
||||
shipping_discount = sum(free_shipping_lines.mapped('price_total'))
|
||||
res['amount_delivery_discounted'] = to_html(shipping_discount)
|
||||
res['delivery_discount_minor_amount'] = payment_utils.to_minor_currency_units(
|
||||
shipping_discount, order.currency_id
|
||||
)
|
||||
discount_lines = order.order_line.filtered(
|
||||
lambda line: line.reward_id.reward_type == 'discount'
|
||||
)
|
||||
groupable_lines = discount_lines.filtered(
|
||||
lambda line: line.reward_id.discount_mode == 'percent'
|
||||
)
|
||||
res['discount_reward_amounts'] = [
|
||||
to_html(sum(lines.mapped('price_subtotal')))
|
||||
for lines in groupable_lines.grouped('reward_id').values()
|
||||
] + [to_html(line.price_subtotal) for line in discount_lines - groupable_lines]
|
||||
return res
|
||||
|
|
@ -1,64 +1,41 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import http, _
|
||||
from odoo.addons.website_sale.controllers import main
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.http import request
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from werkzeug.urls import url_encode, url_parse
|
||||
|
||||
from odoo import _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.http import request, route
|
||||
|
||||
from odoo.addons.website_sale.controllers import main
|
||||
|
||||
|
||||
class WebsiteSale(main.WebsiteSale):
|
||||
|
||||
@http.route()
|
||||
def pricelist(self, promo, **post):
|
||||
order = request.website.sale_get_order()
|
||||
coupon_status = order._try_apply_code(promo)
|
||||
@route()
|
||||
def pricelist(self, promo, reward_id=None, **post):
|
||||
if not (order_sudo := request.cart):
|
||||
return request.redirect('/shop')
|
||||
coupon_status = order_sudo._try_apply_code(promo)
|
||||
if coupon_status.get('not_found'):
|
||||
return super(WebsiteSale, self).pricelist(promo, **post)
|
||||
return super().pricelist(promo, **post)
|
||||
elif coupon_status.get('error'):
|
||||
request.session['error_promo_code'] = coupon_status['error']
|
||||
elif 'error' not in coupon_status:
|
||||
reward_successfully_applied = True
|
||||
if len(coupon_status) == 1:
|
||||
coupon, rewards = next(iter(coupon_status.items()))
|
||||
if len(rewards) == 1 and not rewards.multi_product:
|
||||
reward_successfully_applied = self._apply_reward(order, rewards, coupon)
|
||||
if len(rewards) == 1:
|
||||
reward = rewards
|
||||
else:
|
||||
reward = reward_id in rewards.ids and rewards.browse(reward_id)
|
||||
if reward and (not reward.multi_product or request.env.context.get('product_id')):
|
||||
reward_successfully_applied = self._apply_reward(order_sudo, reward, coupon)
|
||||
|
||||
if reward_successfully_applied:
|
||||
request.session['successful_code'] = promo
|
||||
return request.redirect(post.get('r', '/shop/cart'))
|
||||
|
||||
@http.route()
|
||||
def shop_payment(self, **post):
|
||||
order = request.website.sale_get_order()
|
||||
if order:
|
||||
order._update_programs_and_rewards()
|
||||
order._auto_apply_rewards()
|
||||
return super(WebsiteSale, self).shop_payment(**post)
|
||||
|
||||
@http.route(['/shop/cart'], type='http', auth="public", website=True)
|
||||
def cart(self, **post):
|
||||
order = request.website.sale_get_order()
|
||||
if order and order.state != 'draft':
|
||||
request.session['sale_order_id'] = None
|
||||
order = request.website.sale_get_order()
|
||||
if order:
|
||||
order._update_programs_and_rewards()
|
||||
order._auto_apply_rewards()
|
||||
|
||||
res = super().cart(**post)
|
||||
|
||||
# TODO in master: remove and pass delete=True to the methods fetching the error/success
|
||||
# messages in _get_website_sale_extra_values
|
||||
# clean session messages after displaying them
|
||||
if request.session.get('error_promo_code'):
|
||||
request.session.pop('error_promo_code')
|
||||
if request.session.get('successful_code'):
|
||||
request.session.pop('successful_code')
|
||||
|
||||
return res
|
||||
|
||||
@http.route(['/coupon/<string:code>'], type='http', auth='public', website=True, sitemap=False)
|
||||
@route(['/coupon/<string:code>'], type='http', auth='public', website=True, sitemap=False)
|
||||
def activate_coupon(self, code, r='/shop', **kw):
|
||||
url_parts = url_parse(r)
|
||||
url_query = url_parts.decode_query()
|
||||
|
|
@ -67,9 +44,8 @@ class WebsiteSale(main.WebsiteSale):
|
|||
code = code.strip()
|
||||
|
||||
request.session['pending_coupon_code'] = code
|
||||
order = request.website.sale_get_order()
|
||||
if order:
|
||||
result = order._try_pending_coupon()
|
||||
if order_sudo := request.cart:
|
||||
result = order_sudo._try_pending_coupon()
|
||||
if isinstance(result, dict) and 'error' in result:
|
||||
url_query['coupon_error'] = result['error']
|
||||
else:
|
||||
|
|
@ -80,27 +56,41 @@ class WebsiteSale(main.WebsiteSale):
|
|||
redirect = url_parts.replace(query=url_encode(url_query))
|
||||
return request.redirect(redirect.to_url())
|
||||
|
||||
@http.route(['/shop/claimreward'], type='http', auth='public', website=True, sitemap=False)
|
||||
def claim_reward(self, reward, **post):
|
||||
order = request.website.sale_get_order()
|
||||
coupon_id = False
|
||||
try:
|
||||
reward_id = request.env['loyalty.reward'].sudo().browse(int(reward))
|
||||
except ValueError:
|
||||
reward_id = request.env['loyalty.reward'].sudo()
|
||||
claimable_rewards = order._get_claimable_rewards()
|
||||
for coupon, rewards in claimable_rewards.items():
|
||||
if reward_id in rewards:
|
||||
coupon_id = coupon
|
||||
@route('/shop/claimreward', type='http', auth='public', website=True, sitemap=False)
|
||||
def claim_reward(self, reward_id, code=None, **post):
|
||||
redirect = post.get('r', '/shop/cart')
|
||||
if not coupon_id or not reward_id.exists():
|
||||
if not (order_sudo := request.cart):
|
||||
return request.redirect(redirect)
|
||||
if reward_id.multi_product and 'product_id' in post:
|
||||
|
||||
try:
|
||||
reward_id = int(reward_id)
|
||||
except ValueError:
|
||||
reward_id = None
|
||||
|
||||
reward_sudo = request.env['loyalty.reward'].sudo().browse(reward_id).exists()
|
||||
if not reward_sudo:
|
||||
return request.redirect(redirect)
|
||||
|
||||
if reward_sudo.multi_product and 'product_id' in post:
|
||||
request.update_context(product_id=int(post['product_id']))
|
||||
else:
|
||||
request.redirect(redirect)
|
||||
|
||||
self._apply_reward(order, reward_id, coupon_id)
|
||||
program_sudo = reward_sudo.program_id
|
||||
claimable_rewards = order_sudo._get_claimable_and_showable_rewards()
|
||||
coupon = request.env['loyalty.card']
|
||||
for coupon_, rewards in claimable_rewards.items():
|
||||
if reward_sudo in rewards:
|
||||
coupon = coupon_
|
||||
if code == coupon.code and (
|
||||
(program_sudo.trigger == 'with_code' and program_sudo.program_type != 'promo_code')
|
||||
or (program_sudo.trigger == 'auto'
|
||||
and program_sudo.applies_on == 'future'
|
||||
and program_sudo.program_type not in ('ewallet', 'loyalty'))
|
||||
):
|
||||
return self.pricelist(code, reward_id=reward_id)
|
||||
if coupon:
|
||||
self._apply_reward(order_sudo, reward_sudo, coupon)
|
||||
return request.redirect(redirect)
|
||||
|
||||
def _apply_reward(self, order, reward, coupon):
|
||||
|
|
@ -119,35 +109,13 @@ class WebsiteSale(main.WebsiteSale):
|
|||
if 'error' in reward_status:
|
||||
request.session['error_promo_code'] = reward_status['error']
|
||||
return False
|
||||
order._update_programs_and_rewards()
|
||||
if order.carrier_id.free_over and not reward.program_id.is_payment_program:
|
||||
# update shiping cost if it's `free_over` and reward isn't eWallet or gift card
|
||||
# will call `_update_programs_and_rewards` again, updating applied eWallet/gift cards
|
||||
res = order.carrier_id.rate_shipment(order)
|
||||
if res.get('success'):
|
||||
order.set_delivery_line(order.carrier_id, res['price'])
|
||||
else:
|
||||
order._remove_delivery_line()
|
||||
return True
|
||||
|
||||
@http.route()
|
||||
def cart_update_json(self, *args, set_qty=None, **kwargs):
|
||||
# When a reward line is deleted we remove it from the auto claimable rewards
|
||||
if set_qty == 0:
|
||||
request.update_context(website_sale_loyalty_delete=True)
|
||||
# We need to update the website since `get_sale_order` is called on the website
|
||||
# and does not follow the request's context
|
||||
request.website = request.website.with_context(website_sale_loyalty_delete=True)
|
||||
return super().cart_update_json(*args, set_qty=set_qty, **kwargs)
|
||||
|
||||
|
||||
class PaymentPortal(main.PaymentPortal):
|
||||
|
||||
def _validate_transaction_for_order(self, transaction, sale_order_id):
|
||||
"""Update programs & rewards before finalizing transaction.
|
||||
|
||||
:param payment.transaction transaction: The payment transaction
|
||||
:param int order_id: The id of the sale order to pay
|
||||
:raise: ValidationError if the order amount changed after updating rewards
|
||||
"""
|
||||
super()._validate_transaction_for_order(transaction, sale_order_id)
|
||||
order_sudo = request.env['sale.order'].sudo().browse(sale_order_id)
|
||||
if order_sudo.exists():
|
||||
initial_amount = order_sudo.amount_total
|
||||
order_sudo._update_programs_and_rewards()
|
||||
order_sudo.validate_taxes_on_sales_order() # re-applies taxcloud taxes if necessary
|
||||
if order_sudo.currency_id.compare_amounts(initial_amount, order_sudo.amount_total):
|
||||
raise ValidationError(
|
||||
_("Cannot process payment: applied reward was changed or has expired.")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
from odoo.addons.website_sale.controllers import payment
|
||||
|
||||
|
||||
class PaymentPortal(payment.PaymentPortal):
|
||||
|
||||
def _validate_transaction_for_order(self, transaction, sale_order):
|
||||
"""Update programs & rewards before finalizing transaction.
|
||||
|
||||
:param payment.transaction transaction: The payment transaction
|
||||
:param int order_id: The id of the sale order to pay
|
||||
:raise: ValidationError if the order amount changed after updating rewards
|
||||
"""
|
||||
super()._validate_transaction_for_order(transaction, sale_order)
|
||||
if sale_order.exists():
|
||||
initial_amount = sale_order.amount_total
|
||||
sale_order._update_programs_and_rewards()
|
||||
if sale_order.currency_id.compare_amounts(sale_order.amount_total, initial_amount):
|
||||
raise ValidationError(
|
||||
_(
|
||||
"Cannot process payment: applied reward was changed or has expired.\n"
|
||||
"Please refresh the page and try again."
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import request, route
|
||||
from odoo.tools.misc import format_amount
|
||||
|
||||
from odoo.addons.loyalty.controllers import portal as loyalty_portal
|
||||
|
||||
|
||||
class CustomerPortalLoyalty(loyalty_portal.CustomerPortalLoyalty):
|
||||
|
||||
@route()
|
||||
def portal_get_card_history_values(self, card_id):
|
||||
"""Add published trigger products for the loyalty program."""
|
||||
res = super().portal_get_card_history_values(card_id)
|
||||
program_sudo = request.env['loyalty.program'].sudo().search([
|
||||
('coupon_ids', '=', int(card_id)),
|
||||
])
|
||||
if not program_sudo:
|
||||
return res
|
||||
|
||||
currency = request.env.company.currency_id
|
||||
res['program']['trigger_products'] = [{
|
||||
'id': product.id, 'total_price': format_amount(self.env, product.lst_price, currency)
|
||||
} for product in program_sudo.trigger_product_ids if product.website_published]
|
||||
return res
|
||||
Loading…
Add table
Add a link
Reference in a new issue