Initial commit: Sale packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:49 +02:00
commit 14e3d26998
6469 changed files with 2479670 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="70" height="70" viewBox="0 0 70 70"><defs><path id="a" d="M4 0h61c4 0 5 1 5 5v60c0 4-1 5-5 5H4c-3 0-4-1-4-5V5c0-4 1-5 4-5z"/><linearGradient id="c" x1="98.162%" x2="0%" y1="1.838%" y2="100%"><stop offset="0%" stop-color="#797DA5"/><stop offset="50.799%" stop-color="#6D7194"/><stop offset="100%" stop-color="#626584"/></linearGradient><path id="d" d="M50 31.035a3.5 3.5 0 1 0 0 6.93v3.06a1.633 1.633 0 0 1-1.588 1.286L26.974 43l.998 4h18.955c.998 0 .998 2 0 2h-20.95L19.99 25h-1.996v1c0 .667-.332 1-.997 1S16 26.667 16 26v-2c.066-.667.398-1 .998-1h3.99c.516 0 .848.333.998 1l.998 3.281 25.428.037c1.045 0 1.588.761 1.588 2.018v1.7zM45.43 55a2.497 2.497 0 0 1-2.493-2.5c0-1.38 1.116-2.5 2.494-2.5a2.497 2.497 0 0 1 2.494 2.5c0 1.38-1.117 2.5-2.494 2.5zm-18.955 0a2.497 2.497 0 0 1-2.494-2.5c0-1.38 1.117-2.5 2.494-2.5a2.497 2.497 0 0 1 2.495 2.5c0 1.38-1.117 2.5-2.495 2.5zm12.7-24.996a.51.51 0 0 0-.409.2l-7.668 9.056c-.233.31.004.738.41.738l.696-.002a.51.51 0 0 0 .409-.2l7.63-9.056c.234-.312-.005-.74-.41-.738l-.658.002zm-5.841 4.371c1.29 0 2.334-.979 2.334-2.188 0-1.208-1.044-2.187-2.334-2.187S31 30.979 31 32.188c0 1.208 1.044 2.187 2.334 2.187zm0-3.125c.552 0 1 .42 1 .938 0 .517-.448.937-1 .937s-1-.42-1-.938c0-.517.448-.937 1-.937zm4.668 4.375c-1.29 0-2.334.979-2.334 2.188 0 1.208 1.044 2.187 2.334 2.187s2.334-.979 2.334-2.188c0-1.208-1.044-2.187-2.334-2.187zm0 3.125c-.553 0-1-.42-1-.938 0-.517.447-.937 1-.937.552 0 1 .42 1 .938 0 .517-.448.937-1 .937z"/><path id="e" d="M50 30a3 3 0 0 0 0 6v3.025a1.633 1.633 0 0 1-1.588 1.286L26.974 41l.998 4h18.955c.998 0 .998 2 0 2h-20.95L19.99 23h-1.996v1c0 .667-.332 1-.997 1S16 24.667 16 24v-2c.066-.667.398-1 .998-1h3.99c.516 0 .848.333.998 1l.998 3.281 25.428.037c1.045 0 1.588.761 1.588 2.018V30zm-4.57 23a2.497 2.497 0 0 1-2.493-2.5c0-1.38 1.116-2.5 2.494-2.5a2.497 2.497 0 0 1 2.494 2.5c0 1.38-1.117 2.5-2.494 2.5zm-18.955 0a2.497 2.497 0 0 1-2.494-2.5c0-1.38 1.117-2.5 2.494-2.5a2.497 2.497 0 0 1 2.495 2.5c0 1.38-1.117 2.5-2.495 2.5zM48 26a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm0 11a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-8.825-8.996a.51.51 0 0 0-.409.2l-7.668 9.056c-.233.31.004.738.41.738l.696-.002a.51.51 0 0 0 .409-.2l7.63-9.056c.234-.312-.005-.74-.41-.738l-.658.002zm-5.841 4.371c1.29 0 2.334-.979 2.334-2.188 0-1.208-1.044-2.187-2.334-2.187S31 28.979 31 30.188c0 1.208 1.044 2.187 2.334 2.187zm0-3.125c.552 0 1 .42 1 .938 0 .517-.448.937-1 .937s-1-.42-1-.938c0-.517.448-.937 1-.937zm4.668 4.375c-1.29 0-2.334.979-2.334 2.188 0 1.208 1.044 2.187 2.334 2.187s2.334-.979 2.334-2.188c0-1.208-1.044-2.187-2.334-2.187zm0 3.125c-.553 0-1-.42-1-.938 0-.517.447-.937 1-.937.552 0 1 .42 1 .938 0 .517-.448.937-1 .937z"/></defs><g fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><g mask="url(#b)"><path fill="url(#c)" d="M0 0H70V70H0z"/><path fill="#FFF" fill-opacity=".383" d="M4 1h61c2.667 0 4.333.667 5 2V0H0v3c.667-1.333 2-2 4-2z"/><path fill="#393939" d="M33.317 69H4c-2 0-4-1-4-4V38.29l16.258-16.95L21 21l2 5h26.583l.371 3.987-3.862 4.883 3.764 1.445-.11 3.27L45.076 45H47l.507 1.61-1.993 1.943 1.815 3.434L33.317 69z" opacity=".324"/><path fill="#000" fill-opacity=".383" d="M4 69h61c2.667 0 4.333-1 5-3v4H0v-4c.667 2 2 3 4 3z"/><use fill="#000" fill-rule="nonzero" opacity=".3" xlink:href="#d"/><use fill="#FFF" fill-rule="nonzero" xlink:href="#e"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,36 @@
/** @odoo-module **/
import publicWidget from 'web.public.widget';
import {registry} from "@web/core/registry";
const CouponToasterWidget = publicWidget.Widget.extend({
start() {
let options = {};
const $content = this.$('.coupon-message-content');
const $title = this.$('.coupon-message-title');
if ($content.length) {
Object.assign(options, {message: $content[0].innerHTML});
}
if ($title.length) {
Object.assign(options, {title: $title[0].innerHTML});
}
if (this.$el.hasClass('coupon-info-message')) {
this.displayNotification(Object.assign({type: 'success'}, options));
} else if (this.$el.hasClass('coupon-error-message')) {
this.displayNotification(Object.assign({type: 'danger'}, options));
} else if (this.$el.hasClass('coupon-warning-message')) {
this.displayNotification(Object.assign({type: 'warning'}, options));
}
return this._super(...arguments);
},
});
registry.category("public_root_widgets").add("CouponToasterWidget", {
Widget: CouponToasterWidget,
selector: '.coupon-message',
});
export default CouponToasterWidget;

