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: 6.5 KiB

View file

@ -0,0 +1,24 @@
<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="icon-a" d="M4,5.35309892e-14 C36.4160122,9.87060235e-15 58.0836068,-3.97961823e-14 65,5.07020818e-14 C69,6.733808e-14 70,1 70,5 C70,43.0488877 70,62.4235458 70,65 C70,69 69,70 65,70 C61,70 9,70 4,70 C1,70 7.10542736e-15,69 7.10542736e-15,65 C7.25721566e-15,62.4676575 3.83358709e-14,41.8005206 3.60818146e-14,5 C-1.13686838e-13,1 1,5.75716207e-14 4,5.35309892e-14 Z"/>
<linearGradient id="icon-c" x1="100%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#DA956B"/>
<stop offset="100%" stop-color="#CC7039"/>
</linearGradient>
<path id="icon-d" d="M30.4841117,22.0178818 L43,33 C39,37.3544294 37.3333333,42.3544294 38,48 L21.0744625,32.4683559 L30.4841117,22.0178818 Z M42.5223849,56.838607 C41.2078243,58.1148367 39.1294169,58.18659 37.7708523,56.9633329 L12.0893951,33.839645 C10.6710296,32.562543 10.574444,30.3575851 11.8736617,28.9146577 L16.5784862,23.6894206 C17.9968517,24.9665226 20.1998265,24.8320983 21.4990443,23.3891709 C22.798262,21.9462434 22.7016763,19.7412856 21.2833108,18.4641836 L25.9881354,13.2389465 C27.2873531,11.7960191 29.4903279,11.6615948 30.9086934,12.9386968 L49.9350371,30.0700936 C47.9735137,30.1405297 46.1915216,30.6862713 44.6377627,31.6080597 L31.6243623,19.8907413 C30.9151795,19.2521903 29.8136921,19.3194025 29.1640833,20.0408662 L18.9702967,31.3622132 C18.3206878,32.0836769 18.3689807,33.1861558 19.0781634,33.8247068 L37.0551835,50.0112884 C37.5260595,50.4352671 38.1698855,50.5481058 38.7395561,50.3648826 C39.4901538,52.938764 40.7880675,55.1720216 42.5223849,56.838607 Z M47.7280684,41.09729 C47.7280684,44.4791455 58.0000556,43.620791 58,50.0493457 C58,53.1285938 55.7508537,55.7588721 52.0971585,56.3075293 L52.0971585,58.8554688 C52.0971585,59.2114111 51.7984472,59.5 51.43002,59.5 L49.2062249,59.5 C48.8377977,59.5 48.5390864,59.2114111 48.5390864,58.8554688 L48.5390864,56.2656885 C46.3429776,55.9048584 44.386038,54.9254395 43.0490368,53.6890137 C42.805698,53.4639648 42.7750097,53.0985693 42.9766523,52.8378564 L44.666125,50.6535938 C44.8927853,50.3606006 45.3248687,50.3096289 45.6200774,50.5386523 C47.0052794,51.6132471 48.7943781,52.4661768 50.5039761,52.4661768 C52.4949954,52.4661768 53.4018034,51.3202539 53.4018034,50.255542 C53.4018034,47.1078662 43.1298162,47.7912305 43.1298162,41.1561572 C43.1298162,38.3244092 45.2797812,36.034873 48.539142,35.3210547 L48.539142,32.6445313 C48.539142,32.2885889 48.8378533,32 49.2062805,32 L51.4300755,32 C51.7985028,32 52.0972141,32.2885889 52.0972141,32.6445313 L52.0972141,35.1817822 C53.8848117,35.3813721 55.8225155,36.0588281 57.1724147,37.2123779 C57.4043009,37.4105176 57.4628423,37.7377783 57.3155715,38.0008545 L56.006201,40.3399121 C55.8146766,40.6821045 55.3560189,40.7828125 55.029121,40.5556689 C53.7868535,39.6925342 52.2641099,39.033877 50.7782812,39.033877 C48.9253596,39.033877 47.7280684,39.8438379 47.7280684,41.09729 Z"/>
<path id="icon-e" d="M30.4841117,20.0178818 L43,31 C39,35.3544294 37.3333333,40.3544294 38,46 L21.0744625,30.4683559 L30.4841117,20.0178818 Z M42.5223849,54.838607 C41.2078243,56.1148367 39.1294169,56.18659 37.7708523,54.9633329 L12.0893951,31.839645 C10.6710296,30.562543 10.574444,28.3575851 11.8736617,26.9146577 L16.5784862,21.6894206 C17.9968517,22.9665226 20.1998265,22.8320983 21.4990443,21.3891709 C22.798262,19.9462434 22.7016763,17.7412856 21.2833108,16.4641836 L25.9881354,11.2389465 C27.2873531,9.79601907 29.4903279,9.66159477 30.9086934,10.9386968 L49.9350371,28.0700936 C47.9735137,28.1405297 46.1915216,28.6862713 44.6377627,29.6080597 L31.6243623,17.8907413 C30.9151795,17.2521903 29.8136921,17.3194025 29.1640833,18.0408662 L18.9702967,29.3622132 C18.3206878,30.0836769 18.3689807,31.1861558 19.0781634,31.8247068 L37.0551835,48.0112884 C37.5260595,48.4352671 38.1698855,48.5481058 38.7395561,48.3648826 C39.4901538,50.938764 40.7880675,53.1720216 42.5223849,54.838607 Z M47.7280684,39.09729 C47.7280684,42.4791455 58.0000556,41.620791 58,48.0493457 C58,51.1285938 55.7508537,53.7588721 52.0971585,54.3075293 L52.0971585,56.8554688 C52.0971585,57.2114111 51.7984472,57.5 51.43002,57.5 L49.2062249,57.5 C48.8377977,57.5 48.5390864,57.2114111 48.5390864,56.8554688 L48.5390864,54.2656885 C46.3429776,53.9048584 44.386038,52.9254395 43.0490368,51.6890137 C42.805698,51.4639648 42.7750097,51.0985693 42.9766523,50.8378564 L44.666125,48.6535938 C44.8927853,48.3606006 45.3248687,48.3096289 45.6200774,48.5386523 C47.0052794,49.6132471 48.7943781,50.4661768 50.5039761,50.4661768 C52.4949954,50.4661768 53.4018034,49.3202539 53.4018034,48.255542 C53.4018034,45.1078662 43.1298162,45.7912305 43.1298162,39.1561572 C43.1298162,36.3244092 45.2797812,34.034873 48.539142,33.3210547 L48.539142,30.6445313 C48.539142,30.2885889 48.8378533,30 49.2062805,30 L51.4300755,30 C51.7985028,30 52.0972141,30.2885889 52.0972141,30.6445313 L52.0972141,33.1817822 C53.8848117,33.3813721 55.8225155,34.0588281 57.1724147,35.2123779 C57.4043009,35.4105176 57.4628423,35.7377783 57.3155715,36.0008545 L56.006201,38.3399121 C55.8146766,38.6821045 55.3560189,38.7828125 55.029121,38.5556689 C53.7868535,37.6925342 52.2641099,37.033877 50.7782812,37.033877 C48.9253596,37.033877 47.7280684,37.8438379 47.7280684,39.09729 Z"/>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="icon-b" fill="#fff">
<use xlink:href="#icon-a"/>
</mask>
<g mask="url(#icon-b)">
<rect width="70" height="70" fill="url(#icon-c)"/>
<path fill="#FFF" fill-opacity=".383" d="M4,1.8 L65,1.8 C67.6666667,1.8 69.3333333,1.13333333 70,-0.2 C70,2.46666667 70,3.46666667 70,2.8 L1.10547097e-14,2.8 C-1.65952376e-14,3.46666667 -2.9161925e-14,2.46666667 -2.66453526e-14,-0.2 C0.666666667,1.13333333 2,1.8 4,1.8 Z" transform="matrix(1 0 0 -1 0 2.8)"/>
<path fill="#393939" d="M40.940835,55 L4,55 C2,55 -7.10542736e-15,54.851752 0,50.8490566 L2.0990647e-16,27.6230718 L12,13.490566 L24,0 L37,3.11320755 L46,11.4150943 L52,16.6037736 L52,19.7169811 L57,21.7924528 L51,29.0566038 L57,35.9806542 L52,38.8120355 L52,42.1170824 L40.940835,55 Z" opacity=".324" transform="translate(0 15)"/>
<path fill="#000" fill-opacity=".383" d="M4,4 L65,4 C67.6666667,4 69.3333333,3 70,1 C70,3.66666667 70,5 70,5 L1.77635684e-15,5 C1.77635684e-15,5 1.77635684e-15,3.66666667 1.77635684e-15,1 C0.666666667,3 2,4 4,4 Z" transform="translate(0 65)"/>
<use fill="#000" fill-rule="nonzero" opacity=".3" xlink:href="#icon-d"/>
<use fill="#FFF" fill-rule="nonzero" xlink:href="#icon-e"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

