Files
goodie/frontend/sale/static/src/js/product/product.js
Marc 8741282322 Eliminate Python dependency: embed frontend assets in odoo-go
- Copy all OWL frontend assets (JS/CSS/XML/fonts/images) into frontend/
  directory (2925 files, 43MB) — no more runtime reads from Python Odoo
- Replace OdooAddonsPath config with FrontendDir pointing to local frontend/
- Rewire bundle.go, static.go, templates.go, webclient.go to read from
  frontend/ instead of external Python Odoo addons directory
- Auto-detect frontend/ and build/ dirs relative to binary in main.go
- Delete obsolete Python helper scripts (tools/*.py)

The Go server is now fully self-contained: single binary + frontend/ folder.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 23:09:12 +02:00

96 lines
2.9 KiB
JavaScript

import { Component } from "@odoo/owl";
import { formatCurrency } from "@web/core/currency";
import {
ProductTemplateAttributeLine as PTAL
} from "../product_template_attribute_line/product_template_attribute_line";
import { QuantityButtons } from '../quantity_buttons/quantity_buttons';
import { getSelectedCustomPtav } from "../sale_utils";
import { _t } from "@web/core/l10n/translation";
export class Product extends Component {
static components = { PTAL, QuantityButtons };
static template = "sale.Product";
static props = {
id: { type: [Number, {value: false}], optional: true },
product_tmpl_id: Number,
display_name: String,
description_sale: [Boolean, String], // backend sends 'false' when there is no description
price: Number,
quantity: Number,
uom: { type: Object, optional: true },
available_uoms: { type: Object, optional: true },
attribute_lines: Object,
optional: Boolean,
imageURL: { type: String, optional: true },
archived_combinations: Array,
exclusions: Object,
parent_exclusions: Object,
parent_product_tmpl_id: { type: Number, optional: true },
price_info: { type: String, optional: true },
selectedComboItems: {
type: Array,
element: Object,
shape: {
name: String,
},
optional: true,
},
};
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* Return the price, in the format of the given currency.
*
* @return {String} - The price, in the format of the given currency.
*/
getFormattedPrice() {
return formatCurrency(this.props.price, this.env.currency.id);
}
/**
* Check whether this product is the main product.
*
* @return {Boolean} - Whether this product is the main product.
*/
get isMainProduct() {
return this.env.mainProductTmplId === this.props.product_tmpl_id;
}
/**
* Return this product's image URL.
*
* @return {String} This product's image URL.
*/
get imageUrl() {
const modelPath = this.props.id
? `product.product/${ this.props.id }`
: `product.template/${ this.props.product_tmpl_id }`;
return `/web/image/${ modelPath }/image_256`;
}
/**
* Check whether the provided PTAL should be shown.
*
* @return {Boolean} Whether the PTAL should be shown.
*/
shouldShowPtal(ptal) {
return this.env.canChangeVariant
|| ptal.create_variant === 'no_variant'
|| !!getSelectedCustomPtav(ptal);
}
get UoMTitle() {
return _t("Packaging");
}
async selectUoM(event) {
this.env.setUoM(this.props.product_tmpl_id, parseInt(event.target.value));
}
}