View file

@ -0,0 +1,13 @@
/** @odoo-module **/
import publicWidget from 'web.public.widget';
publicWidget.registry.WebsiteSaleGiftCardCopy = publicWidget.Widget.extend({
selector: '.o_purchased_gift_card',
/**
* @override
*/
start: function () {
new ClipboardJS(this.$el.find('.copy-to-clipboard')[0]);
}
});

View file

@ -0,0 +1,90 @@
/** @odoo-module **/
import tour from 'web_tour.tour';
import tourUtils from 'website_sale.tour_utils';
tour.register('shop_sale_gift_card', {
test: true,
url: '/shop?search=Small%20Drawer'
},
[
// Add a small drawer to the order (50$)
{
content: 'select Small Drawer',
extra_trigger: '.oe_search_found',
trigger: '.oe_product_cart a:contains("TEST - Small Drawer")',
},
{
content: 'Add Small Drawer into cart',
trigger: 'a:contains(ADD TO CART)',
},
tourUtils.goToCart(),
{
content: 'Click on "I have a promo code"',
extra_trigger: '#cart_products',
trigger: '.show_coupon',
},
{
content: 'insert gift card code',
trigger: 'form[name="coupon_code"] input[name="promo"]',
run: 'text GIFT_CARD'
},
{
content: 'validate the gift card',
trigger: 'form[name="coupon_code"] .a-submit',
},
{
content: 'check gift card line',
trigger: '.td-product_name:contains("PAY WITH GIFT CARD")',
},
{
content: 'Click on "I have a promo code"',
trigger: '.show_coupon',
},
{
content: 'insert gift card code',
extra_trigger: 'form[name="coupon_code"]',
trigger: 'form[name="coupon_code"] input[name="promo"]',
run: 'text 10PERCENT'
},
{
content: 'validate the gift card',
trigger: 'form[name="coupon_code"] .a-submit',
},
{
content: 'check gift card amount',
trigger: '.oe_currency_value:contains("-45.00")',
trigger: '.oe_website_sale .oe_cart',
run: function () {}, // it's a check
},
{
content: 'go to shop',
trigger: 'a:contains("Shop")',
},
{
content: "type Gift Card in search",
trigger: 'form input[name="search"]',
run: "text Gift Card",
},
{
content: "start search",
trigger: 'form:has(input[name="search"]) .oe_search_button',
},
{
content: "select Gift Card",
extra_trigger: '.oe_search_found', // Wait to be on search results or it sometimes throws concurent error (sent search form + click on product on /shop)
trigger: '.oe_product_cart a:containsExact("TEST - Gift Card")',
},
{
content: "click on 'Add to Cart' button",
trigger: "a:contains(ADD TO CART)",
},
tourUtils.goToCart({quantity: 2}),
{
content: 'check gift card amount',
trigger: '.oe_currency_value:contains("-45.00")',
trigger: '.oe_website_sale .oe_cart',
run: function () {}, // it's a check
},
],
);