View file

@ -0,0 +1,76 @@
odoo.define('website_event_sale.tour.WebsiteEventSaleTourMethods', function (require) {
'use strict';
function changePricelist(pricelistName) {
return [
{
content: "Go to page Shop",
trigger: '.nav-link:contains("Shop")',
},
{
content: "Toggle Pricelist",
trigger: '.o_pricelist_dropdown > .dropdown-toggle',
run: 'click',
},
{
content: `Activate Pricelist ${pricelistName}`,
trigger: `.dropdown-item:contains(${pricelistName})`,
run: 'click',
},
{
content: 'Wait for pricelist to load',
trigger: `.dropdown-toggle:contains(${pricelistName})`,
run: function () {},
},
];
}
function checkPriceEvent(eventName, price) {
return [
{
content: "Go to page Event",
trigger: '.nav-link:contains("Event")',
},
{
content: "Open the Pycon event",
trigger: `.o_wevent_events_list a:contains(${eventName})`,
},
{
content: "Verify Price",
trigger: `.oe_currency_value:contains(${price})`,
run: function () {}, // it's a check
},
]
}
function checkPriceDiscountEvent(eventName, price, discount) {
return [
...checkPriceEvent(eventName, price),
{
content: "Verify Price before discount",
trigger: `del:contains(${discount})`,
run: function () {}, // it's a check
},
]
}
function checkPriceCart(price) {
return [
{
content: "Go to page Cart",
trigger: '.fa-shopping-cart',
},
{
content: "Verify Price",
trigger: `[id=order_total] .oe_currency_value:contains(${price})`,
run: function () {}, // it's a check
},
]
}
const getPriceListChecksSteps = function ({pricelistName, eventName, price, priceBeforeDiscount=false}) {
const checkPriceSteps = priceBeforeDiscount ? checkPriceDiscountEvent(eventName, price, priceBeforeDiscount) : checkPriceEvent(eventName, price);
return [
...changePricelist(pricelistName),
...checkPriceSteps,
...checkPriceCart(price),
]
}
return { getPriceListChecksSteps, changePricelist, checkPriceCart }
});

