19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:12 +01:00
parent 79f83631d5
commit 73afc09215
6267 changed files with 1534193 additions and 1130106 deletions

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<t t-inherit="event.EventRegistrationSummaryDialog" t-inherit-mode="extension">
<xpath expr="//div[@id='registration_header']" position="inside">
<t t-if="registration.sale_status_value">
<span class="badge rounded-pill" t-out="registration.sale_status_value" t-att-class="registration.has_to_pay ? 'text-bg-danger' : 'text-bg-success'"/>
</t>
</xpath>
</t>
</templates>

View file

@ -0,0 +1,46 @@
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { formView } from "@web/views/form/form_view";
/**
* This controller is overridden to allow configuring sale_order_lines through a popup
* window when a service product linked to events is selected.
*
* This allows keeping an editable list view for sales order and remove the noise of
* those 3 fields ('event_id' + 'event_slot_id' + 'event_ticket_id')
*/
export class EventConfiguratorController extends formView.Controller {
setup() {
super.setup();
this.action = useService("action");
}
/**
* We let the regular process take place to allow the validation of the required fields
* to happen.
*
* Then we can manually close the window, providing event information to the caller.
*
* @override
*/
async onRecordSaved(record) {
await super.onRecordSaved(...arguments);
const { event_id, event_slot_id, event_ticket_id } = record.data;
return this.action.doAction({
type: "ir.actions.act_window_close",
infos: {
eventConfiguration: {
event_id,
event_slot_id,
event_ticket_id,
},
},
});
}
}
registry.category("views").add("event_configurator_form", {
...formView,
Controller: EventConfiguratorController,
});

View file

@ -1,46 +0,0 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { formView } from "@web/views/form/form_view";
import { Record, RelationalModel } from "@web/views/relational_model";
/**
* This model is overridden to allow configuring sale_order_lines through a popup
* window when a product with 'detailed_type' == 'event' is selected.
*
* This allows keeping an editable list view for sales order and remove the noise of
* those 2 fields ('event_id' + 'event_ticket_id')
*/
export class EventConfiguratorRelationalModel extends RelationalModel {}
export class EventConfiguratorRecord extends Record {
/**
* We let the regular process take place to allow the validation of the required fields
* to happen.
*
* Then we can manually close the window, providing event information to the caller.
*
* @override
*/
async save() {
const isSaved = await super.save(...arguments);
if (!isSaved) {
return false;
}
this.model.action.doAction({type: 'ir.actions.act_window_close', infos: {
eventConfiguration: {
event_id: this.data.event_id,
event_ticket_id: this.data.event_ticket_id,
}
}});
return true;
}
}
EventConfiguratorRelationalModel.Record = EventConfiguratorRecord;
registry.category("views").add("event_configurator_form", {
...formView,
Model: EventConfiguratorRelationalModel,
});

View file