View file

@ -0,0 +1,151 @@
/** @odoo-module **/
import tour from 'web_tour.tour';
import ajax from 'web.ajax';
import tourUtils from 'website_sale.tour_utils';
tour.register('shop_sale_loyalty', {
test: true,
url: '/shop?search=Small%20Cabinet',
},
[
/* 1. Buy 1 Small Cabinet, enable coupon code & insert 10% code */
{
content: "select Small Cabinet",
extra_trigger: '.oe_search_found',
trigger: '.oe_product_cart a:contains("Small Cabinet")',
},
{
content: "add 2 Small Cabinet into cart",
trigger: '#product_details input[name="add_qty"]',
run: "text 2",
},
{
content: "click on 'Add to Cart' button",
trigger: "a:contains(ADD TO CART)",
},
tourUtils.goToCart({quantity: 2}),
{
content: "click on 'I have a promo code'",
extra_trigger: '.show_coupon',
trigger: '.show_coupon',
},
{
content: "insert promo code 'testcode'",
extra_trigger: 'form[name="coupon_code"]',
trigger: 'form[name="coupon_code"] input[name="promo"]',
run: "text testcode",
},
{
content: "validate the coupon",
trigger: 'form[name="coupon_code"] .a-submit',
},
{
content: "check reward product",
trigger: '.td-product_name:contains("10.0% discount on total amount")',
run: function () {}, // it's a check
},
{
content: "check loyalty points",
trigger: '.oe_website_sale_gift_card span:contains("372.03 Points")',
run: function () {}, // it's a check
},
/* 2. Add some cabinet to get a free one, play with quantity */
{
content: "go to shop",
trigger: '.td-product_name:contains("10.0% discount on total amount")',
run: function () {
ajax.jsonRpc('/web/dataset/call_kw', 'call', {
model: 'account.tax',
method: 'create',
args: [{
'name':'15% tax incl ' + _.now(),
'amount': 15,
}],
kwargs: {},
}).then(function (tax_id) {
ajax.jsonRpc('/web/dataset/call_kw', 'call', {
model: 'product.template',
method: 'create',
args: [{
'name': 'Taxed Product',
'taxes_id': [([6, false, [tax_id]])],
'list_price': 100,
'website_published': true,
}],
kwargs: {},
}).then(function (data) {
location.href = '/shop';
});
});
},
},
{
content: "type Taxed Product in search",
trigger: 'form input[name="search"]',
run: "text Taxed Product",
},
{
content: "start search",
trigger: 'form:has(input[name="search"]) .oe_search_button',
},
{
content: "select Taxed Product",
extra_trigger: '.oe_search_found', // Wait to be on search results or it sometimes throws concurent error (sent search form + click on product on /shop)
trigger: '.oe_product_cart a:containsExact("Taxed Product")',
},
{
content: "click on 'Add to Cart' button",
trigger: "a:contains(ADD TO CART)",
},
tourUtils.goToCart({quantity: 3}),
{
content: "check reduction amount got recomputed and merged both discount lines into one only",
extra_trigger: '.oe_currency_value:contains("-74.00"):not(#cart_total .oe_currency_value:contains("-74.00"))',
trigger: '.oe_website_sale .oe_cart',
run: function () {}, // it's a check
},
/* 3. Add some cabinet to get a free one, play with quantity */
{
content: "add one Small Cabinet",
trigger: '#cart_products input.js_quantity',
run: "text 3",
},
{
content: "check reduction amount got recomputed when changing qty",
trigger: '.oe_currency_value:contains("-106.00")',
run: function () {}, // it's a check
},
{
content: "add more Small Cabinet into cart",
trigger: '#cart_products input.js_quantity',
run: "text 4",
},
{
content: "check free product is added",
trigger: '#wrap:has(.td-product_name:contains("Free Product - Small Cabinet"))',
run: function () {}, // it's a check
},
{
content: "remove one cabinet from cart",
trigger: '#cart_products input.js_quantity[value="4"]',
run: "text 3",
},
{
content: "check free product is removed",
trigger: '#wrap:not(:has(.td-product_name:contains("Free Product - Small Cabinet")))',
run: function () {}, // it's a check
},
/* 4. Check /shop/payment does not break the `merged discount lines split per tax` (eg: with _compute_tax_id) */
{
content: "go to checkout",
trigger: 'a[href="/shop/checkout?express=1"]',
},
{
content: "check total is unchanged once we land on payment page",
extra_trigger: '#payment_method h3:contains("Pay with")',
trigger: 'tr#order_total .oe_currency_value:contains("967.50")',
run: function () {}, // it's a check
},
]
);