View file

@ -0,0 +1,89 @@
odoo.define('website_event_sale.tour', function (require) {
'use strict';
var tour = require('web_tour.tour');
tour.register('event_buy_tickets', {
test: true,
url: '/event',
},
[
{
content: "Go to the `Events` page",
trigger: 'a[href*="/event"]:contains("Conference for Architects TEST"):first',
},
{
content: "Select 1 unit of `Standard` ticket type",
extra_trigger: '#wrap:not(:has(a[href*="/event"]:contains("Conference for Architects")))',
trigger: 'select:eq(0)',
run: 'text 1',
},
{
content: "Select 2 units of `VIP` ticket type",
extra_trigger: 'select:eq(0):has(option:contains(1):propSelected)',
trigger: 'select:eq(1)',
run: 'text 2',
},
{
content: "Click on `Order Now` button",
extra_trigger: 'select:eq(1):has(option:contains(2):propSelected)',
trigger: '.btn-primary:contains("Register")',
},
{
content: "Fill attendees details",
trigger: 'form[id="attendee_registration"] .btn:contains("Continue")',
run: function () {
$("input[name='1-name']").val("Att1");
$("input[name='1-phone']").val("111 111");
$("input[name='1-email']").val("att1@example.com");
$("input[name='2-name']").val("Att2");
$("input[name='2-phone']").val("222 222");
$("input[name='2-email']").val("att2@example.com");
$("input[name='3-name']").val("Att3");
$("input[name='3-phone']").val("333 333");
$("input[name='3-email']").val("att3@example.com");
},
},
{
content: "Validate attendees details",
extra_trigger: "input[name='1-name'], input[name='2-name'], input[name='3-name']",
trigger: 'button:contains("Continue")',
},
{
content: "Check that the cart contains exactly 3 triggers",
trigger: 'a:has(.my_cart_quantity:containsExact(3)),.o_extra_menu_items .fa-plus',
run: function () {}, // it's a check
},
{
content: "go to cart",
trigger: 'a:contains(Return to Cart)',
},
{
content: "Now click on `Process Checkout`",
extra_trigger: 'a:has(.my_cart_quantity):contains(3),#cart_products input.js_quantity[value="3"]',
trigger: '.btn-primary:contains("Process Checkout")'
},
{
content: "Check that the subtotal is 4,000.00 USD", // this test will fail if the currency of the main company is not USD
trigger: '#order_total_untaxed .oe_currency_value:contains("4,000.00")',
run: function () {}, // it's a check
},
{
content: "Select `Wire Transfer` payment method",
trigger: '#payment_method label:contains("Wire Transfer")',
},
{
content: "Pay",
//Either there are multiple payment methods, and one is checked, either there is only one, and therefore there are no radio inputs
// extra_trigger: '#payment_method input:checked,#payment_method:not(:has("input:radio:visible"))',
trigger: 'button[name="o_payment_submit_button"]:visible:not(:disabled)',
},
{
content: "Last step",
trigger: '.oe_website_sale_tx_status:contains("Please use the following transfer details")',
timeout: 30000,
}
]
);
});

View file

