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>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { models } from '@web/../tests/web_test_helpers';
|
||||
import { ProductProduct as ProductModel } from './product_product';
|
||||
|
||||
export class ProductProduct extends ProductModel {
|
||||
_records = [
|
||||
{ id: 1, name: "Black chair", type: 'goods', list_price: 50.0 },
|
||||
{ id: 2, name: "Blue chair", type: 'goods', list_price: 60.0 },
|
||||
{ id: 3, name: "Black table", type: 'goods', list_price: 70.0 },
|
||||
{ id: 4, name: "Blue table", type: 'goods', list_price: 80.0 },
|
||||
{ id: 5, name: "Test Combo", type: 'combo', combo_ids: [1, 2] },
|
||||
];
|
||||
}
|
||||
|
||||
export class ProductComboItem extends models.ServerModel {
|
||||
_name = 'product.combo.item';
|
||||
_records = [
|
||||
{ id: 1, product_id: 1 },
|
||||
{ id: 2, product_id: 2 },
|
||||
{ id: 3, product_id: 3 },
|
||||
{ id: 4, product_id: 4 },
|
||||
];
|
||||
}
|
||||
|
||||
export class ProductCombo extends models.ServerModel {
|
||||
_name = 'product.combo';
|
||||
_records = [
|
||||
{ id: 1, name: "Chair combo", combo_item_ids: [1, 2] },
|
||||
{ id: 2, name: "Table combo", combo_item_ids: [3, 4] },
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
|
||||
export class ProductProduct extends models.ServerModel {
|
||||
_name = "product.product";
|
||||
|
||||
_records = [
|
||||
{id: 1, name: "Test Product", type: "consu", list_price: 20.0},
|
||||
{id: 2, name: "Test Service Product", type: "service", list_price: 50.0},
|
||||
{id: 14, name: "desk"},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
|
||||
export class ProductTemplate extends models.ServerModel {
|
||||
_name = "product.template";
|
||||
|
||||
get_single_product_variant() {
|
||||
return { product_id: 14, product_name: "desk" };
|
||||
}
|
||||
|
||||
_records = [{ id: 12, name: "desk" }];
|
||||
}
|
||||
16
frontend/product/static/tests/product_combo_test_helpers.js
Normal file
16
frontend/product/static/tests/product_combo_test_helpers.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { defineModels } from '@web/../tests/web_test_helpers';
|
||||
import {
|
||||
ProductCombo,
|
||||
ProductComboItem,
|
||||
ProductProduct,
|
||||
} from './mock_server/mock_models/product_combo';
|
||||
|
||||
export const comboModels = {
|
||||
ProductCombo,
|
||||
ProductComboItem,
|
||||
ProductProduct,
|
||||
}
|
||||
|
||||
export function defineComboModels() {
|
||||
defineModels(comboModels);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { defineMailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { expect, test } from "@odoo/hoot";
|
||||
import { queryAllTexts } from "@odoo/hoot-dom";
|
||||
import { contains, defineModels, fields, getService, models, mountWebClient, onRpc } from "@web/../tests/web_test_helpers";
|
||||
|
||||
class ProductProduct extends models.Model {
|
||||
_records = [{ id: 42, name: "Customizable Desk" }];
|
||||
|
||||
name = fields.Char();
|
||||
}
|
||||
|
||||
class ProductPricelist extends models.Model {
|
||||
_records = [
|
||||
{ id: 1, name: "Public Pricelist" },
|
||||
{ id: 2, name: "Test" },
|
||||
];
|
||||
|
||||
name = fields.Char();
|
||||
}
|
||||
|
||||
defineModels([ProductProduct, ProductPricelist]);
|
||||
defineMailModels();
|
||||
|
||||
test(`Pricelist Client Action`, async () => {
|
||||
onRpc("report.product.report_pricelist", "get_html", async () => "");
|
||||
|
||||
await mountWebClient();
|
||||
await getService("action").doAction({
|
||||
id: 1,
|
||||
name: "Generate Pricelist Report",
|
||||
tag: "generate_pricelist_report",
|
||||
type: "ir.actions.client",
|
||||
context: {
|
||||
active_ids: [42],
|
||||
active_model: "product.product",
|
||||
},
|
||||
});
|
||||
|
||||
// checking default pricelist
|
||||
expect(`select#pricelists > option:eq(0)`).toHaveText("Public Pricelist", {
|
||||
message: "should have default pricelist",
|
||||
});
|
||||
|
||||
// changing pricelist
|
||||
await contains(`select#pricelists`).select("2");
|
||||
|
||||
// check whether pricelist value has been updated or not
|
||||
expect(`select#pricelists > option:eq(0)`).toHaveText("Test", {
|
||||
message: "After pricelist change, the pricelist_id field should be updated",
|
||||
});
|
||||
|
||||
// check default quantities should be there
|
||||
expect(queryAllTexts(`.o_badges_list .badge`)).toEqual(["1", "5", "10"]);
|
||||
|
||||
// existing quantity can not be added.
|
||||
await contains(`.o_add_qty`).click();
|
||||
expect(queryAllTexts(`.o_badges_list .badge`)).toEqual(["1", "5", "10"]);
|
||||
expect(`.o_notification`).toHaveCount(1);
|
||||
expect(`.o_notification .o_notification_content`).toHaveText(
|
||||
"Quantity already present (1).",
|
||||
{ message: "Existing Quantity can not be added" }
|
||||
);
|
||||
expect(`.o_notification .o_notification_bar`).toHaveClass("bg-info");
|
||||
await contains(`.o_notification_close`).click();
|
||||
expect(`.o_notification`).toHaveCount(0);
|
||||
|
||||
// adding few more quantities to check.
|
||||
await contains(`.add-quantity-input`).edit("2", { confirm: false });
|
||||
await contains(`.o_add_qty`).click();
|
||||
expect(queryAllTexts(`.o_badges_list .badge`)).toEqual(["1", "2", "5", "10"]);
|
||||
expect(`.o_notification`).toHaveCount(0);
|
||||
|
||||
await contains(`.add-quantity-input`).edit("3", { confirm: false });
|
||||
await contains(`.o_add_qty`).click();
|
||||
expect(queryAllTexts(`.o_badges_list .badge`)).toEqual(["1", "2", "3", "5", "10"]);
|
||||
expect(`.o_notification`).toHaveCount(0);
|
||||
|
||||
// no more than 5 quantities can be used at a time
|
||||
await contains(`.add-quantity-input`).edit("4", { confirm: false });
|
||||
await contains(`.o_add_qty`).click();
|
||||
expect(queryAllTexts(`.o_badges_list .badge`)).toEqual(["1", "2", "3", "5", "10"]);
|
||||
expect(`.o_notification`).toHaveCount(1);
|
||||
expect(`.o_notification .o_notification_content`).toHaveText(
|
||||
"At most 5 quantities can be displayed simultaneously. Remove a selected quantity to add others.",
|
||||
{ message: "Can not add more then 5 quantities" }
|
||||
);
|
||||
expect(`.o_notification .o_notification_bar`).toHaveClass("bg-warning");
|
||||
});
|
||||
13
frontend/product/static/tests/product_test_helpers.js
Normal file
13
frontend/product/static/tests/product_test_helpers.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineModels } from '@web/../tests/web_test_helpers';
|
||||
import { ProductProduct } from './mock_server/mock_models/product_product';
|
||||
import { ProductTemplate } from './mock_server/mock_models/product_template';
|
||||
|
||||
|
||||
export const productModels = {
|
||||
ProductProduct,
|
||||
ProductTemplate,
|
||||
};
|
||||
|
||||
export function defineProductModels() {
|
||||
defineModels(productModels);
|
||||
}
|
||||
Reference in New Issue
Block a user