@ -1,45 +1,51 @@
/** @odoo-module **/
import { patch } from "@web/core/utils/patch";
import { SaleOrderLineProductField } from '@sale/js/sale_product_field';
import { SaleOrderLineProductField } from "@sale/js/sale_product_field";
import { useService } from "@web/core/utils/hooks";
patch(SaleOrderLineProductField.prototype, 'event_sale', {
async _onProductUpdate() {
this._super(...arguments);
if (this.props.record.data.product_type === 'event') {
patch(SaleOrderLineProductField.prototype, {
setup() {
super.setup();
this.action = useService("action");
},
get isEvent() {
return this.props.record.data.service_tracking === "event";
},
get hasConfigurationButton() {
return super.hasConfigurationButton || this.isEvent;
},
onEditConfiguration() {
if (this.isEvent) {
this._openEventConfigurator();
} else {
super.onEditConfiguration();
}
},
_editLineConfiguration() {
this._super(...arguments);
if (this.props.record.data.product_type === 'event') {
_onProductUpdate() {
if (this.isEvent) {
this._openEventConfigurator();
} else {
super._onProductUpdate();
}
},
get isConfigurableLine() {
return this._super(...arguments) || Boolean(this.props.record.data.event_ticket_id);
},
async _openEventConfigurator() {
let actionContext = {
'default_product_id': this.props.record.data.product_id[0],
const actionContext = {
default_product_id: this.props.record.data.product_id.id,
};
if (this.props.record.data.event_id) {
actionContext.default_event_id = this.props.record.data.event_id[0];
actionContext.default_event_id = this.props.record.data.event_id.id;
}
if (this.props.record.data.event_slot_id) {
actionContext.default_event_slot_id = this.props.record.data.event_slot_id[0];
}
if (this.props.record.data.event_ticket_id) {
actionContext.default_event_ticket_id = this.props.record.data.event_ticket_id[0];
actionContext.default_event_ticket_id = this.props.record.data.event_ticket_id.id;
}
this.action.doAction(
'event_sale.event_configurator_action',
{
additionalContext: actionContext,
onClose: async (closeInfo) => {
if (!closeInfo || closeInfo.special) {
if (!closeInfo?.eventConfiguration || closeInfo.special || closeInfo.dismiss) {
// wizard popup closed or 'Cancel' button triggered
if (!this.props.record.data.event_ticket_id) {
// remove product if event configuration was cancelled.

View file

@ -1,77 +1,59 @@
odoo.define('event.event_configurator_tour', function (require) {
"use strict";
var tour = require('web_tour.tour');
tour.register('event_configurator_tour', {
url: "/web",
test: true,
}, [tour.stepUtils.showAppsMenuItem(), {
trigger: '.o_app[data-menu-xmlid="sale.sale_menu_root"]',
edition: 'community'
}, {
trigger: '.o_app[data-menu-xmlid="sale.sale_menu_root"]',
edition: 'enterprise'
}, {
trigger: ".o_list_button_add",
extra_trigger: ".o_sale_order"
}, {
trigger: "a:contains('Add a product')"
}, {
trigger: 'div[name="product_id"] input, div[name="product_template_id"] input',
run: function (actions) {
actions.text('Event Registration');
}
}, {
trigger: 'ul.ui-autocomplete a:contains("Event Registration")',
run: 'click'
}, {
trigger: 'div[name="event_id"] input',
run: 'click'
}, {
trigger: 'ul.ui-autocomplete a:contains("Design")',
run: 'click',
in_modal: false
}, {
trigger: 'div[name="event_ticket_id"] input',
run: 'click'
}, {
trigger: 'ul.ui-autocomplete a:contains("VIP")',
run: 'click',
in_modal: false
}, {
trigger: '.o_event_sale_js_event_configurator_ok'
}, {
trigger: "td[name='name'][data-tooltip*='VIP']",
run: function () {} // check
}, {
trigger: 'ul.nav a:contains("Order Lines")',
run: 'click'
}, {
content: "search the partner",
trigger: 'div[name="partner_id"] input',
run: 'text Azure'
}, {
content: "select the partner",
trigger: 'ul.ui-autocomplete > li > a:contains(Azure)',
}, {
trigger: 'td:contains("Event")',
run: 'click'
}, {
trigger: 'button.fa-pencil'
}, {
trigger: 'div[name="event_ticket_id"] input',
run: 'click'
}, {
trigger: 'ul.ui-autocomplete a:contains("Standard")',
run: 'click',
in_modal: false
}, {
trigger: '.o_event_sale_js_event_configurator_ok'
}, {
trigger: "td[name='name'][data-tooltip*='Standard']",
run: function () {} // check
}, ...tour.stepUtils.saveForm()
]);
import { registry } from "@web/core/registry";
import { stepUtils } from "@web_tour/tour_utils";
import tourUtils from "@sale/js/tours/tour_utils";
registry.category("web_tour.tours").add("event_configurator_tour", {
url: "/odoo",
steps: () => [
...stepUtils.goToAppSteps("sale.sale_menu_root", "Go to the Sales App"),
...tourUtils.createNewSalesOrder(),
...tourUtils.selectCustomer("Azure"),
...tourUtils.addProduct("Event Registration"),
{
trigger: 'div[name="event_id"] input',
run: "click",
},
{
trigger: "ul.ui-autocomplete a:text(Design Fair Los Angeles)",
run: "click",
},
{
trigger: 'div[name="event_ticket_id"] input',
run: "click",
},
{
trigger: "ul.ui-autocomplete a:contains(VIP)",
run: "click",
},
{
trigger: ".modal .o_event_sale_js_event_configurator_ok",
run: "click",
},
{
content: "Wait the modal is closed",
trigger: "body:not(:has(.modal))",
},
...tourUtils.clickSomewhereElse(),
tourUtils.editLineMatching("Event Registration", "VIP"),
tourUtils.editConfiguration(),
{
trigger: 'div[name="event_ticket_id"] input',
run: "click",
},
{
trigger: "ul.ui-autocomplete a:contains(Standard)",
run: "click",
},
{
trigger: ".modal .o_event_sale_js_event_configurator_ok",
run: "click",
},
{
content: "Wait the modal is closed",
trigger: "body:not(:has(.modal))",
},
...tourUtils.clickSomewhereElse(),
tourUtils.checkSOLDescriptionContains("Event Registration", "Standard"),
...stepUtils.saveForm(),
],
});