@ -0,0 +1,92 @@
odoo.define('website_event_sale.tour.last_ticket', function (require) {
'use strict';
var tour = require('web_tour.tour');
tour.register('event_buy_last_ticket', {
test: true,
url: '/event',
},[{
content: "Open the Last ticket test event page",
trigger: '.o_wevent_events_list a:contains("Last ticket test")',
},
{
content: "Show available Tickets",
trigger: '.btn-primary:contains("Register")',
},
{
content: "Select 2 units of `VIP` ticket type",
extra_trigger: '#wrap:not(:has(a[href*="/event"]:contains("Last ticket test")))',
trigger: 'select:eq(0)',
run: 'text 2',
},
{
content: "Click on `Order Now` button",
extra_trigger: 'select:eq(0):has(option:contains(2):propSelected)',
trigger: '.a-submit:contains("Register")',
},
{
content: "Fill attendees details",
trigger: 'form[id="attendee_registration"] .btn:contains("Continue")',
run: function () {
$("input[name='1-name']").val("Att1");
$("input[name='1-phone']").val("111 111");
$("input[name='1-email']").val("att1@example.com");
$("input[name='2-name']").val("Att2");
$("input[name='2-phone']").val("222 222");
$("input[name='2-email']").val("att2@example.com");
},
},
{
content: "Validate attendees details",
extra_trigger: "input[name='1-name'], input[name='2-name']",
trigger: 'button:contains("Continue")',
},
{
content: "Fill address",
trigger: 'form.checkout_autoformat',
run: function () {
$("input[name='name']").val("test1");
$("input[name='email']").val("test@example.com");
$("input[name='phone']").val("111 111");
$("input[name='street']").val("street test 1");
$("input[name='city']").val("testCity");
$("input[name='zip']").val("123");
$('#country_id option:eq(1)').attr('selected', true);
},
},
{
content: "Validate address",
trigger: '.btn-primary:contains("Next")',
},
{
// if the seats_available checking logic is not correct,
// the shopping cart will be cleared when selling the last ticket
// the tour test will be failed here
content: "Select `Wire Transfer` payment method",
trigger: '#payment_method label:contains("Wire Transfer")',
},
// following steps are based on the website_sale_buy.js
{
content: "Pay",
//Either there are multiple payment methods, and one is checked, either there is only one, and therefore there are no radio inputs
extra_trigger: '#payment_method label:contains("Wire Transfer") input:checked,#payment_method:not(:has("input:radio:visible"))',
trigger: 'button[name="o_payment_submit_button"]:visible:not(:disabled)',
},
{
content: "payment finish",
trigger: '.oe_website_sale:contains("Please use the following transfer details")',
// Leave /shop/confirmation to prevent RPC loop to /shop/payment/get_status.
// The RPC could be handled in python while the tour is killed (and the session), leading to crashes
run: function () {
window.location.href = '/contactus'; // Redirect in JS to avoid the RPC loop (20x1sec)
},
timeout: 30000,
},
{
content: "wait page loaded",
trigger: 'h1:contains("Contact us")',
run: function () {}, // it's a check
},
]);
});

View file

@ -0,0 +1,57 @@
odoo.define('website_event_sale.tour.event_sale_pricelists_different_currencies', function (require) {
'use strict';
const tour = require('web_tour.tour');
const { getPriceListChecksSteps } = require('website_event_sale.tour.WebsiteEventSaleTourMethods');
tour.register('event_sale_pricelists_different_currencies', {
test: true,
url: '/event',
},[
// Register for tickets
{
content: "Open the Pycon event",
trigger: '.o_wevent_events_list a:contains("Pycon")',
},
{
content: "Register",
trigger: '.btn-primary:contains("Register")',
},
{
content: "Fill attendees details",
trigger: 'form[id="attendee_registration"] .btn:contains("Continue")',
run: function () {
$("input[name='1-name']").val("Great Name");
$("input[name='1-phone']").val("111 111");
$("input[name='1-email']").val("great@name.com");
},
},
{
content: "Validate attendees details",
extra_trigger: "input[name='1-name'], input[name='2-name']",
trigger: 'button:contains("Continue")',
},
...getPriceListChecksSteps({
pricelistName: "EUR With Discount Included",
eventName: "Pycon",
price: "90.00",
}),
...getPriceListChecksSteps({
pricelistName: "EUR Without Discount Included",
eventName: "Pycon",
price: "90.00",
priceBeforeDiscount: "100.00",
}),
...getPriceListChecksSteps({
pricelistName: "EX With Discount Included",
eventName: "Pycon",
price: "900.00",
}),
...getPriceListChecksSteps({
pricelistName: "EX Without Discount Included",
eventName: "Pycon",
price: "900.00",
priceBeforeDiscount: "1,000.00",
}),
]);
});