Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
078b57795b | ||
|
|
68a388cd78 | ||
|
|
61fd457af0 | ||
|
|
bde9dbc48d | ||
|
|
1fd092a9f0 | ||
|
|
8d1b953c61 | ||
|
|
497002a112 | ||
|
|
b28c002d7d | ||
|
|
59ffde396f | ||
|
|
29ff175e89 | ||
|
|
2b0e89191a | ||
|
|
9d14652a57 | ||
|
|
634f4fcdf1 | ||
|
|
bd0881f882 | ||
|
|
c83186f809 | ||
|
|
1f8179d562 | ||
|
|
cdf166632a | ||
|
|
1b0198913c | ||
|
|
a6ada39784 | ||
|
|
bb963850b1 | ||
|
|
28d95b4dcd | ||
|
|
5d2dc11fbc | ||
|
|
8319a74f99 | ||
|
|
5cf58ffa8a | ||
|
|
7dfd5aec9b | ||
|
|
768dc1151a | ||
|
|
1a1b62136f | ||
|
|
f0a2c8d745 | ||
|
|
53e9ea999d | ||
|
|
092f1e44a2 | ||
|
|
17f171d3d9 | ||
|
|
5535f10e7d | ||
|
|
a0ef97b48d | ||
|
|
f3e2812694 | ||
|
|
80bf4bc019 | ||
|
|
a8c5c1837d | ||
|
|
04199bd606 | ||
|
|
570085cb04 | ||
|
|
d440d3fa15 | ||
|
|
2677881a88 | ||
|
|
68dd48e506 | ||
|
|
5aa4782de7 | ||
|
|
99245764a9 | ||
|
|
5ce14ea666 | ||
|
|
e067fec168 | ||
|
|
ff42a242db | ||
|
|
ada9605c90 | ||
|
|
babc4642ce | ||
|
|
d69a3da26e | ||
|
|
1c3a2a4b0e | ||
|
|
4d5d59f3bd | ||
|
|
c55c707694 | ||
|
|
63e43ce7a1 | ||
|
|
832bb41206 | ||
|
|
64540e208f | ||
|
|
c74315e950 | ||
|
|
e8c93d89ad | ||
|
|
82b74c359a | ||
|
|
5d65fa7027 | ||
|
|
c6509e9920 | ||
|
|
0e832d8fd1 | ||
|
|
2aa9b19c3c | ||
|
|
bc942cdb7c | ||
|
|
8f72652ada | ||
|
|
812571b177 | ||
|
|
f2e375a8f1 | ||
|
|
d8a6126b9d | ||
|
|
bcd0ef890a | ||
|
|
2359e87a35 | ||
|
|
9e38e05aad | ||
|
|
0f8ae45e59 | ||
|
|
95d5d455b9 | ||
|
|
7497fbf588 | ||
|
|
6d486ad954 | ||
|
|
ae97f4f5eb | ||
|
|
f119f041f0 | ||
|
|
8fc647826f | ||
|
|
b71d6bddb9 | ||
|
|
ec6e496900 | ||
|
|
46b943bffe | ||
|
|
ef0ea506c2 | ||
|
|
0a493d4e10 | ||
|
|
e6f0b6a395 | ||
|
|
283983012f | ||
|
|
3e2a7a71a6 | ||
|
|
4801e09466 | ||
|
|
02b7b4f18c | ||
|
|
3d8fe194be | ||
|
|
db8b2b1c63 | ||
|
|
9715a3b01f | ||
|
|
b42f754525 | ||
|
|
ada11e42cf | ||
|
|
f457858a0f | ||
|
|
937e79b59d | ||
|
|
137bd1a2ae | ||
|
|
3dad3c61db | ||
|
|
a7a428c66e | ||
|
|
5c3b66c90b | ||
|
|
91e4162230 | ||
|
|
6c488a443f | ||
|
|
740e5650a9 | ||
|
|
185e7ab419 | ||
|
|
2a62ac871a | ||
|
|
14029c1074 | ||
|
|
355c5d022e | ||
|
|
48266e8e77 | ||
|
|
fd3f1dc53e | ||
|
|
2940d33273 | ||
|
|
46e874b1e7 | ||
|
|
01c5dd35e3 | ||
|
|
e37acde30c | ||
|
|
bfa7f595cc | ||
|
|
c6adb31afc | ||
|
|
5f647c055a | ||
|
|
91ce3d9a4f | ||
|
|
622d9f0310 | ||
|
|
0cd0fa1af1 | ||
|
|
73b3f34696 | ||
|
|
ea97e65416 | ||
|
|
972453747b | ||
|
|
141bf20c03 | ||
|
|
b9a730942f | ||
|
|
12704a5618 | ||
|
|
268b2645e2 | ||
|
|
a84ee5e983 | ||
|
|
68c26e9725 | ||
|
|
2fe0c31e2b |
No files matched your search
@@ -28,8 +28,7 @@
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="style.css" /></noscript>
|
||||
<link rel="stylesheet" href="style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- Australia landing page (page-scoped; additive) ---- */
|
||||
.cmp-sr-only {
|
||||
@@ -392,7 +391,7 @@
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
@@ -408,6 +407,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero cmp-hero">
|
||||
<div class="hero-bg">
|
||||
<img
|
||||
@@ -428,7 +428,7 @@
|
||||
money in one system, hosted on our own servers in Sydney, Australia. No setup fee. Cancel at any time.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":4,"qty":1,"info":"Australia"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Get On the Rise — $395 a year</button>
|
||||
@@ -635,7 +635,7 @@
|
||||
<h2 class="section-title">Questions the price raises</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary>Where is my data actually stored?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Where is my data actually stored?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
On our servers in Sydney, Australia. When you choose Australia (Sydney) as your server location,
|
||||
@@ -645,7 +645,7 @@
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>How much does Odoo hosting cost in Australia?</summary>
|
||||
<summary class="plausible-event-name=FAQ">How much does Odoo hosting cost in Australia?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Four plans, all billed yearly in US dollars with tax added at checkout: Side Hustle $ 214.00, On
|
||||
@@ -656,7 +656,7 @@
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Do the backups run automatically?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Do the backups run automatically?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Yes — backups run on a schedule without you setting anything up. The number of slots depends on
|
||||
@@ -667,7 +667,7 @@
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>How is this different from odoo.sh?</summary>
|
||||
<summary class="plausible-event-name=FAQ">How is this different from odoo.sh?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
odoo.sh is Odoo's own hosting, running Odoo Enterprise for a developer workflow — you deploy by
|
||||
@@ -679,7 +679,7 @@
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Can I add my own apps, or have something built for me?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Can I add my own apps, or have something built for me?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Yes. Odoo's own apps are all there on every plan, and from On the Rise upwards you can add custom
|
||||
@@ -691,7 +691,7 @@
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>What if I outgrow my plan?</summary>
|
||||
<summary class="plausible-event-name=FAQ">What if I outgrow my plan?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
You move up without a data migration and without downtime. Upgrade from your Odoo settings and
|
||||
@@ -701,7 +701,7 @@
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Do you have Australian support hours, or an Australian office?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Do you have Australian support hours, or an Australian office?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
No separate Australian support desk is published, and we do not claim an Australian office or
|
||||
@@ -721,7 +721,7 @@
|
||||
<div class="container">
|
||||
<p class="cmp-lead">Pick a plan, choose Sydney, and your system is live in about five minutes.</p>
|
||||
<div class="cmp-cta-actions">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":4,"qty":1,"info":"Australia"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Get On the Rise — $395 a year</button>
|
||||
@@ -733,6 +733,7 @@
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
@@ -741,6 +742,7 @@
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="legal.html">Legal</a></li>
|
||||
</ul>
|
||||
@@ -764,7 +766,7 @@
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:hello@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="cmp-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
|
||||
@@ -1,5 +1,59 @@
|
||||
{
|
||||
"posts": [
|
||||
{
|
||||
"id": "your-agent-can-run-your-odoo-hosting",
|
||||
"date": "2026-11-05",
|
||||
"area": "news",
|
||||
"headline": "Your Agent Can Run Your Odoo Hosting: the MCP Server Is Live",
|
||||
"teaser": "This is the piece of the Odoo 20 update we are asked about most: an MCP server that lets your agent work on your Odoo ho",
|
||||
"link": "blog/posts/your-agent-can-run-your-odoo-hosting.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/20_4server.png"
|
||||
},
|
||||
{
|
||||
"id": "freelancer-directory-soft-launch",
|
||||
"date": "2026-11-04",
|
||||
"area": "news",
|
||||
"headline": "Our freelancer directory opens on 1 December. Help us get the signup right",
|
||||
"teaser": "We need your help! We are opening our Odoo Community Freelancer directory on 1 December. Before real clients start brows",
|
||||
"link": "blog/posts/freelancer-directory-soft-launch.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/freelance_platform.png"
|
||||
},
|
||||
{
|
||||
"id": "odoo-20-is-live-on-our-servers-here-is-what-changed",
|
||||
"date": "2026-11-03",
|
||||
"area": "news",
|
||||
"headline": "Odoo 20 Is Live on Our Servers — Here Is What Changed",
|
||||
"teaser": "Two weeks. That is how long it took us to bring up Odoo 20 on our servers, with every new feature that comes with it. It",
|
||||
"link": "blog/posts/odoo-20-is-live-on-our-servers-here-is-what-changed.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/ODOO_20_chatter.png"
|
||||
},
|
||||
{
|
||||
"id": "from-a-spreadsheet-to-a-running-erp",
|
||||
"date": "2026-11-02",
|
||||
"area": "news",
|
||||
"headline": "From a Spreadsheet to a Running ERP in Ten Thursday Sessions",
|
||||
"teaser": "Most small businesses do not run on an ERP. They run on a spreadsheet, a messaging group, and one person's memory. It wo",
|
||||
"link": "blog/posts/from-a-spreadsheet-to-a-running-erp.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/screencast.png"
|
||||
},
|
||||
{
|
||||
"id": "oca-paraguay-internationalization-hackathon",
|
||||
"date": "2026-10-29",
|
||||
"area": "news",
|
||||
"headline": "ODOO4projects Supports the OCA Paraguay Internationalization Hackathon",
|
||||
"teaser": "Two online days to push Odoo's Paraguayan localisation forward — and we are supporting them.",
|
||||
"link": "blog/posts/oca-paraguay-internationalization-hackathon.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/py_hackathon.png"
|
||||
},
|
||||
{
|
||||
"id": "how-to-install-odoo-modules-using-git",
|
||||
"date": "2026-10-28",
|
||||
"area": "deep dive",
|
||||
"headline": "How to Install Odoo Modules Using Git — and the Quick Git Route That Skips the Console",
|
||||
"teaser": "Every business is slightly different, which is why a system that only does the standard thing is only ever half a system",
|
||||
"link": "blog/posts/how-to-install-odoo-modules-using-git.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/screenshot_git.png"
|
||||
},
|
||||
{
|
||||
"id": "odoo-community-is-going-online-on-odoo4projects",
|
||||
"date": "2026-10-27",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
body { background: #0d1b2e; }
|
||||
.blog-post { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem 6rem; color: #171c26; background: #faf7f1; min-height: 100vh; }
|
||||
@@ -60,6 +60,12 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="blog-post">
|
||||
@@ -77,7 +83,7 @@
|
||||
<p>You can now download and archive logfiles directly from the app. <strong>Tip:</strong> When debugging an issue, download the relevant logfile to analyze it locally. Archive older logs regularly to keep your system organized and reduce clutter.</p>
|
||||
|
||||
<h3>3. Take advantage of the free backup schema</h3>
|
||||
<p>We've added a free backup schema for everyone to improve data security. <strong>Tip:</strong> Make sure backups are scheduled and test restoring from a backup occasionally to ensure your data is safe.</p>
|
||||
<p>We've added a <a href="../../index.html#pricing">free backup schema</a> for everyone to improve data security. <strong>Tip:</strong> Make sure backups are scheduled and test restoring from a backup occasionally to ensure your data is safe.</p>
|
||||
|
||||
<h3>4. Explore the improved AI server management backend</h3>
|
||||
<p>The AI server management backend has been upgraded. <strong>Tip:</strong> Spend a few minutes navigating the new interface—you'll find streamlined workflows that make server management more intuitive.</p>
|
||||
@@ -86,7 +92,7 @@
|
||||
<p>Module installation via GIT has been improved. <strong>Tip:</strong> Use GIT to install or update modules more efficiently, especially when you need to manage versions or deploy across multiple environments.</p>
|
||||
|
||||
<h3>6. Get instant help from the AI support bot</h3>
|
||||
<p>Our AI support bot has also been improved. <strong>Tip:</strong> When you run into a question, ask the bot first—it's a quick way to get answers without leaving your workflow.</p>
|
||||
<p>Our <a href="../../support.html">AI support bot</a> has also been improved. <strong>Tip:</strong> When you run into a question, ask the bot first—it's a quick way to get answers without leaving your workflow.</p>
|
||||
|
||||
<p>These updates are designed to save you time and give you more control over your Odoo hosting. Ready to try them out? <a href="https://odoo4projects.com">Start your free trial on ODOO4projects.com</a>.</p>
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #714b67;
|
||||
@@ -126,8 +126,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -297,7 +304,10 @@
|
||||
</li>
|
||||
</ol>
|
||||
<p>
|
||||
Until then, Community + quality hosting is the financially smarter choice.
|
||||
Until then, Community + <a href="../../odoo-hosting-2027.html">quality hosting</a> is the financially smarter choice.
|
||||
</p>
|
||||
<p>
|
||||
When that moment arrives, we take the upgrade on ourselves — what changes, and how we do it for you, is set out on <a href="../../odoo-community-upgrade.html">our Odoo Community upgrade page</a>.
|
||||
</p>
|
||||
|
||||
<div class="cta-box">
|
||||
@@ -314,6 +324,7 @@
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,83 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Our freelancer directory opens on 1 December. Help us get the signup right | ODOO4projects</title>
|
||||
<meta name="description" content="We need your help! We are opening our Odoo Community Freelancer directory on 1 December. Before real clients start brows" />
|
||||
<link rel="canonical" href="https://odoo4projects.com/blog/posts/freelancer-directory-soft-launch.html" />
|
||||
<meta property="og:title" content="Our freelancer directory opens on 1 December. Help us get the signup right" />
|
||||
<meta property="og:description" content="We need your help! We are opening our Odoo Community Freelancer directory on 1 December. Before real clients start brows" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/blog/posts/freelancer-directory-soft-launch.html" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:image" content="https://image.office.odoo4projects.com/img/freelance_platform.png" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<link rel="icon" href="../../images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
body { background: #0d1b2e; }
|
||||
.blog-post { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem 6rem; color: #171c26; background: #faf7f1; min-height: 100vh; }
|
||||
.blog-post h1 { font-family: 'Marcellus', Georgia, serif; font-size: 2.4rem; font-weight: 400; margin: 0 0 0.5rem; color: #0d1b2e; }
|
||||
.blog-post .post-meta { font-family: Inter, sans-serif; font-size: 0.82rem; color: rgba(23,28,38,0.6); margin-bottom: 2rem; }
|
||||
.blog-post .post-meta .badge { display: inline-block; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.15em; text-transform: uppercase; color: #c9a227; margin-right: 0.75rem; }
|
||||
.blog-post .post-image { width: 100%; border-radius: 0.75rem; margin-bottom: 2rem; box-shadow: 0 2px 8px rgba(13,27,46,0.08); }
|
||||
.blog-post p { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; }
|
||||
.blog-post h2 { font-family: 'Marcellus', Georgia, serif; font-size: 1.6rem; font-weight: 400; margin: 2rem 0 0.75rem; color: #0d1b2e; }
|
||||
.blog-post a { color: #8a6f1f; text-decoration: underline; }
|
||||
.blog-post strong { font-weight: 600; }
|
||||
.back-link { display: inline-block; margin-top: 2rem; font-family: 'Marcellus', Georgia, serif; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.04em; color: #c9a227; text-decoration: none; }
|
||||
.back-link:hover { text-decoration: underline; }
|
||||
@media (max-width: 600px) { .blog-post h1 { font-size: 1.7rem; } .blog-post { padding: 2rem 1rem 4rem; } }
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"headline": "Our freelancer directory opens on 1 December. Help us get the signup right",
|
||||
"datePublished": "2026-11-04",
|
||||
"url": "https://odoo4projects.com/blog/posts/freelancer-directory-soft-launch.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/freelance_platform.png",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://odoo4projects.com/images/logo.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="blog-post">
|
||||
<span class="badge">news</span>
|
||||
<h1>Our freelancer directory opens on 1 December. Help us get the signup right</h1>
|
||||
<div class="post-meta">November 4, 2026 · News</div>
|
||||
<img src="https://image.office.odoo4projects.com/img/freelance_platform.png" alt="Our freelancer directory opens on 1 December. Help us get the signup right" class="post-image" loading="lazy" />
|
||||
<div class="post-body">
|
||||
<p>We need your help!<br><br>We are opening our <b>Odoo Community Freelancer directory</b> on 1 December. Before real clients start browsing it, we want the signup to work, and we would like your help to get it right.</p>
|
||||
<p>So this is a soft launch. Sign up for free and tell us how the signup went: where you got stuck, what you expected to find, what you would change. That feedback is what we fix before opening day.</p>
|
||||
<p>Joining is free, for freelancers and clients both. The directory is where a freelancer describes their work, in their own words.</p>
|
||||
<p>If you are a member of the Odoo Community Association, this is a chance to be seen alongside your community. Your profile card carries an OCA Member Profile badge, and a visitor can filter the directory by OCA membership. We mark it, and the choice of who to contact stays with the visitor.</p>
|
||||
<p>Start here: <a href="https://odoo4projects.com/feedback/">odoo4projects.com/feedback</a></p>
|
||||
</div>
|
||||
<a href="../../index.html#blog" class="back-link">← Back to the Blog</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,97 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>From a Spreadsheet to a Running ERP in Ten Thursday Sessions | ODOO4projects</title>
|
||||
<meta name="description" content="Most small businesses do not run on an ERP. They run on a spreadsheet, a messaging group, and one person's memory. It works — until that person is on holiday." />
|
||||
<link rel="canonical" href="https://odoo4projects.com/blog/posts/from-a-spreadsheet-to-a-running-erp.html" />
|
||||
<meta property="og:title" content="From a Spreadsheet to a Running ERP in Ten Thursday Sessions" />
|
||||
<meta property="og:description" content="Most small businesses do not run on an ERP. They run on a spreadsheet, a messaging group, and one person's memory. It works — until that person is on holiday." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:image" content="https://image.office.odoo4projects.com/img/screencast.png" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<link rel="icon" href="../../images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
body { background: #0d1b2e; }
|
||||
.blog-post { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem 6rem; color: #171c26; background: #faf7f1; min-height: 100vh; }
|
||||
.blog-post h1 { font-family: 'Marcellus', Georgia, serif; font-size: 2.4rem; font-weight: 400; margin: 0 0 0.5rem; color: #0d1b2e; }
|
||||
.blog-post .post-meta { font-family: Inter, sans-serif; font-size: 0.82rem; color: rgba(23,28,38,0.6); margin-bottom: 2rem; }
|
||||
.blog-post .post-meta .badge { display: inline-block; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.15em; text-transform: uppercase; color: #c9a227; margin-right: 0.75rem; }
|
||||
.blog-post .post-image { width: 100%; border-radius: 0.75rem; margin-bottom: 2rem; box-shadow: 0 2px 8px rgba(13,27,46,0.08); }
|
||||
.blog-post p { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; }
|
||||
.blog-post ul { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; padding-left: 1.5rem; }
|
||||
.blog-post li { margin-bottom: 0.3rem; }
|
||||
.blog-post a { color: #8a6f1f; text-decoration: underline; }
|
||||
.blog-post strong { font-weight: 600; }
|
||||
.back-link { display: inline-block; margin-top: 2rem; font-family: 'Marcellus', Georgia, serif; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.04em; color: #c9a227; text-decoration: none; }
|
||||
.back-link:hover { text-decoration: underline; }
|
||||
@media (max-width: 600px) { .blog-post h1 { font-size: 1.7rem; } .blog-post { padding: 2rem 1rem 4rem; } }
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"headline": "From a Spreadsheet to a Running ERP in Ten Thursday Sessions",
|
||||
"datePublished": "2026-11-02",
|
||||
"dateModified": "2026-11-02",
|
||||
"url": "https://odoo4projects.com/blog/posts/from-a-spreadsheet-to-a-running-erp.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/screencast.png",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://odoo4projects.com/images/logo.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="blog-post">
|
||||
<span class="badge">news</span>
|
||||
<h1>From a Spreadsheet to a Running ERP in Ten Thursday Sessions</h1>
|
||||
<div class="post-meta">November 2, 2026 · News</div>
|
||||
<img src="https://image.office.odoo4projects.com/img/screencast.png" alt="From a Spreadsheet to a Running ERP in Ten Thursday Sessions" class="post-image" loading="lazy" />
|
||||
<div class="post-body">
|
||||
<p>Most small businesses do not run on an ERP. They run on a spreadsheet, a messaging group, and one person's memory. It works — until that person is on holiday.</p>
|
||||
|
||||
<p>The <strong>Odoo ERP Automation Bootcamp</strong> is ten live Thursday sessions where you build a working system for your own company: your products, your customers, your quotes, your invoices, your stock.</p>
|
||||
|
||||
<p>No programming. No server to install. If you can run your business on a spreadsheet, you can do this.</p>
|
||||
|
||||
<p><strong>What you get</strong></p>
|
||||
<ul>
|
||||
<li>Ten live sessions, one hour each — Thursdays, 18:00–19:00 Central Time</li>
|
||||
<li>Starts Thursday 21 January 2027</li>
|
||||
<li>You build on a live system from the first session, not on slides</li>
|
||||
<li><strong>One year of hosted Odoo Community Edition included</strong> — you automate on a real instance, not a sandbox you set up once and forget</li>
|
||||
<li>A group capped at six, so everyone gets seen</li>
|
||||
</ul>
|
||||
|
||||
<p>You finish with an ERP you actually use, and the judgement to keep it running yourself.</p>
|
||||
|
||||
<p>USD 595.00. Details and the full ten lessons: <a href="https://odoo4projects.com/odoo-erp-automation-bootcamp/?utm_source=linkedin&utm_medium=social&utm_campaign=bootcamp-jan2027">odoo4projects.com/odoo-erp-automation-bootcamp</a></p>
|
||||
</div>
|
||||
<a href="../../index.html#blog" class="back-link">← Back to the Blog</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -36,7 +36,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
.blog-header {
|
||||
padding: 2rem 0;
|
||||
@@ -195,8 +195,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -220,7 +227,7 @@
|
||||
<ul>
|
||||
<li>An active Odoo Enterprise subscription key</li>
|
||||
<li>A full database backup of your CE instance</li>
|
||||
<li>Your ODOO4projects Powerhouse plan (or higher)</li>
|
||||
<li>Your ODOO4projects <a href="../../index.html#pricing">Powerhouse plan</a> (or higher)</li>
|
||||
</ul>
|
||||
<div class="pro-tip">
|
||||
<strong>Pro Tip:</strong> Always take a backup before
|
||||
@@ -267,6 +274,7 @@
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,187 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>How to Install Odoo Modules Using Git — and the Quick Git Route That Skips the Console | ODOO4projects</title>
|
||||
<meta name="description" content="Every business is slightly different, which is why a system that only does the standard thing is only ever half a system. Odoo ships with a broad set of apps -" />
|
||||
<link rel="canonical" href="https://odoo4projects.com/blog/posts/how-to-install-odoo-modules-using-git.html" />
|
||||
<meta property="og:title" content="How to Install Odoo Modules Using Git — and the Quick Git Route That Skips the Console" />
|
||||
<meta property="og:description" content="Every business is slightly different, which is why a system that only does the standard thing is only ever half a system. Odoo ships with a broad set of apps -" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:image" content="https://image.office.odoo4projects.com/img/screenshot_git.png" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<link rel="icon" href="../../images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
body { background: #0d1b2e; }
|
||||
.blog-post { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem 6rem; color: #171c26; background: #faf7f1; min-height: 100vh; }
|
||||
.blog-post h1 { font-family: 'Marcellus', Georgia, serif; font-size: 2.4rem; font-weight: 400; margin: 0 0 0.5rem; color: #0d1b2e; }
|
||||
.blog-post .post-meta { font-family: Inter, sans-serif; font-size: 0.82rem; color: rgba(23,28,38,0.6); margin-bottom: 2rem; }
|
||||
.blog-post .post-meta .badge { display: inline-block; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.15em; text-transform: uppercase; color: #c9a227; margin-right: 0.75rem; }
|
||||
.blog-post .post-image { width: 100%; border-radius: 0.75rem; margin-bottom: 2rem; box-shadow: 0 2px 8px rgba(13,27,46,0.08); }
|
||||
.blog-post p { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; }
|
||||
.blog-post h2 { font-family: 'Marcellus', Georgia, serif; font-size: 1.6rem; font-weight: 400; margin: 2rem 0 0.75rem; color: #0d1b2e; }
|
||||
.blog-post ul, .blog-post ol { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; padding-left: 1.5rem; }
|
||||
.blog-post li { margin-bottom: 0.3rem; }
|
||||
.blog-post a { color: #8a6f1f; text-decoration: underline; }
|
||||
.blog-post strong { font-weight: 600; }
|
||||
.blog-post figure { margin: 2rem 0; }
|
||||
.blog-post figure img { width: 100%; border-radius: 0.75rem; box-shadow: 0 2px 8px rgba(13,27,46,0.08); }
|
||||
.blog-post figcaption { font-family: Inter, sans-serif; font-size: 0.85rem; line-height: 1.6; color: rgba(23,28,38,0.6); margin-top: 0.6rem; }
|
||||
.back-link { display: inline-block; margin-top: 2rem; font-family: 'Marcellus', Georgia, serif; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.04em; color: #c9a227; text-decoration: none; }
|
||||
.back-link:hover { text-decoration: underline; }
|
||||
@media (max-width: 600px) { .blog-post h1 { font-size: 1.7rem; } .blog-post { padding: 2rem 1rem 4rem; } }
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"headline": "How to Install Odoo Modules Using Git — and the Quick Git Route That Skips the Console",
|
||||
"datePublished": "2026-10-28",
|
||||
"dateModified": "2026-10-28",
|
||||
"url": "https://odoo4projects.com/blog/posts/how-to-install-odoo-modules-using-git.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/screenshot_git.png",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://odoo4projects.com/images/logo.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="blog-post">
|
||||
<span class="badge">deep dive</span>
|
||||
<h1>How to Install Odoo Modules Using Git — and the Quick Git Route That Skips the Console</h1>
|
||||
<div class="post-meta">October 28, 2026 · Deep Dive</div>
|
||||
<img src="https://image.office.odoo4projects.com/img/screenshot_git.png" alt="How to Install Odoo Modules Using Git — and the Quick Git Route That Skips the Console" class="post-image" loading="lazy" />
|
||||
<div class="post-body">
|
||||
<p>Every business is slightly different, which is why a system that only does the standard thing is only ever half a system. Odoo ships with a broad set of apps - sales, invoicing, stock, purchasing, projects, website - and on top of that it lets you add <strong>modules</strong>: focused pieces of function that one business needed and someone wrote down properly. Installing a module is the moment your system stops being shipped defaults and starts being yours.</p>
|
||||
|
||||
<p>This is the long version of that operation: what a module actually is, where to find a good one, and the two routes into a live instance on our servers - <strong>Quick Git</strong> and <strong>Git</strong>. Read it once and the phrase "just install the module" stops being a mystery.</p>
|
||||
|
||||
<h2>1. What an app or a module is - and where to find one</h2>
|
||||
|
||||
<p>A module (the words "app" and "module" get used interchangeably, and nobody is being sloppy when they do) is a business capability that has been packaged so the system can pick it up. A stock reservation method, a localisation for your country's tax rules, a dashboard for one department - each of those is a module somewhere.</p>
|
||||
|
||||
<p>There are two places worth looking, and they are not equivalent:</p>
|
||||
|
||||
<ul>
|
||||
<li><strong>apps.odoo.com</strong> - the official app store. Largest catalogue, most commercial publishers, and a mixture of quality that ranges from excellent to abandoned.</li>
|
||||
<li><strong>apps.odoo-community.org</strong> - the Odoo Community Association's own index. Smaller, curated, and built by the people who write Odoo for a living.</li>
|
||||
</ul>
|
||||
|
||||
<p>Search on what the business needs to <em>do</em>, not on what you think the feature is called. "Reserve stock for a customer order" finds better things than "stock module" does.</p>
|
||||
|
||||
<h2>2. What you are actually downloading - quality, version, and a folder of files</h2>
|
||||
|
||||
<p><strong>A module is a folder of files.</strong> That is the whole secret. It holds a manifest that names it, Python and XML that describe what it does, and whatever assets it needs. Your instance reads that folder. There is no installer in the classic sense, no setup wizard that writes into the operating system - which is exactly why the two routes below are both, essentially, "get the folder in front of the server and tell the server to look again".</p>
|
||||
|
||||
<p>Two things decide whether a module is worth your time:</p>
|
||||
|
||||
<ol>
|
||||
<li><strong>Provider quality.</strong> The app store marks modules and providers with quality indicators, and the reviews on the card are worth reading before the description. The best of the lot are the <strong>OCA modules</strong> - they are made with ❤️ by the community association, peer-reviewed, and maintained against new Odoo versions by people who have no incentive to sell you anything.</li>
|
||||
<li><strong>Version match.</strong> A module is written for one Odoo version. It needs to match the version of <em>your</em> instance. A module built for a different version is not "probably fine" - it is the single most common reason a module misbehaves after installation, and no amount of restarting fixes it.</li>
|
||||
</ol>
|
||||
|
||||
<p><strong>What you get when you download.</strong> Downloading a module gives you a <strong>zip file</strong>, and inside that zip you will often find several <strong>sub-modules, each in its own separate folder</strong>. That detail matters later: the system looks for modules at a certain depth, and a zip that has been unpacked one folder too deep is the second most common reason a module never appears.</p>
|
||||
|
||||
<p>Both routes below are described in detail, because they solve the same problem for two different kinds of user.</p>
|
||||
|
||||
<h2>3. Two ways to install: Git, or Quick Git</h2>
|
||||
|
||||
<p><strong>With Git</strong> you are the professional who wants the full workflow: your own repository per instance, your own keys, your own history, push and pull as you develop.</p>
|
||||
|
||||
<p><strong>With Quick Git</strong> you just want the thing working: you upload your zip file and our servers handle all the git work behind it. Same destination, far less to learn.</p>
|
||||
|
||||
<p>Pick by who you are. If you are going to develop against the instance, use Git. If you bought a module, got a zip, and want it live this afternoon, Quick Git is the shorter road.</p>
|
||||
|
||||
<h2>4. Upload the module: Quick Git</h2>
|
||||
|
||||
<p>Everything happens inside your Odoo, in the console we run for you:</p>
|
||||
|
||||
<ol>
|
||||
<li>Go to <strong>settings -> 4server -> GIT/MCP</strong> in your ODOO.</li>
|
||||
<li>Click on the button <strong>Import Module</strong> and select your ZIP file.</li>
|
||||
<li>Confirm the upload.</li>
|
||||
<li>After the upload is confirmed, <strong>restart the server</strong> - and then do the <strong>Update Module List</strong> dance (section 6). Both steps, in that order.</li>
|
||||
</ol>
|
||||
|
||||
<figure>
|
||||
<img src="https://image.office.odoo4projects.com/img/screenshot_quick_git.png" alt="Settings -> 4server -> GIT/MCP, with the Import Module dialog open: choose the Module .ZIP file, then click Import.">
|
||||
<figcaption>Quick Git: Settings → 4server → GIT/MCP, then <strong>Import Module</strong> and pick your ZIP.</figcaption>
|
||||
</figure>
|
||||
|
||||
<p>That is the whole procedure. The server unpacks the zip, puts the sub-modules where they belong, and commits them so the change is part of the instance's history rather than a loose file sitting on a disk somewhere.</p>
|
||||
|
||||
<h2>5. Upload the module: Git</h2>
|
||||
|
||||
<p>For professionals we use Git. Every ODOO instance on our server has its own git repository - one instance, one repo - so your customisations are versioned, reviewable, and portable rather than living in a folder nobody remembers creating.</p>
|
||||
|
||||
<p>Setting it up, in order:</p>
|
||||
|
||||
<ol>
|
||||
<li><strong>Create an SSH key.</strong> On your console, create one if you do not already have one:</li>
|
||||
</ol>
|
||||
|
||||
<p><code>ssh-keygen</code></p>
|
||||
|
||||
<ol start="2">
|
||||
<li><strong>Copy the PUBLIC part of that key</strong> - the public part, never the private one - into your ODOO instance, in the field labelled <strong>SSH Public Key</strong>.</li>
|
||||
<li><strong>Pro tip:</strong> you can add several keys, so you can develop with your team. One key per person, added the same way.</li>
|
||||
<li><strong>Reboot the server to activate the key.</strong> The key does not count until the reboot has happened.</li>
|
||||
<li><strong>Clone the repository to your PC.</strong> Use the clone URL and paste it into your command line, so the git repository gets cloned on your machine.</li>
|
||||
<li><strong>Add your modules and push.</strong> You can install all your custom modules into the <code>custom/</code> folder and push it. Done.</li>
|
||||
</ol>
|
||||
|
||||
<figure>
|
||||
<img src="https://image.office.odoo4projects.com/img/screenshot_git.png" alt="The GIT/MCP tab: Clone URL, Git Pull and Import Module buttons, the SSH public key field with a pasted ssh-ed25519 key, and the warning that key changes take effect after you save and restart the server.">
|
||||
<figcaption>The Git route: your <strong>Clone URL</strong>, the <strong>SSH public key</strong> field, and the reminder that a key change needs a save and a restart.</figcaption>
|
||||
</figure>
|
||||
|
||||
<p>From then on, a module in the repository is a module on the server: push, restart, update the module list, and the new function is there.</p>
|
||||
|
||||
<h2>6. Troubleshooting, and the Update Module List dance</h2>
|
||||
|
||||
<p>When a new module is installed, you need to tell ODOO there is something new. It does not go looking by itself. This is the step people skip, and it is the reason a perfectly installed module "does not work".</p>
|
||||
|
||||
<ol>
|
||||
<li>Go to <strong>Settings</strong>, scroll all the way down, and click on <strong>Activate Developer Mode</strong>.</li>
|
||||
<li>Go to <strong>Apps</strong> and click on the new menu item <strong>Update APP List</strong>.</li>
|
||||
<li>Your new modules should be visible - perhaps you need to delete the filter <strong>APPS</strong> by clicking on the X.</li>
|
||||
</ol>
|
||||
|
||||
<p>That last line is the trap. The Apps screen comes with a filter applied, so a module that is installed, matched to the right version, and sitting exactly where it should be can still be invisible - hidden by a filter, not by a problem. Remove the filter and look again before you conclude anything is wrong.</p>
|
||||
|
||||
<p>If a module is still not there after you have restarted the server <em>and</em> updated the app list: check the version match first, then check whether the zip unpacked into a folder inside a folder. Those two account for most cases, and both are fixed by getting the folder to the right depth - by uploading the zip again through Quick Git, or by pushing the correctly nested folder through Git.</p>
|
||||
|
||||
<h2>7. What this means for the person who owns the business</h2>
|
||||
|
||||
<p>You do not have to enjoy any of this. The point of <a href="../../odoo-hosting-2027.html">running your system as a service</a> is that the boring half - the repository, the keys, the restart, the version match - is somebody else's job. Add a capability when the business needs it, not when a project plan says so: a module goes in, the menu item appears, and your team uses it the same day.</p>
|
||||
|
||||
<p>If a console is not where you want to spend your afternoon, that is not a gap in your abilities. It is a job that should never have been yours in the first place.</p>
|
||||
</div>
|
||||
<a href="../../index.html#blog" class="back-link">← Back to the Blog</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -31,7 +31,7 @@
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
/* Blog post specific overrides — matching homepage light theme */
|
||||
body {
|
||||
@@ -182,8 +182,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="blog-post-container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -211,7 +218,7 @@
|
||||
</ul>
|
||||
<h2>Example: AI-Powered Lead Scoring</h2>
|
||||
<p>
|
||||
Create an n8n workflow that triggers whenever a new lead
|
||||
Create an <a href="../../odoo-n8n-masterclass/">n8n workflow</a> that triggers whenever a new lead
|
||||
is created in Odoo CRM. The workflow sends the lead data
|
||||
to an AI model for scoring and enrichment, then updates
|
||||
the lead record with the results.
|
||||
@@ -229,8 +236,8 @@
|
||||
</div>
|
||||
<h2>Deploy in Minutes</h2>
|
||||
<p>
|
||||
With ODOO4projects, you can deploy n8n alongside your
|
||||
Odoo instance with a single click. No complex networking
|
||||
With ODOO4projects, you can <a href="../../odoo-hosting-2027.html">deploy n8n alongside your
|
||||
Odoo instance</a> with a single click. No complex networking
|
||||
or security configuration needed — everything is
|
||||
pre-configured.
|
||||
</p>
|
||||
@@ -247,5 +254,6 @@
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -36,7 +36,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #714b67;
|
||||
@@ -206,8 +206,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -221,8 +228,8 @@
|
||||
<div class="post-content">
|
||||
<p>
|
||||
One of the most powerful features of Odoo is its modular
|
||||
architecture. With ODOO4projects' On the Rise plan and
|
||||
above, you can install custom modules directly from Git
|
||||
architecture. With ODOO4projects' <a href="../../index.html#pricing">On the Rise plan and
|
||||
above</a>, you can install custom modules directly from Git
|
||||
repositories. Here's how.
|
||||
</p>
|
||||
<h2>Step 1: Connect Your Git Repository</h2>
|
||||
@@ -269,6 +276,7 @@
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -36,7 +36,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #714b67;
|
||||
@@ -206,8 +206,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -228,8 +235,8 @@
|
||||
</p>
|
||||
<h2>Step 1: Choose Your Plan</h2>
|
||||
<p>
|
||||
At ODOO4projects we offer four plans designed to grow
|
||||
with you. If you're just getting started,
|
||||
At ODOO4projects we offer <a href="../../index.html#pricing">four plans designed to grow
|
||||
with you</a>. If you're just getting started,
|
||||
<strong>Side Hustle</strong> gives you a fully
|
||||
functional Odoo CE instance with 1 backup slot and
|
||||
domain mapping. As your needs grow, you can upgrade to
|
||||
@@ -269,7 +276,7 @@ Admin credentials: sent via email</code></pre>
|
||||
<p>
|
||||
With your instance live and your domain mapped, you're
|
||||
ready to install apps, configure users, and customize
|
||||
your workflows. Need help? Our support team is just a
|
||||
your workflows. Need help? Our <a href="../../support.html">support team</a> is just a
|
||||
message away.
|
||||
</p>
|
||||
<div class="cta-box">
|
||||
@@ -288,6 +295,7 @@ Admin credentials: sent via email</code></pre>
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -35,7 +35,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #714b67;
|
||||
@@ -188,8 +188,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -207,7 +214,7 @@
|
||||
</p>
|
||||
<p>
|
||||
This certification reflects our commitment to providing
|
||||
best-in-class hosting infrastructure, expert consulting,
|
||||
best-in-class <a href="../../odoo-hosting-2027.html">hosting infrastructure</a>, expert consulting,
|
||||
and exceptional support for Odoo users worldwide.
|
||||
</p>
|
||||
<h2>What This Means for You</h2>
|
||||
@@ -253,9 +260,10 @@
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script
|
||||
defer
|
||||
src="/static/agent-odoo4projects/agent.js"
|
||||
src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"
|
||||
></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -36,7 +36,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
@@ -189,8 +189,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -210,7 +217,7 @@
|
||||
<p>
|
||||
Your control panel has been completely rebuilt for speed
|
||||
and clarity. Key metrics — instance status,
|
||||
resource usage, backup history — are now front and
|
||||
resource usage, <a href="../../support.html">backup history</a> — are now front and
|
||||
center. The new dashboard loads 3x faster and works
|
||||
seamlessly on mobile.
|
||||
</p>
|
||||
@@ -230,7 +237,7 @@
|
||||
</div>
|
||||
<h2>AI-Powered Monitoring</h2>
|
||||
<p>
|
||||
Our new monitoring system uses machine learning to
|
||||
Our new <a href="../../odoo-hosting-2027.html">monitoring system</a> uses machine learning to
|
||||
detect anomalies in your instance's performance before
|
||||
they become problems. You'll receive proactive alerts
|
||||
with suggested remediation steps.
|
||||
@@ -253,9 +260,10 @@
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script
|
||||
defer
|
||||
src="/static/agent-odoo4projects/agent.js"
|
||||
src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"
|
||||
></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,97 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>ODOO4projects Supports the OCA Paraguay Internationalization Hackathon | ODOO4projects</title>
|
||||
<meta name="description" content="Two online days to push Odoo's Paraguayan localisation forward — and we are supporting them." />
|
||||
<link rel="canonical" href="https://odoo4projects.com/blog/posts/oca-paraguay-internationalization-hackathon.html" />
|
||||
<meta property="og:title" content="ODOO4projects Supports the OCA Paraguay Internationalization Hackathon" />
|
||||
<meta property="og:description" content="Two online days to push Odoo's Paraguayan localisation forward — and we are supporting them." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:image" content="https://image.office.odoo4projects.com/img/py_hackathon.png" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<link rel="icon" href="../../images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
body { background: #0d1b2e; }
|
||||
.blog-post { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem 6rem; color: #171c26; background: #faf7f1; min-height: 100vh; }
|
||||
.blog-post h1 { font-family: 'Marcellus', Georgia, serif; font-size: 2.4rem; font-weight: 400; margin: 0 0 0.5rem; color: #0d1b2e; }
|
||||
.blog-post .post-meta { font-family: Inter, sans-serif; font-size: 0.82rem; color: rgba(23,28,38,0.6); margin-bottom: 2rem; }
|
||||
.blog-post .post-meta .badge { display: inline-block; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.15em; text-transform: uppercase; color: #c9a227; margin-right: 0.75rem; }
|
||||
.blog-post .post-image { width: 100%; border-radius: 0.75rem; margin-bottom: 2rem; box-shadow: 0 2px 8px rgba(13,27,46,0.08); }
|
||||
.blog-post p { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; }
|
||||
.blog-post h2 { font-family: 'Marcellus', Georgia, serif; font-size: 1.6rem; font-weight: 400; margin: 2rem 0 0.75rem; color: #0d1b2e; }
|
||||
.blog-post ul { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; padding-left: 1.5rem; }
|
||||
.blog-post li { margin-bottom: 0.3rem; }
|
||||
.blog-post a { color: #8a6f1f; text-decoration: underline; }
|
||||
.blog-post strong { font-weight: 600; }
|
||||
.back-link { display: inline-block; margin-top: 2rem; font-family: 'Marcellus', Georgia, serif; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.04em; color: #c9a227; text-decoration: none; }
|
||||
.back-link:hover { text-decoration: underline; }
|
||||
@media (max-width: 600px) { .blog-post h1 { font-size: 1.7rem; } .blog-post { padding: 2rem 1rem 4rem; } }
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"headline": "ODOO4projects Supports the OCA Paraguay Internationalization Hackathon",
|
||||
"datePublished": "2026-10-29",
|
||||
"dateModified": "2026-10-29",
|
||||
"url": "https://odoo4projects.com/blog/posts/oca-paraguay-internationalization-hackathon.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/py_hackathon.png",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://odoo4projects.com/images/logo.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="blog-post">
|
||||
<span class="badge">news</span>
|
||||
<h1>ODOO4projects Supports the OCA Paraguay Internationalization Hackathon</h1>
|
||||
<div class="post-meta">October 29, 2026 · News</div>
|
||||
<img src="https://image.office.odoo4projects.com/img/py_hackathon.png" alt="ODOO4projects Supports the OCA Paraguay Internationalization Hackathon" class="post-image" loading="lazy" />
|
||||
<div class="post-body">
|
||||
<p>Two online days to push Odoo's Paraguayan localisation forward — and we are supporting them.</p>
|
||||
|
||||
<p>The OCA Paraguay community is running an <strong>Internationalization Hackathon</strong> on <strong>12 and 14 November 2026</strong>. It is online, it is free, and it is open to every level: you can develop, test, document or translate.</p>
|
||||
|
||||
<h2>What the two days are for</h2>
|
||||
|
||||
<ul>
|
||||
<li><strong>Updating modules to Odoo 19 and 20</strong> — consolidating the 19.0 branch and moving toward the newest versions.</li>
|
||||
<li><strong>New features</strong> the Paraguayan community needs in day-to-day work.</li>
|
||||
<li><strong>Testing and documentation</strong> — coverage and clear guides, so more people adopt Odoo here.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Why we support it</h2>
|
||||
|
||||
<p>Localisation is the part of open source no vendor ships for you: the chart of accounts, the taxes, electronic invoicing, the labels in your own language. It exists because a community maintains it. <a href="../../odoo-hosting-2027.html">We run Odoo Community hosting</a>, so a stronger Paraguayan localisation is our customers' business — and ours.</p>
|
||||
|
||||
<p>Sign up at <strong>oca-py.org</strong>: your name, your GitHub user and how you can contribute. Open to all levels.</p>
|
||||
</div>
|
||||
<a href="../../index.html#blog" class="back-link">← Back to the Blog</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -34,7 +34,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #714b67;
|
||||
@@ -99,8 +99,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -112,7 +119,7 @@
|
||||
alt="This is how i updated my Invoices from Odoo 19 to Odoo 20 with n8n and much MCP"
|
||||
class="post-image" loading="lazy" />
|
||||
<div class="post-content">
|
||||
<p>Copying invoices from one Odoo instance to another by hand is the kind of task that looks small until you are on invoice forty. I moved mine from Odoo 19 to Odoo 20 with an n8n workflow and the ODOO MCP from much ( available at the APP store for free) pointed at the new system, and the setup is simpler than it sounds: the old invoice goes in as context, the tool writes it into the new Odoo, and the agent handles the mapping in between.</p>
|
||||
<p>Copying invoices from one Odoo instance to another by hand is the kind of task that looks small until you are on invoice forty. I moved mine <a href="../../odoo-community-upgrade.html">from Odoo 19 to Odoo 20</a> with an <a href="../../odoo-n8n-masterclass/">n8n workflow</a> and the ODOO MCP from much ( available at the APP store for free) pointed at the new system, and the setup is simpler than it sounds: the old invoice goes in as context, the tool writes it into the new Odoo, and the agent handles the mapping in between.</p>
|
||||
|
||||
<p>What decides whether this works or turns into a mess is not the automation itself. It is the order of operations and the rules you give the agent.</p>
|
||||
|
||||
@@ -167,6 +174,7 @@
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,101 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Odoo 20 Is Live on Our Servers — Here Is What Changed | ODOO4projects</title>
|
||||
<meta name="description" content="Two weeks. That is how long it took us to bring up Odoo 20 on our servers, with every new feature that comes with it. It" />
|
||||
<link rel="canonical" href="https://odoo4projects.com/blog/posts/odoo-20-is-live-on-our-servers-here-is-what-changed.html" />
|
||||
<meta property="og:title" content="Odoo 20 Is Live on Our Servers — Here Is What Changed" />
|
||||
<meta property="og:description" content="Two weeks. That is how long it took us to bring up Odoo 20 on our servers, with every new feature that comes with it. It" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/blog/posts/odoo-20-is-live-on-our-servers-here-is-what-changed.html" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:image" content="https://image.office.odoo4projects.com/img/ODOO_20_chatter.png" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<link rel="icon" href="../../images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
body { background: #0d1b2e; }
|
||||
.blog-post { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem 6rem; color: #171c26; background: #faf7f1; min-height: 100vh; }
|
||||
.blog-post h1 { font-family: 'Marcellus', Georgia, serif; font-size: 2.4rem; font-weight: 400; margin: 0 0 0.5rem; color: #0d1b2e; }
|
||||
.blog-post .post-meta { font-family: Inter, sans-serif; font-size: 0.82rem; color: rgba(23,28,38,0.6); margin-bottom: 2rem; }
|
||||
.blog-post .post-meta .badge { display: inline-block; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.15em; text-transform: uppercase; color: #c9a227; margin-right: 0.75rem; }
|
||||
.blog-post .post-image { width: 100%; border-radius: 0.75rem; margin-bottom: 2rem; box-shadow: 0 2px 8px rgba(13,27,46,0.08); }
|
||||
.blog-post p { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; }
|
||||
.blog-post h2 { font-family: 'Marcellus', Georgia, serif; font-size: 1.6rem; font-weight: 400; margin: 2rem 0 0.75rem; color: #0d1b2e; }
|
||||
.blog-post ul, .blog-post ol { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; padding-left: 1.5rem; }
|
||||
.blog-post li { margin-bottom: 0.3rem; }
|
||||
.blog-post a { color: #8a6f1f; text-decoration: underline; }
|
||||
.blog-post strong { font-weight: 600; }
|
||||
.blog-post figure { margin: 2rem 0; }
|
||||
.blog-post figure img { width: 100%; border-radius: 0.75rem; box-shadow: 0 2px 8px rgba(13,27,46,0.08); }
|
||||
.blog-post figcaption { font-family: Inter, sans-serif; font-size: 0.85rem; line-height: 1.6; color: rgba(23,28,38,0.6); margin-top: 0.6rem; }
|
||||
.back-link { display: inline-block; margin-top: 2rem; font-family: 'Marcellus', Georgia, serif; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.04em; color: #c9a227; text-decoration: none; }
|
||||
.back-link:hover { text-decoration: underline; }
|
||||
@media (max-width: 600px) { .blog-post h1 { font-size: 1.7rem; } .blog-post { padding: 2rem 1rem 4rem; } }
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"headline": "Odoo 20 Is Live on Our Servers — Here Is What Changed",
|
||||
"datePublished": "2026-11-03",
|
||||
"url": "https://odoo4projects.com/blog/posts/odoo-20-is-live-on-our-servers-here-is-what-changed.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/ODOO_20_chatter.png",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://odoo4projects.com/images/logo.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="blog-post">
|
||||
<span class="badge">news</span>
|
||||
<h1>Odoo 20 Is Live on Our Servers — Here Is What Changed</h1>
|
||||
<div class="post-meta">November 3, 2026 · News</div>
|
||||
<img src="https://image.office.odoo4projects.com/img/ODOO_20_chatter.png" alt="Odoo 20 Is Live on Our Servers — Here Is What Changed" class="post-image" loading="lazy" />
|
||||
<div class="post-body">
|
||||
<p>Two weeks. That is how long it took us to bring up <strong>Odoo 20</strong> on our servers, with every new feature that comes with it. It is live now — if your instance runs with us, the engine underneath it just moved forward.</p>
|
||||
|
||||
<p>The version upgrade is only part of the story. Alongside it we shipped a set of changes to the management console, the place where you run your Odoo hosting from inside Odoo itself.</p>
|
||||
|
||||
<h2>What landed</h2>
|
||||
|
||||
<ul>
|
||||
<li><strong>An MCP server</strong> so your agent can work on your hosting directly — restart the server, upload modules, add and check domains, manage backups, read the logfiles.</li>
|
||||
<li><strong>Logfiles you can keep</strong> — download and archive them instead of watching a live view and hoping the right lines are still there.</li>
|
||||
<li><strong>A free backup scheme for everyone</strong> — the least glamorous part of hosting, and the one you miss most when it is gone.</li>
|
||||
<li><strong>A better AI server-management backend</strong> — the layer that connects the agent-facing tools to the hosting underneath.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Why it matters</h2>
|
||||
|
||||
<p>Nothing here asks you to learn a new product. The console stays where it was; the upgrade makes it do more of the routine work for you, and the parts you would rather not think about — backups, logs, restarts — now have a baseline everyone gets.</p>
|
||||
|
||||
<p>Over the next two weeks we take one piece at a time: the MCP server first, then the quieter half — backups and logfiles. Follow along.</p>
|
||||
</div>
|
||||
<a href="../../index.html#blog" class="back-link">← Back to the Blog</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -16,7 +16,7 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
body { background: #0d1b2e; }
|
||||
.blog-post { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem 6rem; color: #171c26; background: #faf7f1; min-height: 100vh; }
|
||||
@@ -60,6 +60,12 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="blog-post">
|
||||
@@ -68,7 +74,7 @@
|
||||
<div class="post-meta">Oct 06, 2026</div>
|
||||
<img src="https://image.office.odoo4projects.com/img/ODOO_20_chatter.png" alt="Odoo 20 Is Live on Our Servers — With an MCP Server and Free Backups" class="post-image" loading="lazy" />
|
||||
<div class="post-body">
|
||||
<p>Two weeks. That is how long it took us to bring up Odoo 20 on our servers, with all of the new features that come with it. It is live now.</p><p>But the version upgrade is not the whole story. Alongside it, we shipped a set of updates to our management console — the place where you manage your Odoo hosting from inside Odoo itself.</p><h2>An MCP Server for Your Agent</h2><p>The biggest addition is an MCP server that lets your agent control your Odoo hosting directly. That means an agent can:</p><ul><li>Restart the server</li><li>Upload modules</li><li>Add and check domains</li><li>Manage your backups</li><li>Read the logfiles</li></ul><p>Instead of clicking through menus to handle routine hosting tasks, you can hand them to an agent and stay focused on your actual work.</p><h2>Logfiles You Can Keep</h2><p>Logfiles can now be downloaded and archived. When something needs investigating, you can pull the logs and hold on to them, rather than scrolling through a live view and hoping the relevant lines are still there by the time you look.</p><h2>Free Backups for Everyone</h2><p>We also added a free backup scheme for every customer. Backups are the least glamorous part of hosting and the one you miss most when they are gone. Having a baseline in place for everyone meaningfully improves data security across the board.</p><h2>Better AI Server Management</h2><p>Finally, we improved our AI server management backend — the layer that connects the agent-facing tools to the underlying hosting infrastructure. It is now more capable and better suited to the way these tools are actually used.</p><h2>What It Adds Up To</h2><p>Odoo 20 running on our servers, a console that manages your Odoo from within Odoo, an MCP server that opens hosting tasks up to your agent, downloadable and archivable logfiles, a free backup scheme, and a stronger AI management backend. All of it is available now.</p><p>Take a look at our homepage and sign up for a trial to see how it works in practice.</p>
|
||||
<p>Two weeks. That is how long it took us to bring up Odoo 20 on our servers, with all of the new features that come with it. It is live now.</p><p>But the version upgrade is not the whole story. Alongside it, we shipped a set of updates to our <a href="../../odoo-hosting-2027.html">management console</a> — the place where you manage your Odoo hosting from inside Odoo itself.</p><h2>An MCP Server for Your Agent</h2><p>The biggest addition is an MCP server that lets your agent control your Odoo hosting directly. That means an agent can:</p><ul><li>Restart the server</li><li>Upload modules</li><li>Add and check domains</li><li>Manage your backups</li><li>Read the logfiles</li></ul><p>Instead of clicking through menus to handle routine hosting tasks, you can hand them to an agent and stay focused on your actual work.</p><h2>Logfiles You Can Keep</h2><p>Logfiles can now be downloaded and archived. When something needs investigating, you can pull the logs and hold on to them, rather than scrolling through a live view and hoping the relevant lines are still there by the time you look.</p><h2>Free Backups for Everyone</h2><p>We also added a free backup scheme for every customer. Backups are the least glamorous part of hosting and the one you miss most when they are gone. Having a baseline in place for everyone meaningfully improves data security across the board.</p><h2>Better AI Server Management</h2><p>Finally, we improved our AI server management backend — the layer that connects the agent-facing tools to the underlying hosting infrastructure. It is now more capable and better suited to the way these tools are actually used.</p><h2>What It Adds Up To</h2><p>Odoo 20 running on our servers, a console that manages your Odoo from within Odoo, an MCP server that opens hosting tasks up to your agent, downloadable and archivable logfiles, a free backup scheme, and a stronger AI management backend. All of it is available now.</p><p>Take a look at our homepage and <a href="../../index.html#pricing">sign up for a trial</a> to see how it works in practice.</p>
|
||||
</div>
|
||||
<a href="../../index.html#blog" class="back-link">← Back to the Blog</a>
|
||||
</main>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
body { background: #0d1b2e; }
|
||||
.blog-post { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem 6rem; color: #171c26; background: #faf7f1; min-height: 100vh; }
|
||||
@@ -58,6 +58,12 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="blog-post">
|
||||
@@ -81,7 +87,7 @@
|
||||
|
||||
<h2>The console gets the attention next</h2>
|
||||
|
||||
<p>We are not done. The next round of work lands in the management console — and the MCP server that lets your agent restart a server, read the logfiles or install a module is only one part of it. If you run an instance day to day, that is the area to watch.</p>
|
||||
<p>We are not done. The next round of work lands in the <a href="../../odoo-hosting-2027.html">management console</a> — and the MCP server that lets your agent restart a server, read the logfiles or install a module is only one part of it. If you run an instance day to day, that is the area to watch.</p>
|
||||
|
||||
<p>Stay tuned: we publish what lands, when it lands.</p>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
/* Blog post specific styles — leverages CSS vars from style.css */
|
||||
:root {
|
||||
@@ -165,8 +165,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container" style="width:80%; max-width:800px; margin:0 auto; padding:0 20px;">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -255,7 +262,7 @@
|
||||
build agentic workflows.
|
||||
</p>
|
||||
<p>
|
||||
Combined with N8N automation workflows and custom
|
||||
Combined with <a href="../../odoo-n8n-masterclass/">N8N automation workflows</a> and custom
|
||||
modules hosted on ODOO4projects, you can create
|
||||
sophisticated pipelines where AI agents coordinate
|
||||
across multiple ODOO apps, external services, and
|
||||
@@ -265,7 +272,7 @@
|
||||
<h2>Why Host with ODOO4projects?</h2>
|
||||
<p>
|
||||
Running AI agents alongside ODOO requires reliable,
|
||||
scalable infrastructure. Our hosting platform offers:
|
||||
scalable infrastructure. Our <a href="../../odoo-hosting-2027.html">hosting platform</a> offers:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
@@ -303,6 +310,7 @@
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -35,7 +35,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
.container {
|
||||
width: 80%;
|
||||
@@ -173,8 +173,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -213,7 +220,7 @@ Odoo > Settings > Technical > Scheduled Actions > backup job</code><
|
||||
screen.
|
||||
</p>
|
||||
<div class="pro-tip">
|
||||
<strong>Pro Tip:</strong> Your plan decides how many
|
||||
<strong>Pro Tip:</strong> Your <a href="../../index.html#pricing">plan</a> decides how many
|
||||
backups you keep. Side Hustle keeps one, On the Rise and
|
||||
Powerhouse keep four. When the slots are full the oldest
|
||||
backup is overwritten and permanently deleted, so before
|
||||
@@ -231,12 +238,18 @@ Odoo > Settings > Technical > Scheduled Actions > backup job</code><
|
||||
>Choose a Plan</a
|
||||
>
|
||||
</div>
|
||||
<p>
|
||||
A backup is the safety net for a single change. When the change is bigger than one
|
||||
module, a version upgrade or a migration, a staging environment is worth it. Read
|
||||
<a href="../../odoo-staging-environment/">what a staging environment is, and why you probably do not need one</a>.
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
<div class="post-footer">
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -35,7 +35,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #714b67;
|
||||
@@ -194,8 +194,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -207,8 +214,8 @@
|
||||
<div class="post-meta">June 2, 2026 · Speed Run</div>
|
||||
<div class="post-content">
|
||||
<p>
|
||||
Ready to see Odoo in action? Deploying your first
|
||||
instance on ODOO4projects takes less time than brewing
|
||||
Ready to see Odoo in action? <a href="../../odoo-hosting-2027.html">Deploying your first
|
||||
instance on ODOO4projects</a> takes less time than brewing
|
||||
your morning coffee. Here's the speed-run.
|
||||
</p>
|
||||
<h2>Step 1: Choose a Plan</h2>
|
||||
@@ -259,6 +266,7 @@ Password: (check your email)</code></pre>
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -34,7 +34,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../style.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #714b67;
|
||||
@@ -99,8 +99,15 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="../../index.html#blog">← Back to Blog</a>
|
||||
@@ -114,11 +121,11 @@
|
||||
<div class="post-content">
|
||||
<p>Every new Odoo release starts the same routine. You install the latest version, open a browser, and begin clicking through your favourite OCA repositories to find out which modules have been ported — and which ones you will have to live without for a while.</p>
|
||||
|
||||
<p>We do the same thing. So we automated it. Our homepage now carries a live table of the OCA modules we rely on most, checked and updated by our robots on a daily basis.</p>
|
||||
<p>We do the same thing. So we automated it. Our <a href="../../index.html#ocaModules">homepage</a> now carries a live table of the OCA modules we rely on most, checked and updated by our robots on a daily basis.</p>
|
||||
|
||||
<h2>Why a tracker is worth having</h2>
|
||||
|
||||
<p>OCA porting work happens at its own pace. Maintainers volunteer their time, and a module that is solid on one version can sit unported on the next for weeks or months. Checking manually means guessing, and guessing during an upgrade project is expensive — you plan around a module that is not ready, or you delay a migration that was actually fine to start.</p>
|
||||
<p>OCA porting work happens at its own pace. Maintainers volunteer their time, and a module that is solid on one version can sit unported on the next for weeks or months. Checking manually means guessing, and guessing during an <a href="../../odoo-community-upgrade.html">upgrade project</a> is expensive — you plan around a module that is not ready, or you delay a migration that was actually fine to start.</p>
|
||||
|
||||
<p>A tracker turns that guesswork into a glance. That is the whole point.</p>
|
||||
|
||||
@@ -157,6 +164,7 @@
|
||||
<a href="../../index.html#blog">← Back to all posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,97 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Your Agent Can Run Your Odoo Hosting: the MCP Server Is Live | ODOO4projects</title>
|
||||
<meta name="description" content="This is the piece of the Odoo 20 update we are asked about most: an MCP server that lets your agent work on your Odoo ho" />
|
||||
<link rel="canonical" href="https://odoo4projects.com/blog/posts/your-agent-can-run-your-odoo-hosting.html" />
|
||||
<meta property="og:title" content="Your Agent Can Run Your Odoo Hosting: the MCP Server Is Live" />
|
||||
<meta property="og:description" content="This is the piece of the Odoo 20 update we are asked about most: an MCP server that lets your agent work on your Odoo ho" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/blog/posts/your-agent-can-run-your-odoo-hosting.html" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:image" content="https://image.office.odoo4projects.com/img/20_4server.png" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<link rel="icon" href="../../images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link rel="stylesheet" href="../../style.css?v=061517baef" />
|
||||
<style>
|
||||
body { background: #0d1b2e; }
|
||||
.blog-post { max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem 6rem; color: #171c26; background: #faf7f1; min-height: 100vh; }
|
||||
.blog-post h1 { font-family: 'Marcellus', Georgia, serif; font-size: 2.4rem; font-weight: 400; margin: 0 0 0.5rem; color: #0d1b2e; }
|
||||
.blog-post .post-meta { font-family: Inter, sans-serif; font-size: 0.82rem; color: rgba(23,28,38,0.6); margin-bottom: 2rem; }
|
||||
.blog-post .post-meta .badge { display: inline-block; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.15em; text-transform: uppercase; color: #c9a227; margin-right: 0.75rem; }
|
||||
.blog-post .post-image { width: 100%; border-radius: 0.75rem; margin-bottom: 2rem; box-shadow: 0 2px 8px rgba(13,27,46,0.08); }
|
||||
.blog-post p { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; }
|
||||
.blog-post h2 { font-family: 'Marcellus', Georgia, serif; font-size: 1.6rem; font-weight: 400; margin: 2rem 0 0.75rem; color: #0d1b2e; }
|
||||
.blog-post ul, .blog-post ol { font-family: Inter, sans-serif; font-size: 1rem; line-height: 1.7; margin-bottom: 1.2rem; padding-left: 1.5rem; }
|
||||
.blog-post li { margin-bottom: 0.3rem; }
|
||||
.blog-post a { color: #8a6f1f; text-decoration: underline; }
|
||||
.blog-post strong { font-weight: 600; }
|
||||
.back-link { display: inline-block; margin-top: 2rem; font-family: 'Marcellus', Georgia, serif; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.04em; color: #c9a227; text-decoration: none; }
|
||||
.back-link:hover { text-decoration: underline; }
|
||||
@media (max-width: 600px) { .blog-post h1 { font-size: 1.7rem; } .blog-post { padding: 2rem 1rem 4rem; } }
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"headline": "Your Agent Can Run Your Odoo Hosting: the MCP Server Is Live",
|
||||
"datePublished": "2026-11-05",
|
||||
"url": "https://odoo4projects.com/blog/posts/your-agent-can-run-your-odoo-hosting.html",
|
||||
"image": "https://image.office.odoo4projects.com/img/20_4server.png",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://odoo4projects.com/images/logo.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="blog-post">
|
||||
<span class="badge">news</span>
|
||||
<h1>Your Agent Can Run Your Odoo Hosting: the MCP Server Is Live</h1>
|
||||
<div class="post-meta">November 5, 2026 · News</div>
|
||||
<img src="https://image.office.odoo4projects.com/img/20_4server.png" alt="Your Agent Can Run Your Odoo Hosting: the MCP Server Is Live" class="post-image" loading="lazy" />
|
||||
<div class="post-body">
|
||||
<p>This is the piece of the Odoo 20 update we are asked about most: an <strong>MCP server</strong> that lets your agent work on your Odoo hosting directly, instead of you clicking through menus to do routine things.</p>
|
||||
|
||||
<h2>What your agent can do</h2>
|
||||
|
||||
<ul>
|
||||
<li><strong>Restart the server</strong> — the task nobody wants to be paged for.</li>
|
||||
<li><strong>Upload modules</strong> — deploy new functionality as part of the same workflow.</li>
|
||||
<li><strong>Add and check domains</strong> — routing handled where the work happens.</li>
|
||||
<li><strong>Manage your backups</strong> — create them, and reinstall one when you need to.</li>
|
||||
<li><strong>Read the logfiles</strong> — investigate a problem without digging through them by hand.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Why we built it this way</h2>
|
||||
|
||||
<p>Hosting chores are short, frequent and interrupt you at the worst moment. Handing them to an agent changes the shape of the day: you stay on the work that moves your project, and the operational tasks happen in the background — under the same account, on the same console you already use.</p>
|
||||
|
||||
<p>The console itself is unchanged. What changed is that the routine half of running an instance no longer needs you in front of it.</p>
|
||||
</div>
|
||||
<a href="../../index.html#blog" class="back-link">← Back to the Blog</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -128,7 +128,9 @@
|
||||
.hero-stats{display:flex;gap:1.5rem;margin-bottom:2rem;flex-wrap:wrap}.hero-stat{display:flex;align-items:center;gap:.4rem;color:rgba(255,255,255,.65);font-size:.85rem}.hero-stat i{color:var(--brass);font-size:.75rem}
|
||||
.hero-actions{display:flex;gap:1rem;flex-wrap:wrap;margin-bottom:2rem}
|
||||
.hero-notice{position:absolute;top:1.25rem;right:1.25rem;z-index:3;display:flex;align-items:center;gap:.55rem;max-width:min(360px,calc(100% - 2rem));padding:.6rem .85rem .6rem 1rem;background:#f5c542;color:var(--midnight);border:1px solid rgba(13,27,46,.14);border-radius:var(--radius);box-shadow:0 8px 24px rgba(13,27,46,.3);font-family:Inter,sans-serif;font-size:.82rem;line-height:1.4;animation:heroNoticeIn .4s cubic-bezier(.16,1,.3,1)}
|
||||
.hero-notice[hidden]{display:none}
|
||||
/* `.hero-notice[hidden]{display:none}` used to live here; the site-wide `[hidden]`
|
||||
rule in /style.css hides it (`.hero-notice` sets `display:flex`, which outranked
|
||||
the UA rule). */
|
||||
.hero-notice i{color:var(--midnight);font-size:.9rem;flex-shrink:0}
|
||||
.hero-notice-text{flex:1;min-width:0;overflow-wrap:anywhere}
|
||||
.hero-notice-close{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:1.35rem;height:1.35rem;padding:0;border:0;border-radius:50%;background:rgba(13,27,46,.12);color:var(--midnight);font-size:1rem;line-height:1;cursor:pointer;transition:background .2s}
|
||||
@@ -220,15 +222,14 @@
|
||||
#customQuoteModal .biz-success p{color:var(--midnight)}
|
||||
@media(max-width:600px){.oca-table td,.oca-table th{padding:.5rem .65rem;font-size:.8rem}.ow-panel{left:5%;right:5%}.ow-close{top:.5rem;right:.5rem;font-size:1.6rem}}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!--
|
||||
@@ -240,6 +241,7 @@
|
||||
FINISH: unreviewed and undocumented is unfinished; this build ends with the finish review, the verdict, and DESIGN.md.
|
||||
-->
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero">
|
||||
<div class="hero-notice" id="heroConfirmNotice" role="status" aria-live="polite" hidden>
|
||||
<i class="fas fa-check-circle" aria-hidden="true"></i>
|
||||
@@ -259,7 +261,7 @@
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a href="#pricing" class="btn btn-brass">Pläne & Preise ansehen →</a>
|
||||
<a href="/support.html" class="btn btn-outline">So funktioniert es</a>
|
||||
<a href="/de/support.html" class="btn btn-outline">So funktioniert es</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -362,32 +364,32 @@
|
||||
<div class="container">
|
||||
<h2 class="section-title">Häufige Fragen</h2>
|
||||
<div class="faq-grid">
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Was, wenn mein Plan nicht mehr ausreicht?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Wachsen Sie von Side Hustle bis Empire — ohne Datenmigration und ohne Ausfallzeit. Upgraden Sie direkt in den Odoo-Einstellungen: Ihre Instanz bleibt aktiv, Ihre Daten kommen mit.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Kann ich es anpassen?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Ja. On the Rise und höher unterstützen Git-basierte Module. Installieren Sie eigene Anwendungen, entwickeln Sie selbst oder nutzen Sie Quick GIT für die Installation mit einem Klick.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Wie schnell kann ich loslegen?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>In fünf Minuten. Plan wählen, Region auswählen — Ihre Odoo-Instanz läuft. Keine Einrichtungsgebühr. Zahlung über Stripe. Jederzeit kündbar.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Kann ich Odoo Enterprise betreiben?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Powerhouse und Empire sind Enterprise-bereit. Bringen Sie Ihre Lizenz mit — die Infrastruktur stellen wir.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Was kann Odoo Community?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Lager, Buchhaltung, CRM, Vertrieb, Fertigung, Personal — alles in einem System. Kostenlos und vollständig Open Source.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Gibt es ein Partnerprogramm?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Nein. Wettbewerbsfähige Preise für unsere gemeinsamen Kunden liegen in unserem eigenen Interesse.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="/support.html" class="faq-link">Alle Fragen →</a>
|
||||
<a href="/de/support.html" class="faq-link">Alle Fragen →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -416,7 +418,7 @@
|
||||
<small class="price-period">/ Jahr</small>
|
||||
</div>
|
||||
<p class="desc">"ODOO Standard .. das ist alles, was mein Unternehmen braucht"</p>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy" data-id="6">Jetzt kaufen</a>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="6">Jetzt kaufen</a>
|
||||
<ul>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Odoo CE in 5 Minuten starten</li>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Automatische Backups — kein Merken nötig</li>
|
||||
@@ -434,7 +436,7 @@
|
||||
<small class="price-period">/ Jahr</small>
|
||||
</div>
|
||||
<p class="desc">"Ich brauche ein paar Module und professionelle Berichte"</p>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy" data-id="4">Jetzt kaufen</a>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="4">Jetzt kaufen</a>
|
||||
<ul>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Odoo CE in 5 Minuten starten</li>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Automatische Backups — kein Merken nötig</li>
|
||||
@@ -453,7 +455,7 @@
|
||||
<small class="price-period">/ Jahr</small>
|
||||
</div>
|
||||
<p class="desc">"ODOO Enterprise ist ein Muss!"</p>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy" data-id="5">Jetzt kaufen</a>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="5">Jetzt kaufen</a>
|
||||
<ul>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Odoo CE in 5 Minuten starten</li>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Automatische Backups — kein Merken nötig</li>
|
||||
@@ -484,7 +486,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<p class="pricing-cta-note">Geld sparen, weniger Verwaltung</p>
|
||||
<p class="pricing-cta-note"><a href="/odoo-hosting-2027.html"><strong>Alle Wege vergleichen, Odoo 2027 zu hosten →</strong></a></p>
|
||||
<p class="pricing-cta-note"><a href="/de/odoo-hosting-2027.html"><strong>Alle Wege vergleichen, Odoo 2027 zu hosten →</strong></a></p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -496,7 +498,7 @@
|
||||
<h2 class="ow-title" id="orderPlanTitle">On the Rise</h2>
|
||||
<p class="ow-price">
|
||||
<span class="ow-price-amount" id="orderPlanPrice">$ 395.00</span> <span id="orderPlanPeriod">/ Jahr</span>
|
||||
<span class="ow-price-tax" id="orderPlanTax">+ MwSt.</span>
|
||||
<span class="ow-price-tax" id="orderPlanTax">inkl. MwSt.</span>
|
||||
</p>
|
||||
<p class="ow-coupon-msg" id="orderCouponMsg">Fragen vor dem Kauf? Fragen Sie den Assistenten auf dieser Seite.</p>
|
||||
<p class="ow-yearly-save" id="orderYearlySave">Jährliche Abrechnung. Keine Einrichtungsgebühr.</p>
|
||||
@@ -509,7 +511,7 @@
|
||||
<option value="Netherlands">Niederlande (Amsterdam)</option>
|
||||
<option value="UK">Vereinigtes Königreich (London)</option>
|
||||
</select>
|
||||
<a id="orderBuyBtn" href="/support.html#contact" class="btn btn-brass ow-buy">Weiter zu Stripe →</a>
|
||||
<a id="orderBuyBtn" href="/de/support.html#contact" class="btn btn-brass ow-buy">Weiter zu Stripe →</a>
|
||||
<p class="ow-note">🔒 Sichere Stripe-Zahlung · Karte für den Kauf erforderlich, nicht für den Start.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -625,13 +627,14 @@
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Nützliche Links</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/de/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/de/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/de/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Rechtliches</a></li>
|
||||
@@ -671,7 +674,7 @@
|
||||
</footer>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
|
||||
<script src="/script.js"></script>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
<script src="/script.js?v=d2046e3469"></script>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,888 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Odoo Community Upgrade — für Sie übernommen | ODOO4projects</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Ein Odoo Community Upgrade erklärt: Was sich ändert, was bricht, die konkreten Befehle und wie wir Ihre Datenbank auf unsere Server migrieren."
|
||||
/>
|
||||
<link rel="canonical" href="https://odoo4projects.com/de/odoo-community-upgrade.html" />
|
||||
<link rel="alternate" hreflang="en-US" href="https://odoo4projects.com/odoo-community-upgrade.html" />
|
||||
<link rel="alternate" hreflang="de" href="https://odoo4projects.com/de/odoo-community-upgrade.html" />
|
||||
<link rel="alternate" hreflang="es" href="https://odoo4projects.com/es/odoo-community-upgrade.html" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://odoo4projects.com/odoo-community-upgrade.html" />
|
||||
<meta property="og:title" content="Odoo Community Upgrade — für Sie übernommen" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Was sich bei einem Odoo Community Upgrade ändert, die konkreten Befehle für Entwickler und wie wir Ihre Datenbank auf unsere Server migrieren."
|
||||
/>
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/de/odoo-community-upgrade.html" />
|
||||
<meta property="og:image" content="https://odoo4projects.com/images/hero/amsterdam.webp" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Odoo Community Upgrade — für Sie übernommen" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Was sich bei einem Odoo Community Upgrade ändert, die konkreten Befehle für Entwickler und wie wir Ihre Datenbank auf unsere Server migrieren."
|
||||
/>
|
||||
<meta name="twitter:image" content="https://odoo4projects.com/images/hero/amsterdam.webp" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- Odoo Community Upgrade page (page-scoped; additive) ---- */
|
||||
.oc-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Top bar (page-scoped: the site has no global header) */
|
||||
.cmp-topbar {
|
||||
background: var(--midnight-2);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.85rem 0;
|
||||
}
|
||||
.cmp-topbar .container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.cmp-brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
}
|
||||
.cmp-brand span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar-links {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
font-size: 0.82rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
.cmp-topbar-links a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar-links a:hover {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar .lang-switch-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.45);
|
||||
}
|
||||
.cmp-topbar .lang-switch {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar .lang-switch a:hover,
|
||||
.cmp-topbar .lang-switch a:focus-visible {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.cmp-topbar .lang-switch a[aria-current="true"] {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* Hero — the same midnight lounge as the rest of the site, with our own
|
||||
Amsterdam photo behind the copy. */
|
||||
.oc-hero {
|
||||
min-height: 0;
|
||||
padding: 3.5rem 0 3rem;
|
||||
}
|
||||
.oc-hero .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.oc-hero h1 span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.oc-hero .hero-sub {
|
||||
max-width: 700px;
|
||||
}
|
||||
.oc-hero-img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
opacity: 0.25;
|
||||
filter: brightness(1.15) saturate(1.1);
|
||||
}
|
||||
|
||||
.oc-body {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.75;
|
||||
}
|
||||
.section-dark .oc-body {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.oc-body p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oc-body strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-dark .oc-body strong {
|
||||
color: #fff;
|
||||
}
|
||||
.oc-pull {
|
||||
max-width: 760px;
|
||||
margin: 2rem auto 0;
|
||||
padding-top: 1.25rem;
|
||||
border-top: 1px solid var(--line-brass);
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.05rem;
|
||||
color: var(--ink);
|
||||
text-align: center;
|
||||
}
|
||||
.section-dark .oc-pull {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
|
||||
/* Numbered process list */
|
||||
.oc-steps {
|
||||
max-width: 820px;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
counter-reset: oc-step;
|
||||
}
|
||||
.oc-steps li {
|
||||
position: relative;
|
||||
counter-increment: oc-step;
|
||||
padding: 0 0 1.4rem 3.2rem;
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
line-height: 1.7;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.25);
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.oc-steps li::before {
|
||||
content: counter(oc-step);
|
||||
position: absolute;
|
||||
left: -1.05rem;
|
||||
top: -0.15rem;
|
||||
width: 2.1rem;
|
||||
height: 2.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1rem;
|
||||
color: var(--midnight);
|
||||
background: var(--brass);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.oc-steps li strong {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.oc-steps li:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* Technical section: code cards + substitution notes */
|
||||
.oc-code {
|
||||
background: var(--midnight);
|
||||
border: 1px solid var(--line-brass);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1rem 1.15rem;
|
||||
margin: 1.1rem 0 0;
|
||||
overflow-x: auto;
|
||||
box-shadow: var(--shadow-rest);
|
||||
}
|
||||
.section-dark .oc-code {
|
||||
background: var(--midnight-2);
|
||||
}
|
||||
/* R1 moved the process list onto a light band and the technical section onto a
|
||||
dark one, so their text colours have to follow the band, not their old parent. */
|
||||
.section-light .oc-steps li {
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
.section-light .oc-steps li strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-dark .oc-sub h3 {
|
||||
color: var(--cream);
|
||||
}
|
||||
.section-dark .oc-sub > p,
|
||||
.section-dark .oc-note {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.section-dark .oc-note strong {
|
||||
color: #fff;
|
||||
}
|
||||
/* R3 puts the "See the plans" link inside the dark offer band. */
|
||||
.section-dark .oc-body a {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.oc-code code {
|
||||
display: block;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.7;
|
||||
color: #ece6da;
|
||||
white-space: pre;
|
||||
tab-size: 2;
|
||||
}
|
||||
.oc-note {
|
||||
margin: 0.9rem 0 0;
|
||||
padding: 0.15rem 0 0.15rem 1rem;
|
||||
border-left: 2px solid var(--brass);
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
}
|
||||
.oc-note p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oc-sub {
|
||||
margin-top: 2.25rem;
|
||||
}
|
||||
.oc-sub h3 {
|
||||
color: var(--ink);
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
.oc-sub > p {
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
/* FAQ */
|
||||
.cmp-faq-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cmp-faq {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.4rem 1.25rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
transition: box-shadow 0.25s;
|
||||
}
|
||||
.cmp-faq[open],
|
||||
.cmp-faq:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
.cmp-faq summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.85rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.98rem;
|
||||
color: var(--midnight);
|
||||
}
|
||||
.cmp-faq summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.cmp-faq summary::after {
|
||||
content: "+";
|
||||
font-family: Inter, sans-serif;
|
||||
color: var(--brass);
|
||||
font-size: 1.15rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
.cmp-faq[open] summary::after {
|
||||
content: "\2212";
|
||||
}
|
||||
.cmp-faq summary:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.cmp-faq .cmp-a {
|
||||
font-size: 0.87rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.cmp-faq .cmp-a p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.cmp-faq-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Final CTA band */
|
||||
.cmp-cta {
|
||||
text-align: center;
|
||||
}
|
||||
.cmp-cta .oc-lead {
|
||||
font-size: 1.1rem;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
max-width: 700px;
|
||||
margin: 0 auto 1.5rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
.cmp-cta-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.cmp-cta-actions .btn {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/* Focus states on every CTA */
|
||||
.btn:focus-visible,
|
||||
.cmp-topbar-links a:focus-visible {
|
||||
outline: 3px solid var(--brass-bright);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.btn-brass:focus-visible {
|
||||
outline-color: #fff;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.oc-hero {
|
||||
padding: 3rem 0 2.5rem;
|
||||
}
|
||||
.oc-steps li {
|
||||
padding-left: 2.6rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "WebPage",
|
||||
"@id": "https://odoo4projects.com/odoo-community-upgrade.html#webpage",
|
||||
"url": "https://odoo4projects.com/odoo-community-upgrade.html",
|
||||
"name": "Odoo Community Upgrade — für Sie übernommen",
|
||||
"description": "Ein Odoo Community Upgrade erklärt: Was sich ändert, was bricht, die konkreten Befehle und wie wir Ihre Datenbank auf unsere Server migrieren.",
|
||||
"inLanguage": "de",
|
||||
"isPartOf": { "@id": "https://odoo4projects.com/#organization" }
|
||||
},
|
||||
{
|
||||
"@type": "Service",
|
||||
"name": "Migration der Odoo-Community-Datenbank auf das Hosting von ODOO4projects",
|
||||
"provider": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"url": "https://odoo4projects.com/odoo-community-upgrade.html"
|
||||
},
|
||||
{
|
||||
"@type": "FAQPage",
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Ist ein Upgrade dasselbe wie ein Update?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Nein. Ein Update bringt Ihnen die neueste Fassung der Software, die Sie bereits einsetzen. Ein Upgrade bringt Ihre Datenbank auf eine neue Hauptversion (18 auf 19 oder 19 auf 20) und wandelt die Daten selbst um. Es geht nur in eine Richtung: einen unterstützten Weg zurück gibt es nicht, und es ist keine Lizenzänderung, kein Editionswechsel und kein Hosting-Wechsel."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Können wir direkt von Odoo 14 auf Odoo 20 upgraden?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Nein. Es geht immer nur eine Hauptversion auf einmal: 14 auf 15 auf 16 auf 17 auf 18 auf 19 auf 20. Eine Version zu überspringen ist kein unterstützter Weg. Unser eigener Migrationsservice dokumentiert Unterstützung für Datenbanken auf Odoo 17, 18 und 19, nur Hauptreleases, keine Patch-Releases; ältere Datenbanken brauchen zuerst eine Kompatibilitätsprüfung, die mit einem Support-Ticket beginnt."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Was passiert mit meiner Historie: Rechnungen, Zahlungen, Anhänge?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Das ist die richtige Frage, und die ehrliche Antwort lautet: Es hängt vom Weg ab. Der OpenUpgrade-Weg — eine Versionsmigration auf Ihrem eigenen Server — nimmt die Datenbank mit und erhält die Historie und die Verknüpfungen zwischen den Datensätzen. Die OpenUpgrade-Dokumentation warnt, dass der andere Weg, Dokumente in ein neues System zu verschieben, nur einen Teil Ihrer Daten rettet und die Historie und die Verknüpfungen zwischen den Datensätzen verliert, zum Beispiel die Rechnungen je Kunde. Unser Service baut Ihnen eine neue Datenbank und bringt Ihre Daten hinein; unser Weg ist also der, nach dem Sie fragen sollten: Bitten Sie uns vor Ihrer Freigabe, genau aufzulisten, welche Datensätze in der neuen Datenbank sein werden und welche nicht. Wir möchten lieber, dass Sie sie stellen, als dass Sie sie annehmen."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Funktionieren meine individuellen Module weiterhin?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Nicht von allein. Ein Modul, das für Ihr Geschäft geschrieben wurde, braucht seinen Code auf der Zielversion, und Umbenennungen, die sonst Daten kosten würden, brauchen eigene Migrationsskripte. Die Odoo-Dokumentation ist hier deutlich: Ein Upgrade ist blockiert, bis es eine Version Ihrer individuellen Module für die Zielversion gibt. Module, die mit Odoo ausgeliefert werden, und Module der Community-Vereinigung bringen ihre eigenen Migrationsskripte mit; Ihre nicht, und die muss jemand schreiben."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Was kostet es, und wie lange dauert es?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Für den Upgrade-Service veröffentlichen wir weder Preis noch Dauer, und wir erfinden hier auch keine. Was wir veröffentlichen, ist der Anfang: Sie eröffnen ein Support-Ticket, wir prüfen Ihre Datenbank auf Kompatibilität und melden uns bei Ihnen. Wenn Sie es gegen die Eigenleistung abwägen, ist der ehrliche Vergleich nicht die Servermiete, sondern Ihre eigenen Stunden, die auf keiner Rechnung auftauchen."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Brauche ich einen Entwickler?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Um die Befehle im technischen Abschnitt auszuführen, ja; oder jemanden, der sich im Terminal mit PostgreSQL auskennt. Damit wir es übernehmen, nein: Genau das ist der Sinn des Service. Sie senden die Datenbank, wir bauen das neue System auf unserer Infrastruktur, und Sie erhalten die Zugangsdaten."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Kann ich das System mit der neuen Version ansehen, bevor es live geht?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Ja, und das sollten Sie. Wer die Arbeit macht, migriert zuerst eine Kopie; das ist die erste Regel des ganzen Prozesses, in der Odoo-Dokumentation wie im OpenUpgrade-Projekt. Und die migrierte Kopie ist das, was Sie prüfen, bevor mit dem System, auf dem Ihr Geschäft läuft, irgendetwas passiert. Unser Service folgt demselben Prinzip: Wir bauen das neue System auf unseren eigenen Servern, und Sie vergleichen es mit dem alten."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Wir sind woanders gehostet. Können Sie uns trotzdem upgraden?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Ja, genau dafür ist unser Migrationsservice da. Sie eröffnen ein Support-Ticket, wir senden Ihnen ein sicheres Formular zum Hochladen Ihrer Datenbank, richten Ihnen einen neuen Server auf unserer Infrastruktur ein und stellen die Zugangsdaten bereit. Datenbanken auf Odoo 17, 18 und 19, nur Hauptreleases; ältere nach einer Kompatibilitätsprüfung."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="cmp-topbar">
|
||||
<div class="container">
|
||||
<a class="cmp-brand" href="/de/">ODOO4<span>projects</span></a>
|
||||
<nav class="cmp-topbar-links" aria-label="Seitenlinks">
|
||||
<a href="/de/#pricing">Tarife & Preise</a>
|
||||
<a href="/de/support.html">Support</a>
|
||||
</nav>
|
||||
<div data-lang-switcher class="lang-switch-slot"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero oc-hero">
|
||||
<div class="hero-bg">
|
||||
<img
|
||||
class="oc-hero-img"
|
||||
src="/images/hero/amsterdam.webp"
|
||||
alt="Amsterdam in der Abenddämmerung — eine der sechs Regionen, in denen unsere Server laufen"
|
||||
width="1920"
|
||||
height="768"
|
||||
fetchpriority="high"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="container">
|
||||
<p class="hero-kicker">ODOO COMMUNITY UPGRADE</p>
|
||||
<h1><span>Odoo Community Upgrade</span>: Was sich ändert und wie wir es für Sie übernehmen</h1>
|
||||
<p class="hero-sub">
|
||||
Der Sprung auf eine neue Odoo-Hauptversion ist kein Update: Er ist eine Umwandlung Ihrer Datenbank in nur eine Richtung, und nichts, was Sie falsch machen wollen. Hier steht, wie wir das für Sie übernehmen — ein neues System auf unseren eigenen Servern, Ihr bestehendes bleibt unberührt, während wir arbeiten — und darunter die konkreten Befehle, die ein Entwickler ausführen würde.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="/de/support.html#contact" class="btn btn-brass btn-lg">Ticket eröffnen: Sagen Sie uns, welche Version Sie nutzen</a>
|
||||
<a href="/de/#pricing" class="btn btn-outline btn-lg">Tarife ansehen</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What an upgrade is -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Der Unterschied, auf den es ankommt</p>
|
||||
<h2 class="section-title">Was ein Odoo Community Upgrade wirklich ist</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Odoo benutzt zwei Wörter, die gleich klingen und es nicht sind. Ein <strong>Update</strong> bringt Ihnen die neueste Fassung der Software, die Sie bereits einsetzen. Ein <strong>Upgrade</strong> bringt Ihre Datenbank auf eine neue Hauptversion (18 auf 19 oder 19 auf 20) und wandelt die Daten selbst um. Es geht nur in eine Richtung: einen unterstützten Weg zurück gibt es nicht, und es ist keine Lizenzänderung, kein Wechsel der Edition und kein Wechsel des Hosting-Anbieters.
|
||||
</p>
|
||||
<p>Drei Dinge sollten Sie wissen, bevor jemand Ihr System anfasst.</p>
|
||||
<p>
|
||||
<strong>Es geht immer nur eine Hauptversion auf einmal.</strong> Ein Sprung von 17 auf 20 sind drei Migrationen, nicht eine: 17 → 18, 18 → 19, 19 → 20. Eine Version zu überspringen ist im gesamten Odoo-Ökosystem kein unterstützter Weg.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Er wird an einer Kopie gemacht, nie an der laufenden Datenbank.</strong> Alle, die darüber geschrieben haben (die eigene Dokumentation von Odoo, das OpenUpgrade-Projekt der OCA und jeder Praktiker, den wir gesehen haben), beginnen mit einem Backup und arbeiten an einer Zweitkopie. Sie erfahren, was kaputtgegangen ist, an der Kopie und nicht vor Ihren Kunden.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Ihre eigenen Anpassungen sind der Teil, der Arbeit macht.</strong> Ein Modul, das für Ihr Geschäft gebaut wurde, zieht nicht von selbst mit: Sein Code muss auf die Zielversion gebracht werden, und Umbenennungen, die sonst Daten kosten würden, brauchen eigene Migrationsskripte. Die Odoo-Dokumentation sagt es unverblümt: Ein Upgrade ist blockiert, bis es Ihre individuellen Module für die Zielversion gibt.
|
||||
</p>
|
||||
<p>
|
||||
Und dann der Weg selbst. Odoo verkauft einen Upgrade-Pfad für Enterprise; für Odoo Community ist die Open-Source-Antwort das OpenUpgrade-Projekt der OCA. Die OpenUpgrade-Dokumentation stellt fest, dass die Odoo Community Edition Migrationen zwischen Hauptversionen nicht unterstützt, und hält fest, dass OpenUpgrade die Lösung ist, die der Gründer von Odoo selbst dafür empfiehlt. Es ist ein echtes Projekt, gepflegt von der Community-Vereinigung, und es ist der Weg, den ein Entwickler auf einer Community-Datenbank nutzt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Our way -->
|
||||
<section class="section-dark" id="our-way">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Der Weg von ODOO4projects</p>
|
||||
<h2 class="section-title">Der Weg von ODOO4projects: eine neue Datenbank, und wir erledigen die Arbeit</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Nichts davon müssen Sie selbst tun. Wenn Ihr Geschäft auf Odoo Community läuft und Sie die Version wechseln wollen, ohne jemanden einzustellen, der die Reihenfolge auf dieser Seite abarbeitet, machen wir stattdessen Folgendes.
|
||||
</p>
|
||||
<p>
|
||||
Sie eröffnen ein Support-Ticket und sagen uns, was Sie haben. Wir sehen uns zuerst Ihre Datenbank an (ihre Version, ihre Anpassungen, ob wir sie überhaupt bewegen können) und sagen Ihnen, was wir finden. Dann senden wir Ihnen einen Link zu einem sicheren Formular, über das Sie Ihre Datenbank hochladen. Sobald wir sie haben, richten wir Ihnen einen neuen Server auf unserer eigenen Infrastruktur ein und übergeben Ihnen die Zugangsdaten. Ihr bestehendes System läuft die ganze Zeit weiter, weil wir es nicht anfassen: Wir arbeiten an der Datenbank, die Sie uns gesendet haben, und an dem neuen Server, den wir gebaut haben.
|
||||
</p>
|
||||
<p>
|
||||
Wenn Sie lieber erst eine Zahl sehen möchten: Welchen Tarif Sie brauchen, hängt von den Modulen ab, die Sie nutzen, und die Tarife finden Sie hier — <a href="/de/#pricing">Tarife ansehen</a>. Das Upgrade selbst ist auf dieser Seite nicht bepreist; wir melden uns bei Ihnen, nachdem wir Ihre Datenbank angesehen haben.
|
||||
</p>
|
||||
<p>
|
||||
Genau dieser letzte Punkt ist der ganze Grund für diesen Weg. Bei unserem Service migrieren Sie nicht abends nach Ladenschluss Ihre laufende Datenbank. Sie sehen sich ein zweites System an, in einer neuen Version, mit Ihren Daten darin, und können beide vergleichen, bevor Sie irgendetwas entscheiden.
|
||||
</p>
|
||||
<p>
|
||||
Unser Migrationsservice dokumentiert Unterstützung für Datenbanken auf Odoo 17, 18 und 19, nur Hauptreleases; Patch-Releases wie 18.1 oder 17.2 werden nirgends in unserem Service unterstützt. Ist Ihre Datenbank älter als 17, helfen wir Ihnen trotzdem, sie auf ein unterstütztes Release zu bringen, aber erst nach einer Prüfung auf Kompatibilität. Neue Instanzen auf unseren Servern können auf Odoo 19 oder Odoo 20 angelegt werden. Wenn Sie gezielt auf 20 wollen, sagen Sie es im Ticket: Die Version, zu der Sie gehen, zählt mehr als die, auf der Sie sind.
|
||||
</p>
|
||||
<p>
|
||||
Auf der KI-Seite ist hier ein Fall, den wir tatsächlich veröffentlicht haben. Rechnungen von Hand von einer Odoo-Instanz in eine andere zu kopieren ist langsam und leicht falsch, also haben wir es stattdessen mit einem Workflow gemacht: Datensätze aus einem Odoo-19-System in ein neues Odoo-20-System geschrieben, angetrieben von einem Automatisierungs-Workflow und einem MCP-Server, der auf das neue System zeigt. Drei Regeln machten es sicher (Rechnungsnummer und Datum ändern sich nie, der Kontakt wird nachgeschlagen statt geraten, das Produkt wird nachgeschlagen statt geraten) und eine harte Vorgabe: Fehlt ein Kontakt oder ein Produkt, bricht der Lauf laut ab, statt einen Fast-Doppelgänger anzulegen. Bevor wir es auf den Rest losließen, haben wir eine Rechnung von Anfang bis Ende geprüft: Nummer, Datum, Kontakt, Positionen.
|
||||
</p>
|
||||
<p>
|
||||
Eines verwischen wir nicht, denn es ist der Unterschied zwischen uns und einem Verkäufer. Der MCP-Server, den wir in unserer eigenen Verwaltungskonsole mitliefern, macht Hosting-Operationen. Er startet einen Server neu, lädt ein Modul hoch, fügt eine Domain hinzu oder prüft sie, verwaltet Backups und liest eine Logdatei; das ist die veröffentlichte Liste, und sie ist eine echte Erleichterung, wenn Sie einen KI-Assistenten nutzen. Er ist keine Datenmigrations-Engine, und wir beschreiben ihn auch nicht als eine. Die Importarbeit oben wurde mit einem Automatisierungs-Workflow und einem MCP von Drittanbietern erledigt; die KI machte den mühsamen Teil und wurde von einem Menschen geprüft, genau wie es sein soll.
|
||||
</p>
|
||||
<p>
|
||||
Und die ehrliche Grenze, in den Worten des Projekts, das sich damit am besten auskennt. Die OpenUpgrade-Dokumentation nennt die Export-und-Import-Alternative und benennt ihren Preis klar: Sie retten nur einen Teil Ihrer Daten, und insbesondere erhalten Sie nicht die Historie und die Verknüpfungen zwischen den Datensätzen, zum Beispiel die Rechnungen je Kunde. Das ist das Risiko jedes Weges, der Dokumente in ein neues System verschiebt, und deshalb stellen Sie uns, wenn Sie diesen Weg mit uns gehen, vor Ihrer Freigabe eine Frage: Welche Datensätze werden in der neuen Datenbank sein und welche nicht? Wir möchten lieber, dass Sie sie stellen, als dass Sie sie annehmen.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Process -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Der dokumentierte Weg</p>
|
||||
<h2 class="section-title">Der Upgrade-Prozess, Schritt für Schritt</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Das ist die Reihenfolge, auf die sich die Odoo-Dokumentation, das OpenUpgrade-Projekt und die aufgezeichneten Workshops einig sind. Nichts davon ist unseres und nichts davon ist geheim: Es ist der dokumentierte Weg, in der Reihenfolge, in der er gegangen wird.
|
||||
</p>
|
||||
</div>
|
||||
<ol class="oc-steps">
|
||||
<li>
|
||||
<strong>Sichern Sie die Datenbank und wissen Sie, wo der Filestore liegt.</strong> Vor allem anderen. Die Dokumentation des OpenUpgrade-Projekts sagt, dass Sie unbedingt ein Backup der laufenden Datenbank machen müssen, und jeder Praktiker macht das zuerst.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Arbeiten Sie an einer Kopie.</strong> Spielen Sie das Backup in eine Testdatenbank ein und migrieren Sie diese. Ihr laufendes System bleibt unberührt, bis die Kopie funktioniert.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Richten Sie zuerst die Zielversion ein.</strong> Installieren Sie das neuere Odoo und legen Sie den OpenUpgrade-Code für die Zielversion in dessen Add-ons-Pfad, neben die Module, die Sie bereits nutzen.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Portieren Sie Ihre individuellen Module.</strong> Bringen Sie ihren Code auf die neue Version, bevor die Migration läuft.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Führen Sie die Migration an der Kopie aus.</strong> Ein Modul nach dem anderen, in Abhängigkeitsreihenfolge; jedes führt erst sein Pre-Skript aus, dann lädt es, dann sein Post-Skript.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Rechnen Sie damit, sie mehr als einmal auszuführen.</strong> Das ist iterativ. Im aufgezeichneten Workshop ist die Umgebung (Repositories, Branches, die Modulliste) der Teil, der Zeit kostet; der Migrationslauf selbst ist schnell, sobald die Umgebung steht. Sie setzen zurück und laufen erneut, bis das Log sauber ist.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Schließen Sie mit einem einfachen Update ab.</strong> Das Update noch einmal ohne die Migrationsparameter auszuführen, hebt den Zustand „inkompatibel“ auf und lässt die Datenbank nutzbar zurück.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Testen Sie anhand der Daten, nicht anhand der Versionsnummer.</strong> Öffnen Sie die migrierte Kopie und prüfen Sie, was zählt: einen Kunden, ein Produkt, einen Auftrag, eine Rechnung, eine Zahlung. So überprüfen die Praktiker es am Bildschirm.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Räumen Sie danach auf.</strong> Veraltete Tabellen, Spalten und Views, die eine Migration zurücklässt, kosten Leistung; deshalb werden sie entfernt, wenn das System eine Zeit lang läuft und niemand ein Problem gemeldet hat.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Dann geht es in den Produktivbetrieb.</strong> Spielen Sie die migrierte Datenbank dort ein, wo sie hingehört, oder lassen Sie das Upgrade zu einem Zeitpunkt Ihrer Wahl auf der Produktivdatenbank laufen.
|
||||
</li>
|
||||
</ol>
|
||||
<p class="oc-pull">
|
||||
So sieht es ehrlich aus: Die Vorbereitung ist der lange Teil, die Migration selbst der kurze, und die Kopie ist das, was Sie kaputtmachen dürfen.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Technical section -->
|
||||
<section class="section-dark" id="commands">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Für Ihre Entwickler</p>
|
||||
<h2 class="section-title">Für Ihre Entwickler: die konkreten Befehle</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Wenn Sie Odoo Community selbst betreiben und das lieber im Haus erledigen möchten, statt es uns zu überlassen, sind das die Befehle. Sie sind aus der jeweiligen Dokumentation übernommen, und bei jedem steht, was Sie einsetzen müssen und wovor die Quelle warnt. Nichts davon haben wir gegen Ihre Datenbank ausgeführt, und kein von uns veröffentlichter Befehl läuft auf unseren eigenen Servern: Unser Service beginnt mit einem Support-Ticket, nicht mit einem Terminal.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="oc-sub">
|
||||
<h3>Odoos Upgrade-Plattform</h3>
|
||||
<p>
|
||||
Odoo dokumentiert eine Upgrade-Plattform, die für On-Premise-Installationen über die Kommandozeile funktioniert. Die Odoo-Dokumentation stellt fest, dass die Migrationsskripte, die sie ausführt, nicht Open Source sind und zu Enterprise gehören; die Plattform selbst aber bringt eine selbst gehostete Datenbank auf die neue Version.
|
||||
</p>
|
||||
<pre class="oc-code"><code># upgraded TEST database
|
||||
python <(curl -s https://upgrade.odoo.com/upgrade) test -d <your db name> -t <target version>
|
||||
|
||||
# production upgrade
|
||||
python <(curl -s https://upgrade.odoo.com/upgrade) production -d <your db name> -t <target version>
|
||||
|
||||
# general help
|
||||
python <(curl -s https://upgrade.odoo.com/upgrade) --help</code></pre>
|
||||
<div class="oc-note">
|
||||
<p>
|
||||
<strong>Ersetzen:</strong> <code><your db name></code> ist die Datenbank auf der Maschine, auf der Sie den Befehl ausführen, und <code><target version></code> ist die Version, zu der Sie wechseln — 17.0, 18.0 oder 19.0, entsprechend dem Versionsauswahlfeld auf unserer eigenen Tarifseite.
|
||||
</p>
|
||||
<p>
|
||||
Was die Odoo-Dokumentation neben diesen drei Zeilen verlangt, weil davon abhängt, ob sie funktionieren: Das Skript braucht die üblichen Linux-Befehle auf der Maschine; der Systembenutzer, der es ausführt, braucht Zugriff auf Ihre PostgreSQL-Datenbank (die übliche PostgreSQL-Client-Umgebung, etwa <code>.pgpass</code>); und die Maschine muss die Upgrade-Plattform auf TCP 443 und auf einem Port im Bereich 32768-60999 erreichen, ein Firewall kann also eine Ausnahme brauchen. Die Kopie, die Sie hochladen, wird ohne Filestore übermittelt, deshalb muss der Produktiv-Filestore in die aktualisierte Datenbank zusammengeführt werden, bevor Sie sie testen. Der Download enthält <code>dump.sql</code> und einen Filestore-Ordner, und nur wer das Upgrade angefordert hat, kann das Ergebnis herunterladen.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oc-sub">
|
||||
<h3>Der Community-Weg: OCA OpenUpgrade</h3>
|
||||
<pre class="oc-code"><code># 1. OpenUpgrade for the TARGET version (the branch is the target major version)
|
||||
git clone --depth 1 --branch <TARGET>.0 https://github.com/OCA/OpenUpgrade.git
|
||||
|
||||
# 2. helper library — the line the OpenUpgrade docs use
|
||||
pip install "git+https://github.com/OCA/openupgradelib.git@master#egg=openupgradelib"
|
||||
|
||||
# 3. put the clone on the add-ons path of the <TARGET> Odoo config
|
||||
# addons_path = <your own addons>,</abs/path>/OpenUpgrade
|
||||
|
||||
# 4. migrate the copy of the database
|
||||
<odoo-bin> -c /etc/odoo/<TARGET>.conf \
|
||||
-d <DB> \
|
||||
--upgrade-path=/abs/path/OpenUpgrade/openupgrade_scripts/scripts \
|
||||
-u all --stop-after-init \
|
||||
--load=base,web,openupgrade_framework
|
||||
|
||||
# 5. finish: a plain update, no migration parameters
|
||||
<odoo-bin> -c /etc/odoo/<TARGET>.conf -d <DB> -u all --stop-after-init</code></pre>
|
||||
<div class="oc-note">
|
||||
<p>
|
||||
<strong>Vier Dinge ersetzen:</strong> <code><TARGET></code> ist die Ziel-Hauptversion (17, 18 oder 19 — nicht die Version, von der Sie kommen); <code><DB></code> ist die Kopie, die Sie migrieren, nie die laufende Datenbank; <code><odoo-bin></code> ist die Binärdatei der Zielversion, und wie sie heißt, hängt davon ab, wie Sie Odoo installiert haben (<code>odoo-bin</code>, <code>odoo</code> oder das Docker-Äquivalent); und beide absoluten Pfade sind Ihre eigenen — der Add-ons-Pfad und der Ort des OpenUpgrade-Klons.
|
||||
</p>
|
||||
<p>
|
||||
Zwei Details aus der eigenen Dokumentation des Projekts, die man mitnehmen sollte: Der <code>openupgrade_framework</code>-Teil dieses Befehls ist eine Reihe von Patches, die unter anderem verhindern, dass Odoo die Spalten und Tabellen von Feldern löscht, die es nicht mehr gibt — einer der Wege, auf denen eine Migration Daten verliert. Und die Umgebungsvariable <code>OPENUPGRADE_USE_DEMO=yes</code> behält die Demodaten in der migrierten Datenbank, wenn Sie sie wollen.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oc-sub">
|
||||
<h3>Ihre individuellen Module</h3>
|
||||
<pre class="oc-code"><code># Odoo's own code-rewrite command (it runs the scripts in odoo/upgrade_code)
|
||||
<odoo-bin> upgrade_code --from <FROM> --to <TO> --dry-run</code></pre>
|
||||
<div class="oc-note">
|
||||
<p>
|
||||
<strong>Ersetzen Sie</strong> <code><FROM></code> und <code><TO></code> durch die beiden Hauptversionen (zum Beispiel 18 und 19). Führen Sie es zuerst mit <code>--dry-run</code> aus. Die eigene Befehlsreferenz von Odoo nennt diesen Befehl ein „Best-Effort“-Werkzeug und warnt, dass er „keine Silberkugeln“ ist: Er schreibt um, was er kann, und hinterlässt Ihnen eine Liste dessen, was ein Mensch noch ändern muss. Das Gegenstück der OpenUpgrade-Community für Modulcode ist <code>odoo-module-migrator</code>, das INFO für automatische Änderungen, WARNING für prüfenswerte Dinge und ERROR für Dinge protokolliert, die gar nicht funktionieren. Beide Werkzeuge berichten; keines denkt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oc-sub">
|
||||
<h3>Backups und der Filestore</h3>
|
||||
<pre class="oc-code"><code># stop the service while you work (packaged install; the Odoo docs show this pattern)
|
||||
sudo service odoo<TARGET> stop
|
||||
|
||||
# database dump (PostgreSQL's own tool)
|
||||
sudo -u postgres pg_dump -Fc -d <DB> -f /path/backup/<DB>.dump
|
||||
|
||||
# restore a dump into a fresh database
|
||||
sudo -u postgres createdb -O <DB_OWNER> <DB_NEW>
|
||||
sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
|
||||
# the filestore lives under Odoo's data directory:
|
||||
# default on Unix: $XDG_DATA_HOME or ~/.local/share/Odoo or /var/lib/Odoo
|
||||
# filestore path: <data_dir>/filestore/<DB></code></pre>
|
||||
<div class="oc-note">
|
||||
<p>
|
||||
<strong>Ersetzen Sie</strong> die Datenbanknamen, den Eigentümer, den Backup-Pfad und das Filestore-Datenverzeichnis durch Ihre eigenen; der Filestore enthält die Anhänge und Dokumente, auf die Ihre Datensätze zeigen, und eine Datenbank, die ohne ihn wiederhergestellt wird, ist eine Datenbank mit fehlenden Dateien. Das sind die dokumentierten Verfahren von PostgreSQL und Odoo, nicht unsere: Wir veröffentlichen keinen Befehl, der auf unseren eigenen Servern läuft, weil unser Service mit einem Ticket beginnt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Self-hosting cost -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Eigenleistung</p>
|
||||
<h2 class="section-title">Was Eigenleistung wirklich kostet</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Ein gemieteter Server ist billig. Das ist die kleinste Zahl in dieser Entscheidung. Odoo Community selbst ist kostenlos: Eine Lizenz pro Benutzer werden Sie auf diesem Weg nirgends finden, weil Community keine hat.
|
||||
</p>
|
||||
<p>
|
||||
Was in dieser Zahl nicht steckt, ist der Mensch. Ein Upgrade auf Ihrem eigenen Server heißt: Jemand installiert die neue Version, bringt den Migrationscode auf den richtigen Pfad, portiert die Module, die Ihr Geschäft tatsächlich nutzt, lässt die Migration laufen, bis das Log nicht mehr meckert, prüft, ob Kunden, Aufträge und Rechnungen noch da sind, räumt auf, was die Migration hinterlassen hat, und macht das Ganze dann zu einem passenden Zeitpunkt noch einmal auf der Produktivdatenbank. Die Odoo-Dokumentation sagt, das Update erledigt am besten die Person, die Odoo ursprünglich eingerichtet hat. Auf einem gemieteten Server sind das Sie oder jemand, den Sie pro Stunde bezahlen, und keine dieser Zeilen steht auf der Rechnung. Das ist die Hälfte der Rechnung, die niemand ausdruckt, und die Hälfte, die in Ihren Abenden landet.
|
||||
</p>
|
||||
<p>
|
||||
Wir werden Ihre Stunden nicht beziffern, weil wir sie nicht gemessen haben und eine Marketingzahl schlechter wäre als keine. Was wir sagen, ist der Teil, bei dem es nicht wirklich ums Geld geht: Während Sie diese Arbeit machen, machen Sie nicht die Arbeit, für die man Sie bezahlt, und wenn die Migration falsch ist, erfahren Sie es von einem Kunden.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section class="section-dark" id="faq">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Klare Antworten</p>
|
||||
<h2 class="section-title">Fragen zum Upgrade</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Ist ein Upgrade dasselbe wie ein Update?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Nein. Ein Update bringt Ihnen die neueste Fassung der Software, die Sie bereits einsetzen. Ein Upgrade bringt Ihre Datenbank auf eine neue Hauptversion (18 auf 19 oder 19 auf 20) und wandelt die Daten selbst um. Es geht nur in eine Richtung: einen unterstützten Weg zurück gibt es nicht, und es ist keine Lizenzänderung, kein Editionswechsel und kein Hosting-Wechsel.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Können wir direkt von Odoo 14 auf Odoo 20 upgraden?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Nein. Es geht immer nur eine Hauptversion auf einmal: 14 auf 15 auf 16 auf 17 auf 18 auf 19 auf 20. Eine Version zu überspringen ist kein unterstützter Weg. Unser eigener Migrationsservice dokumentiert Unterstützung für Datenbanken auf Odoo 17, 18 und 19, nur Hauptreleases, keine Patch-Releases; ältere Datenbanken brauchen zuerst eine Kompatibilitätsprüfung, die mit einem Support-Ticket beginnt.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Was passiert mit meiner Historie: Rechnungen, Zahlungen, Anhänge?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Das ist die richtige Frage, und die ehrliche Antwort lautet: Es hängt vom Weg ab. Der OpenUpgrade-Weg — eine Versionsmigration auf Ihrem eigenen Server — nimmt die Datenbank mit und erhält die Historie und die Verknüpfungen zwischen den Datensätzen. Die OpenUpgrade-Dokumentation warnt, dass der andere Weg, Dokumente in ein neues System zu verschieben, nur einen Teil Ihrer Daten rettet und die Historie und die Verknüpfungen zwischen den Datensätzen verliert, zum Beispiel die Rechnungen je Kunde. Unser Service baut Ihnen eine neue Datenbank und bringt Ihre Daten hinein; unser Weg ist also der, nach dem Sie fragen sollten: Bitten Sie uns vor Ihrer Freigabe, genau aufzulisten, welche Datensätze in der neuen Datenbank sein werden und welche nicht. Wir möchten lieber, dass Sie sie stellen, als dass Sie sie annehmen.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Funktionieren meine individuellen Module weiterhin?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Nicht von allein. Ein Modul, das für Ihr Geschäft geschrieben wurde, braucht seinen Code auf der Zielversion, und Umbenennungen, die sonst Daten kosten würden, brauchen eigene Migrationsskripte. Die Odoo-Dokumentation ist hier deutlich: Ein Upgrade ist blockiert, bis es eine Version Ihrer individuellen Module für die Zielversion gibt. Module, die mit Odoo ausgeliefert werden, und Module der Community-Vereinigung bringen ihre eigenen Migrationsskripte mit; Ihre nicht, und die muss jemand schreiben.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Was kostet es, und wie lange dauert es?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Für den Upgrade-Service veröffentlichen wir weder Preis noch Dauer, und wir erfinden hier auch keine. Was wir veröffentlichen, ist der Anfang: Sie eröffnen ein Support-Ticket, wir prüfen Ihre Datenbank auf Kompatibilität und melden uns bei Ihnen. Wenn Sie es gegen die Eigenleistung abwägen, ist der ehrliche Vergleich nicht die Servermiete, sondern Ihre eigenen Stunden, die auf keiner Rechnung auftauchen.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Brauche ich einen Entwickler?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Um die Befehle im technischen Abschnitt auszuführen, ja; oder jemanden, der sich im Terminal mit PostgreSQL auskennt. Damit wir es übernehmen, nein: Genau das ist der Sinn des Service. Sie senden die Datenbank, wir bauen das neue System auf unserer Infrastruktur, und Sie erhalten die Zugangsdaten.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Kann ich das System mit der neuen Version ansehen, bevor es live geht?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Ja, und das sollten Sie. Wer die Arbeit macht, migriert zuerst eine Kopie; das ist die erste Regel des ganzen Prozesses, in der Odoo-Dokumentation wie im OpenUpgrade-Projekt. Und die migrierte Kopie ist das, was Sie prüfen, bevor mit dem System, auf dem Ihr Geschäft läuft, irgendetwas passiert. Unser Service folgt demselben Prinzip: Wir bauen das neue System auf unseren eigenen Servern, und Sie vergleichen es mit dem alten.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Wir sind woanders gehostet. Können Sie uns trotzdem upgraden?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Ja, genau dafür ist unser Migrationsservice da. Sie eröffnen ein Support-Ticket, wir senden Ihnen ein sicheres Formular zum Hochladen Ihrer Datenbank, richten Ihnen einen neuen Server auf unserer Infrastruktur ein und stellen die Zugangsdaten bereit. Datenbanken auf Odoo 17, 18 und 19, nur Hauptreleases; ältere nach einer Kompatibilitätsprüfung.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Final CTA band -->
|
||||
<section class="section-dark cmp-cta" id="start">
|
||||
<div class="container">
|
||||
<p class="oc-lead">
|
||||
Sie eröffnen ein Support-Ticket, wir prüfen Ihre Datenbank auf Kompatibilität und melden uns bei Ihnen.
|
||||
</p>
|
||||
<div class="cmp-cta-actions">
|
||||
<a href="/de/support.html#contact" class="btn btn-brass btn-lg">Ticket eröffnen: Sagen Sie uns, welche Version Sie nutzen</a>
|
||||
<a href="/de/#pricing" class="btn btn-outline btn-lg">Tarife ansehen</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Nützliche Links</h4>
|
||||
<ul>
|
||||
<li><a href="/de/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/de/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/de/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Rechtliches</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Partner</h4>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
<a href="https://OD8N.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OD8N</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>Über uns</h4>
|
||||
<p>Wir bauen clevere, skalierbare Geschäftslösungen: die <strong>Stabilität</strong> von Odoo ERP trifft auf die <strong>Kraft</strong> von KI-Agenten und N8N-Automatisierungen.</p>
|
||||
<p>Von schlanken Vertriebsprozessen bis zum globalen Rollout: Unser <strong>schlanker, umweltfreundlicher</strong> Ansatz senkt Kosten, steigert die Effizienz und lässt Unternehmen ohne Grenzen wachsen.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Folgen Sie uns</h4>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="oc-sr-only" for="footerContactEmail">Ihre E-Mail-Adresse</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Ihre E-Mail-Adresse" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
<label class="oc-sr-only" for="footerContactText">Ihre Nachricht</label>
|
||||
<textarea id="footerContactText" name="message" placeholder="Ihre Nachricht …" required></textarea>
|
||||
<button type="submit" class="footer-send-btn" aria-label="Nachricht senden"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M2 21l21-9L2 3v7l15 2-15 2z" /></svg></button>
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -31,8 +31,9 @@
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
||||
<link rel="preload" as="image" href="/images/hero/bootcamp-hero-mobile-900.webp" media="(max-width: 640px)" fetchpriority="high" />
|
||||
<link rel="preload" as="image" href="/images/hero/bootcamp-hero-desktop-1920.webp" media="(min-width: 641px)" fetchpriority="high" />
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- ODOO ERP Automation Bootcamp landing page (page-scoped; additive) ---- */
|
||||
.bc-sr-only {
|
||||
@@ -192,6 +193,14 @@
|
||||
form[action$="/shop/post_basket"] .btn {
|
||||
line-height: inherit;
|
||||
}
|
||||
/* At 0 seats /static/bootcamp-availability.js disables these Buy buttons; make the
|
||||
disabled state read as disabled — quiet dimming in the page's own CI, never an
|
||||
alert banner. */
|
||||
form[action$="/shop/post_basket"] .btn:disabled,
|
||||
form[action$="/shop/post_basket"] .btn[aria-disabled="true"] {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Grids — auto-fit so no breakpoint is needed */
|
||||
.bc-list {
|
||||
@@ -223,7 +232,7 @@
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-rest);
|
||||
padding: 1.4rem 1.4rem 1.4rem 3.4rem;
|
||||
transition: box-shadow 0.25s, transform 0.25s;
|
||||
transition: transform 0.25s; /* box-shadow kept, not transitioned (non-composited) */
|
||||
}
|
||||
.bc-lessons li:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
@@ -313,7 +322,7 @@
|
||||
.bc-schedule dt {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.92rem;
|
||||
color: var(--brass-deep);
|
||||
color: #876c1e; /* 4.68:1 on --ivory (was --brass-deep 4.49:1) */
|
||||
}
|
||||
.bc-schedule dd {
|
||||
margin: 0;
|
||||
@@ -452,6 +461,109 @@
|
||||
.btn-brass:focus-visible {
|
||||
outline-color: #fff;
|
||||
}
|
||||
/* Waiting list — for someone who cannot attend the January cohort.
|
||||
Deliberately quieter than the Buy button: outline button, smaller type, no brass fill. */
|
||||
.bc-waitlist {
|
||||
/* Component-scoped error colour: the site has no shared token for it. */
|
||||
--wl-error: #b02a37;
|
||||
max-width: 720px;
|
||||
margin: 2.5rem auto 0;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: var(--ivory);
|
||||
text-align: left;
|
||||
}
|
||||
.bc-wl-title {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 1.1rem;
|
||||
color: var(--ink);
|
||||
}
|
||||
.bc-wl-lead {
|
||||
margin: 0 0 1.1rem;
|
||||
font-size: 0.88rem;
|
||||
line-height: 1.6;
|
||||
color: rgba(23, 28, 38, 0.78); /* the page's own .bc-note value, on the same cream */
|
||||
}
|
||||
.bc-wl-form input,
|
||||
.bc-wl-form textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 0.6rem;
|
||||
padding: 0.6rem 0.75rem;
|
||||
font-family: Inter, sans-serif;
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink);
|
||||
background: #fff;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.bc-wl-form textarea {
|
||||
min-height: 3.4rem;
|
||||
resize: vertical;
|
||||
}
|
||||
.bc-wl-btn {
|
||||
padding: 0.6rem 1.5rem;
|
||||
font-size: 0.8rem;
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
border-color: rgba(23, 28, 38, 0.35);
|
||||
}
|
||||
.bc-wl-btn:hover {
|
||||
border-color: var(--brass);
|
||||
background: rgba(201, 162, 39, 0.12);
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.bc-wl-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
.bc-wl-success {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: var(--success);
|
||||
}
|
||||
.bc-wl-error {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--wl-error);
|
||||
}
|
||||
|
||||
/* --- 2026-11-02 PageSpeed pass (page-scoped, additive) ---------------------
|
||||
1. The footer <h4>s became <h3>s so the heading order descends after the last
|
||||
section h2 (a11y "heading-order"); these rules keep their look identical to
|
||||
the shared .footer h4 in /style.css.
|
||||
2. A link inside an on-dark note is the lighter brass (7.15:1 on midnight,
|
||||
A11y "color-contrast") and underlined, so it is distinguishable without
|
||||
colour (A11y "link-in-text-block"). */
|
||||
.footer h3 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
color: #fff;
|
||||
margin-bottom: 0.8rem;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
.bc-note.on-dark a {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
}
|
||||
/* the footer copyright line at .35 alpha was 3.2:1 on midnight */
|
||||
.footer .fcopy {
|
||||
color: rgba(255, 255, 255, 0.5); /* 5.17:1 */
|
||||
}
|
||||
/* no-JS footer fallback (rendered only when JavaScript is off) */
|
||||
.footer .bc-noscript {
|
||||
margin-top: 0.6rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.footer .bc-noscript a {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
@@ -482,8 +594,9 @@
|
||||
"@type": "CourseInstance",
|
||||
"courseMode": "online",
|
||||
"courseWorkload": "PT1H",
|
||||
"startDate": "2026-01-22",
|
||||
"endDate": "2026-03-26",
|
||||
"maximumAttendeeCapacity": 6,
|
||||
"startDate": "2027-01-21",
|
||||
"endDate": "2027-03-25",
|
||||
"instructor": {
|
||||
"@type": "Person",
|
||||
"name": "Oliver Arnold",
|
||||
@@ -500,7 +613,7 @@
|
||||
},
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "465.00",
|
||||
"price": "595.00",
|
||||
"priceCurrency": "USD",
|
||||
"category": "Paid",
|
||||
"url": "https://odoo4projects.com/odoo-erp-automation-bootcamp/"
|
||||
@@ -554,12 +667,18 @@
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="bc-topbar">
|
||||
<div class="container">
|
||||
<a class="bc-brand" href="/">ODOO4<span>projects</span></a>
|
||||
<a class="bc-brand" href="/de/">ODOO4<span>projects</span></a>
|
||||
<nav class="bc-topbar-links" aria-label="Seitenlinks">
|
||||
<a href="/de/#pricing">Pläne & Preise</a>
|
||||
<a href="/de/support.html">Support</a>
|
||||
@@ -569,9 +688,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero bc-hero">
|
||||
<div class="container">
|
||||
<p class="hero-kicker">Q1 2026 · 10 LIVE-SESSIONS · OLIVER ARNOLD</p>
|
||||
<p class="hero-kicker">Q1 2027 · 10 LIVE-SESSIONS · OLIVER ARNOLD</p>
|
||||
<h1>ODOO ERP Automation Bootcamp</h1>
|
||||
<p class="hero-sub">
|
||||
Kein Programmieren. Kein Server, den Sie einrichten müssen. Wenn Sie Ihr Geschäft mit einer Tabelle steuern, schaffen Sie das auch.
|
||||
@@ -579,19 +699,26 @@
|
||||
<div class="hero-stats">
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> 10 Live-Sessions, je eine Stunde</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Donnerstags 18:00–19:00 US-Zentralzeit</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Start am Donnerstag, 22. Januar 2026</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Start am Donnerstag, 21. Januar 2027</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Ein Jahr Odoo Community Edition inklusive</span>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<input type="hidden" name="basket" value='[{"product_id":12,"qty":1}]' />
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":17,"qty":1,"info":"Q1 2027, English"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Für 465.00 USD kaufen</button>
|
||||
<button type="submit" class="btn btn-brass btn-lg">Für 595.00 USD kaufen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Live remaining-seat count, immediately below the hero. One seat element only on
|
||||
the page; /static/bootcamp-availability.js fills it from the availability webhook
|
||||
and leaves it empty+hidden if that fetch fails. -->
|
||||
<div class="container">
|
||||
<p class="bc-note bc-seats" data-bc-seats hidden></p>
|
||||
</div>
|
||||
|
||||
<!-- From zero to a running ERP -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
@@ -604,10 +731,10 @@
|
||||
</p>
|
||||
<p class="bc-subline">Drei Monate. Zehn Stunden Unterricht. Ein System, das Ihr Unternehmen steuert.</p>
|
||||
<div class="bc-action">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<input type="hidden" name="basket" value='[{"product_id":12,"qty":1}]' />
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":17,"qty":1,"info":"Q1 2027, English"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Für 465.00 USD kaufen</button>
|
||||
<button type="submit" class="btn btn-brass btn-lg">Für 595.00 USD kaufen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -720,22 +847,24 @@
|
||||
<dt>Sitzungen</dt>
|
||||
<dd>10, jeden Donnerstag von 18:00–19:00 US-Zentralzeit</dd>
|
||||
<dt>Zeitraum</dt>
|
||||
<dd>Q1 2026</dd>
|
||||
<dd>Q1 2027</dd>
|
||||
<dt>Erste Sitzung</dt>
|
||||
<dd>Donnerstag, 22. Januar 2026</dd>
|
||||
<dd>Donnerstag, 21. Januar 2027</dd>
|
||||
<dt>Letzte Sitzung</dt>
|
||||
<dd>Donnerstag, 26. März 2026</dd>
|
||||
<dd>Donnerstag, 25. März 2027</dd>
|
||||
<dt>Termine</dt>
|
||||
<dd>22. Januar · 29. Januar · 5. Februar · 12. Februar · 19. Februar · 26. Februar · 5. März · 12. März · 19. März · 26. März 2026</dd>
|
||||
<dd>21. Januar · 28. Januar · 4. Februar · 11. Februar · 18. Februar · 25. Februar · 4. März · 11. März · 18. März · 25. März 2027</dd>
|
||||
<dt>Dauer</dt>
|
||||
<dd>1 Stunde pro Sitzung, insgesamt 10 Stunden</dd>
|
||||
<dt>Ort</dt>
|
||||
<dd>Live und online</dd>
|
||||
<dt>Gruppengröße</dt>
|
||||
<dd>Begrenzt auf 6 Teilnehmer</dd>
|
||||
<dt>Trainer</dt>
|
||||
<dd>Oliver - The OC Guy - Arnold, Technical Lead bei ODOO4projects</dd>
|
||||
</dl>
|
||||
<p class="bc-note">
|
||||
Die US-Zentralzeit liegt bis zum 8. März auf UTC−6 und danach auf UTC−5; Kalendereinladungen enthalten die richtige Ortszeit.
|
||||
Die US-Zentralzeit liegt bis zum 14. März auf UTC−6 und danach auf UTC−5; Kalendereinladungen enthalten die richtige Ortszeit.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -760,17 +889,37 @@
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Preis und Buchung</h2>
|
||||
<p class="bc-price">Das Programm kostet USD 465.00 für alle zehn Sitzungen.</p>
|
||||
<p class="bc-price">Das Programm kostet USD 595.00 für alle zehn Sitzungen.</p>
|
||||
<p class="bc-note"><strong>Begrenzt auf 6 Teilnehmer</strong> — die Gruppe ist klein, damit der Trainer sich Ihre eigene Konfiguration ansehen kann.</p>
|
||||
<p class="bc-note">Ein Platz ist <strong>jederzeit übertragbar</strong> und kann <strong>bis zwei Wochen vor</strong> der ersten Sitzung am 21. Januar 2027 storniert werden.</p>
|
||||
<p class="bc-lead">
|
||||
Umfasst das komplette Programm: zehn Live-Sessions, ein Jahr gehostetes Odoo Community Edition, die Alumni-Community und die Expertenprüfung.
|
||||
</p>
|
||||
<div class="bc-action">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<input type="hidden" name="basket" value='[{"product_id":12,"qty":1}]' />
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":17,"qty":1,"info":"Q1 2027, English"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Für 465.00 USD kaufen</button>
|
||||
<button type="submit" class="btn btn-brass btn-lg">Für 595.00 USD kaufen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Waiting list: for a visitor who cannot attend the January cohort.
|
||||
Secondary to the Buy button above. Same CRM webhook and same payload shape as the
|
||||
site's footer contact form (area:'message'); the copy lives here, in the page's
|
||||
language, and /static/bootcamp-waitlist.js carries no strings. -->
|
||||
<div class="bc-waitlist">
|
||||
<h3 class="bc-wl-title">Andere Zeitzone oder andere Sprache?</h3>
|
||||
<p class="bc-wl-lead">Der Januar-Kurs läuft donnerstags 18:00–19:00 US-Zentralzeit, auf Englisch. Wenn Sie eine andere Uhrzeit oder eine andere Sprache brauchen, tragen Sie sich in die Warteliste ein. Wir schreiben Ihnen, sobald ein passender Kurs startet.</p>
|
||||
<form id="bcWaitlistForm" class="bc-wl-form" action="https://n8n.odoo4projects.com/webhook/ODOO4projects/crm" method="post" enctype="text/plain">
|
||||
<label class="bc-sr-only" for="bcWaitlistEmail">Ihre E-Mail-Adresse</label>
|
||||
<input type="email" id="bcWaitlistEmail" name="email" placeholder="Ihre E-Mail-Adresse" required />
|
||||
<label class="bc-sr-only" for="bcWaitlistComment">Welche Zeitzone oder Sprache Sie brauchen</label>
|
||||
<textarea id="bcWaitlistComment" name="comment" rows="2" placeholder="Welche Zeitzone oder Sprache brauchen Sie?" required></textarea>
|
||||
<button type="submit" class="btn bc-wl-btn" data-sending="Wird eingetragen…">In die Warteliste eintragen</button>
|
||||
</form>
|
||||
<p class="bc-wl-success" id="bcWaitlistSuccess" role="status" style="display:none">Sie stehen auf der Warteliste. Wir schreiben Ihnen, sobald ein Kurs in Ihrer Zeitzone oder Sprache angekündigt wird.</p>
|
||||
<p class="bc-wl-error" id="bcWaitlistError" role="alert" style="display:none">Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut.</p>
|
||||
</div>
|
||||
<ul class="bc-related">
|
||||
<li><a href="/de/support.html#contact">Fragen vor der Buchung? Sprechen Sie zuerst mit uns</a></li>
|
||||
<li><a href="/de/odoo-hosting-2027.html">Wie das Hosting nach Ihrem Jahr bei uns aussieht</a></li>
|
||||
@@ -786,31 +935,31 @@
|
||||
<h2 class="section-title">Fragen, die zuerst kommen</h2>
|
||||
<div class="bc-faq-grid">
|
||||
<details class="bc-faq">
|
||||
<summary>Brauche ich technische Kenntnisse?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Brauche ich technische Kenntnisse?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Nein. Die Sitzungen setzen kein ERP-Wissen und keine Programmierkenntnisse voraus. Sie arbeiten mit Ihren eigenen Daten, statt einer leeren Demo zu folgen.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>Was, wenn ich eine Sitzung verpasse?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Was, wenn ich eine Sitzung verpasse?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Die Sitzungen sind live und bauen aufeinander auf, nehmen Sie also teil, wenn Sie können. Wenn Sie eine verpassen, holen Sie im Alumni-Chat und im offenen Workshop der letzten Sitzung wieder auf.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>Ist das Hosting nach dem Kurs enthalten?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Ist das Hosting nach dem Kurs enthalten?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Ja, ein Jahr lang, im Programm enthalten. Danach wechselt Ihr System auf einen unserer normalen Hosting-Tarife, zum Preis, der auf unserer Website steht.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>Was muss ich installieren?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Was muss ich installieren?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Nichts zu installieren und nichts selbst zu betreiben. Ein Computer und ein Browser genügen, das laufende System stellen wir. n8n, das in Lektion 9 zum Einsatz kommt, ist ein kostenloses Konto im kostenlosen Tarif von n8n.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>Ist das ein Kurs über Odoo?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Ist das ein Kurs über Odoo?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Es ist ein Kurs darüber, wie Ihr Geschäft läuft. Odoo ist der Motor unter dem System, das Sie aufbauen; die zehn Lektionen drehen sich um Ihr Lager, Ihre Rechnungen, Ihre Kunden und die Stunden, die Sie zurückbekommen.</p>
|
||||
</div>
|
||||
@@ -818,6 +967,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
@@ -825,16 +975,16 @@
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Nützliche Links</h4>
|
||||
<h3>Nützliche Links</h3>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/de/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/de/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/de/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Rechtliches</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Partner</h4>
|
||||
<h3>Partner</h3>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
@@ -842,17 +992,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>Über uns</h4>
|
||||
<h3>Über uns</h3>
|
||||
<p>Wir bauen clevere, skalierbare Geschäftslösungen: die <strong>Stabilität</strong> von Odoo ERP trifft auf die <strong>Kraft</strong> von KI-Agenten und N8N-Automatisierungen.</p>
|
||||
<p>Von schlanken Vertriebsprozessen bis zum globalen Rollout: Unser <strong>schlanker, umweltfreundlicher</strong> Ansatz senkt Kosten, steigert die Effizienz und lässt Unternehmen ohne Grenzen wachsen.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Folgen Sie uns</h4>
|
||||
<h3>Folgen Sie uns</h3>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:hello@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<form class="footer-contact-form" id="footerContactForm" action="https://n8n.odoo4projects.com/webhook/ODOO4projects/crm" method="post" enctype="text/plain" data-ok="Danke! Wir melden uns in Kürze bei Ihnen." data-err="Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut.">
|
||||
<label class="bc-sr-only" for="footerContactEmail">Ihre E-Mail-Adresse</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Ihre E-Mail-Adresse" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
@@ -862,12 +1012,15 @@
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
<noscript><p class="bc-noscript">JavaScript ist deaktiviert. Schreiben Sie uns direkt an <a href="mailto:support@odoo4projects.com">support@odoo4projects.com</a>.</p></noscript>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script defer src="/static/buy.js"></script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/buy.js?v=31314de600"></script>
|
||||
<script defer src="/static/bootcamp-availability.js?v=94dfd8cd7c"></script>
|
||||
<script defer src="/static/bootcamp-waitlist.js?v=6c2e2fbd33"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -31,8 +31,7 @@
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- Odoo Hosting 2027 landing page (page-scoped; additive) ---- */
|
||||
.cmp-sr-only {
|
||||
@@ -479,7 +478,7 @@
|
||||
{
|
||||
"@type": "Product",
|
||||
"name": "Verwaltetes Odoo Community Hosting",
|
||||
"description": "Verwaltetes Odoo Community Hosting: Server, Backups, SSL-Zertifikat und Versions-Upgrades laufen für Sie zu einem Jahrespreis, ohne Lizenz pro Benutzer bei Odoo Community.",
|
||||
"description": "Verwaltetes Odoo Community Hosting: Server, Backups und SSL-Zertifikat laufen für Sie, und Ihre Odoo-Installation bleibt innerhalb ihrer Version aktuell, zu einem Jahrespreis, ohne Lizenz pro Benutzer bei Odoo Community. Ein Wechsel auf eine neue Hauptversion ist eine Migration und wird separat angeboten.",
|
||||
"brand": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"offers": [
|
||||
{
|
||||
@@ -560,7 +559,7 @@
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
@@ -576,14 +575,15 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero cmp-hero">
|
||||
<div class="container">
|
||||
<p class="hero-kicker">Vollständig verwaltetes Odoo Community Hosting</p>
|
||||
<h1>Odoo Hosting 2027: verwaltetes Odoo Community, <span>in etwa fünf Minuten einsatzbereit</span></h1>
|
||||
<p class="hero-sub">
|
||||
Ein verwaltetes Odoo Community System: Ihr Lager, Ihre Aufträge, Ihre Rechnungen und Ihre Kunden in
|
||||
einem System. Wir betreiben Server, Backups, Zertifikat und Upgrades. Sie pflegen Ihre Daten ein und
|
||||
kümmern sich ums Geschäft.
|
||||
einem System. Wir betreiben Server, Backups, Zertifikat und die Updates innerhalb Ihrer Odoo-Version.
|
||||
Sie pflegen Ihre Daten ein und kümmern sich ums Geschäft.
|
||||
</p>
|
||||
<div class="hero-stats">
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Etwa 5 Minuten bis zum laufenden System</span>
|
||||
@@ -606,7 +606,9 @@
|
||||
<p class="cmp-lead">
|
||||
Sie sollten nicht die IT-Abteilung werden müssen, um zu wissen, was in Ihrem Lager liegt. Ein
|
||||
Geschäftssystem abonniert man, man baut es nicht. Server, Patches, Backups, Zertifikat,
|
||||
Versions-Upgrade: das ist dauerhaft unsere Aufgabe, und kein Abend, den Sie Ihrer Firma zurückgeben.
|
||||
die Updates innerhalb Ihrer Odoo-Version: das ist dauerhaft unsere Aufgabe, und kein Abend,
|
||||
den Sie Ihrer Firma zurückgeben. Die Datenbank auf eine neue Hauptversion zu bringen, ist eine
|
||||
Migration, die wir separat anbieten.
|
||||
</p>
|
||||
<p class="cmp-lead">
|
||||
Deshalb bringen wir Ihr Lager, Ihre Aufträge, Ihre Rechnungen und die offenen Forderungen an einen
|
||||
@@ -703,7 +705,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Versions-Upgrades</th>
|
||||
<td class="is-us">Ein Support-Ticket. Wir migrieren die Versionen 17, 18 und 19.</td>
|
||||
<td class="is-us">Updates und Upgrades innerhalb Ihrer Version sind inklusive. Ein Wechsel auf eine neue Hauptversion ist eine Migration und wird separat angeboten.</td>
|
||||
<td>Sie machen es selbst, nach einem vollständigen Backup.</td>
|
||||
<td>Push in den Branch; scheitert ein Modul-Update, setzt Odoo den Server zurück und rollt die Datenbank zurück.</td>
|
||||
<td>Automatisch und verpflichtend nach Odoos Zeitplan.</td>
|
||||
@@ -919,37 +921,37 @@
|
||||
<h2 class="section-title">Fragen, die die Tabelle aufwirft</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary>Was bedeutet „fünf Minuten“ eigentlich?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Was bedeutet „fünf Minuten“ eigentlich?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Fünf Minuten dauert es bis zum laufenden System, nicht bis zum fertigen System. Ihre eigenen Kunden, Produkte und Bestände einzupflegen ist die Arbeit der ersten Woche. Diese Woche ist bei allen Wegen oben gleich lang.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Unterstützen Sie Odoo Online?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Unterstützen Sie Odoo Online?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Nein. Odoo Online führt nur die Standard-Apps von Odoo und ist mit eigenen Modulen oder Modulen aus dem Odoo Apps Store nicht kompatibel, Sie können also keine App hinzufügen, die nicht auf Odoos Liste steht. Upgrades sind automatisch und verpflichtend nach Odoos Zeitplan. Wenn Odoos Standard-Apps alles abdecken, was Sie je brauchen, ist Odoo Online die günstigere und einfachere Antwort, und wir sind nicht die richtige Wahl.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Kann ich eigene Apps oder OCA-Module hinzufügen?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Kann ich eigene Apps oder OCA-Module hinzufügen?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Odoos eigene Apps sind in jedem Plan verfügbar. Eigene und OCA-Module installieren Sie ab On the Rise, per Git oder mit einem Klick. Bei Side Hustle gibt es keine Modulinstallation.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Brauche ich einen KI-Assistenten, um ODOO4projects zu nutzen?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Brauche ich einen KI-Assistenten, um ODOO4projects zu nutzen?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Nein. Wir liefern unseren MCP-Server direkt in den Apps mit, sodass ein KI-Assistent wie Claude Code oder Hermes den Server neu starten, ein Modul hochladen, eine Domain hinzufügen oder das Log für Sie lesen kann. Sie öffnen nie ein Hosting-Panel. Es ist optional: Das Geschäft läuft ohne ihn genau gleich.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Können wir später zu Odoo Enterprise wechseln?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Können wir später zu Odoo Enterprise wechseln?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Ja. Bringen Sie Ihre eigene Odoo-Enterprise-Lizenz mit und behalten Sie dasselbe System. Keine Migration.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Gibt es eine Lizenz pro Benutzer?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Gibt es eine Lizenz pro Benutzer?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Nein. Odoo Community hat keine Lizenz pro Benutzer; unsere Pläne sind ein pauschaler Jahrespreis. Odoo Enterprise, wenn Sie es mitbringen, wird von Odoo S.A. pro Benutzer lizenziert.</p>
|
||||
</div>
|
||||
@@ -979,13 +981,14 @@
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Nützliche Links</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/de/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/de/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/de/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Rechtliches</a></li>
|
||||
@@ -1010,7 +1013,7 @@
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:hello@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="cmp-sr-only" for="footerContactEmail">Ihre E-Mail-Adresse</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Ihre E-Mail-Adresse" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* Language selector — the page's top row: the back-link stays left, the selector travels right.
|
||||
Cream canvas, so lang.js's own dark-brass active colour is the correct one (no override). */
|
||||
@@ -268,9 +268,16 @@
|
||||
.contact-form { padding: 1.25rem; }
|
||||
}
|
||||
</style>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="/de/">← Zurück zur Startseite</a>
|
||||
@@ -285,7 +292,9 @@
|
||||
<p>
|
||||
Für die schnellste Hilfe lesen Sie bitte zuerst unsere <strong>FAQ</strong> — unser Support-Bot
|
||||
hilft bei schnellen Lösungen wie <strong>git pull</strong> oder Neustarts — oder senden Sie
|
||||
einfach ein <strong>Ticket</strong> an unser Support-Team.
|
||||
einfach ein <strong>Ticket</strong> an unser Support-Team. Dringende Themen kann der
|
||||
<strong>KI-Agent</strong> übernehmen, den wir anbieten, und E-Mail-Support antwortet
|
||||
innerhalb von <strong>24 Stunden</strong>.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -321,7 +330,7 @@
|
||||
<!-- First Steps -->
|
||||
<div class="faq-panel active" id="panel-first-steps">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Mein Odoo wirkt leer. Was kann ich damit machen?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -341,7 +350,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Wie installiere ich eine neue App?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -351,7 +360,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Wie richte ich meinen E-Mail-Server zum Versand von Nachrichten aus Odoo ein?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -361,7 +370,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Wie ändere ich meinen Anmeldenamen oder mein Passwort?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -375,7 +384,7 @@
|
||||
<!-- Advanced Users -->
|
||||
<div class="faq-panel" id="panel-advanced">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Bekomme ich SSH-Zugriff auf meinen Service?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -384,7 +393,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Wie stelle ich die Häufigkeit meiner Backups ein?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -393,7 +402,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Wie lange werden Backups gespeichert?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -402,7 +411,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Wie leite ich meine Domain auf mein Odoo?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -412,7 +421,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Wie kann ich Odoo Enterprise installieren?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -425,7 +434,7 @@
|
||||
<!-- Trouble Shooting -->
|
||||
<div class="faq-panel" id="panel-trouble">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Nach einem git check in startet mein Server nicht mehr oder zeigt Fehler 500</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -434,7 +443,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Warum zeigt meine Domain „Unknown Certificate“ oder „Bad Gateway“ an?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -447,7 +456,7 @@
|
||||
<!-- Commercial -->
|
||||
<div class="faq-panel" id="panel-commercial">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Ist die Odoo Enterprise License enthalten?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -456,7 +465,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Wie kann ich meinen Service upgraden?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -469,7 +478,7 @@
|
||||
<!-- Bring your Database -->
|
||||
<div class="faq-panel" id="panel-migrate">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Wie kann ich meine Odoo-Datenbank von einem anderen Anbieter umziehen?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -479,7 +488,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Kann ich meine Odoo-Datenbank von einer älteren Version aktualisieren, z. B. 14 → 19?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -576,6 +585,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -128,7 +128,9 @@
|
||||
.hero-stats{display:flex;gap:1.5rem;margin-bottom:2rem;flex-wrap:wrap}.hero-stat{display:flex;align-items:center;gap:.4rem;color:rgba(255,255,255,.65);font-size:.85rem}.hero-stat i{color:var(--brass);font-size:.75rem}
|
||||
.hero-actions{display:flex;gap:1rem;flex-wrap:wrap;margin-bottom:2rem}
|
||||
.hero-notice{position:absolute;top:1.25rem;right:1.25rem;z-index:3;display:flex;align-items:center;gap:.55rem;max-width:min(360px,calc(100% - 2rem));padding:.6rem .85rem .6rem 1rem;background:#f5c542;color:var(--midnight);border:1px solid rgba(13,27,46,.14);border-radius:var(--radius);box-shadow:0 8px 24px rgba(13,27,46,.3);font-family:Inter,sans-serif;font-size:.82rem;line-height:1.4;animation:heroNoticeIn .4s cubic-bezier(.16,1,.3,1)}
|
||||
.hero-notice[hidden]{display:none}
|
||||
/* `.hero-notice[hidden]{display:none}` used to live here; the site-wide `[hidden]`
|
||||
rule in /style.css hides it (`.hero-notice` sets `display:flex`, which outranked
|
||||
the UA rule). */
|
||||
.hero-notice i{color:var(--midnight);font-size:.9rem;flex-shrink:0}
|
||||
.hero-notice-text{flex:1;min-width:0;overflow-wrap:anywhere}
|
||||
.hero-notice-close{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:1.35rem;height:1.35rem;padding:0;border:0;border-radius:50%;background:rgba(13,27,46,.12);color:var(--midnight);font-size:1rem;line-height:1;cursor:pointer;transition:background .2s}
|
||||
@@ -220,15 +222,14 @@
|
||||
#customQuoteModal .biz-success p{color:var(--midnight)}
|
||||
@media(max-width:600px){.oca-table td,.oca-table th{padding:.5rem .65rem;font-size:.8rem}.ow-panel{left:5%;right:5%}.ow-close{top:.5rem;right:.5rem;font-size:1.6rem}}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!--
|
||||
@@ -240,6 +241,7 @@
|
||||
FINISH: unreviewed and undocumented is unfinished; this build ends with the finish review, the verdict, and DESIGN.md.
|
||||
-->
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero">
|
||||
<div class="hero-notice" id="heroConfirmNotice" role="status" aria-live="polite" hidden>
|
||||
<i class="fas fa-check-circle" aria-hidden="true"></i>
|
||||
@@ -259,7 +261,7 @@
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a href="#pricing" class="btn btn-brass">Ver planes y precios →</a>
|
||||
<a href="/support.html" class="btn btn-outline">Cómo funciona</a>
|
||||
<a href="/es/support.html" class="btn btn-outline">Cómo funciona</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -362,32 +364,32 @@
|
||||
<div class="container">
|
||||
<h2 class="section-title">Preguntas frecuentes</h2>
|
||||
<div class="faq-grid">
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>¿Y si mi plan se me queda corto?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Crezca de Side Hustle a Empire sin migrar datos ni perder disponibilidad. Cambie de plan en los ajustes de Odoo: su instancia sigue activa y sus datos vienen con usted.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>¿Puedo personalizarlo?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Sí. On the Rise y los planes superiores admiten módulos vía Git. Instale aplicaciones personalizadas, desarrolle las suyas o use Quick GIT para instalarlas con un clic.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>¿En cuánto tiempo puedo empezar?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Cinco minutos. Elija un plan, escoja su región y su instancia de Odoo estará activa. Sin cuota de alta. Pago con Stripe. Cancele cuando quiera.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>¿Puedo usar Odoo Enterprise?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Powerhouse y Empire están listos para Enterprise. Traiga su licencia; nosotros ponemos la infraestructura.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>¿Odoo Community? ¿Qué puede hacer?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Inventario, contabilidad, CRM, ventas, fabricación, RR. HH.: todo en un solo sistema. Gratuito y totalmente de código abierto.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>¿Tienen un programa de afiliados?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>No. Creemos que unos precios competitivos para nuestros clientes compartidos están en nuestro propio interés.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="/support.html" class="faq-link">Todas las preguntas →</a>
|
||||
<a href="/es/support.html" class="faq-link">Todas las preguntas →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -416,7 +418,7 @@
|
||||
<small class="price-period">/ año</small>
|
||||
</div>
|
||||
<p class="desc">"ODOO Estándar... es todo lo que mi negocio necesita"</p>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy" data-id="6">Comprar ahora</a>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="6">Comprar ahora</a>
|
||||
<ul>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Lance Odoo CE en 5 minutos</li>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Copias automáticas, sin acordarse</li>
|
||||
@@ -434,7 +436,7 @@
|
||||
<small class="price-period">/ año</small>
|
||||
</div>
|
||||
<p class="desc">"Necesito algunos módulos e informes profesionales"</p>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy" data-id="4">Comprar ahora</a>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="4">Comprar ahora</a>
|
||||
<ul>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Lance Odoo CE en 5 minutos</li>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Copias automáticas, sin acordarse</li>
|
||||
@@ -453,7 +455,7 @@
|
||||
<small class="price-period">/ año</small>
|
||||
</div>
|
||||
<p class="desc">"¡ODOO Enterprise es imprescindible!"</p>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy" data-id="5">Comprar ahora</a>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="5">Comprar ahora</a>
|
||||
<ul>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Lance Odoo CE en 5 minutos</li>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Copias automáticas, sin acordarse</li>
|
||||
@@ -484,7 +486,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<p class="pricing-cta-note">Ahorre dinero, menos administración</p>
|
||||
<p class="pricing-cta-note"><a href="/odoo-hosting-2027.html"><strong>Compare todas las formas de alojar Odoo en 2027 →</strong></a></p>
|
||||
<p class="pricing-cta-note"><a href="/es/odoo-hosting-2027.html"><strong>Compare todas las formas de alojar Odoo en 2027 →</strong></a></p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -496,7 +498,7 @@
|
||||
<h2 class="ow-title" id="orderPlanTitle">On the Rise</h2>
|
||||
<p class="ow-price">
|
||||
<span class="ow-price-amount" id="orderPlanPrice">$ 395.00</span> <span id="orderPlanPeriod">/ año</span>
|
||||
<span class="ow-price-tax" id="orderPlanTax">+ impuestos</span>
|
||||
<span class="ow-price-tax" id="orderPlanTax">impuestos incluidos</span>
|
||||
</p>
|
||||
<p class="ow-coupon-msg" id="orderCouponMsg">¿Dudas antes de comprar? Pregunte al asistente en esta página.</p>
|
||||
<p class="ow-yearly-save" id="orderYearlySave">Facturación anual. Sin cuota de alta.</p>
|
||||
@@ -509,7 +511,7 @@
|
||||
<option value="Netherlands">Países Bajos (Amsterdam)</option>
|
||||
<option value="UK">Reino Unido (London)</option>
|
||||
</select>
|
||||
<a id="orderBuyBtn" href="/support.html#contact" class="btn btn-brass ow-buy">Continuar a Stripe →</a>
|
||||
<a id="orderBuyBtn" href="/es/support.html#contact" class="btn btn-brass ow-buy">Continuar a Stripe →</a>
|
||||
<p class="ow-note">🔒 Pago seguro con Stripe · Se requiere tarjeta para comprar, no para empezar.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -625,13 +627,14 @@
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Enlaces útiles</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/es/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/es/odoo-hosting-2027.html">ODOO Hosting en 2027</a></li>
|
||||
<li><a href="/es/support.html">Soporte</a></li>
|
||||
<li><a href="/legal.html">Aviso legal</a></li>
|
||||
@@ -671,7 +674,7 @@
|
||||
</footer>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
|
||||
<script src="/script.js"></script>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
<script src="/script.js?v=d2046e3469"></script>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,888 @@
|
||||
<!doctype html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Odoo Community Upgrade — gestionado para usted | ODOO4projects</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Un cambio de versión de Odoo Community explicado: qué cambia, qué se rompe, los comandos reales y cómo migramos su base de datos a nuestros servidores."
|
||||
/>
|
||||
<link rel="canonical" href="https://odoo4projects.com/es/odoo-community-upgrade.html" />
|
||||
<link rel="alternate" hreflang="en-US" href="https://odoo4projects.com/odoo-community-upgrade.html" />
|
||||
<link rel="alternate" hreflang="de" href="https://odoo4projects.com/de/odoo-community-upgrade.html" />
|
||||
<link rel="alternate" hreflang="es" href="https://odoo4projects.com/es/odoo-community-upgrade.html" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://odoo4projects.com/odoo-community-upgrade.html" />
|
||||
<meta property="og:title" content="Odoo Community Upgrade — gestionado para usted" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Qué cambia en un cambio de versión de Odoo Community, los comandos reales para el desarrollador y cómo trasladamos su base de datos a nuestros servidores."
|
||||
/>
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/es/odoo-community-upgrade.html" />
|
||||
<meta property="og:image" content="https://odoo4projects.com/images/hero/amsterdam.webp" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Odoo Community Upgrade — gestionado para usted" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Qué cambia en un cambio de versión de Odoo Community, los comandos reales para el desarrollador y cómo trasladamos su base de datos a nuestros servidores."
|
||||
/>
|
||||
<meta name="twitter:image" content="https://odoo4projects.com/images/hero/amsterdam.webp" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- Odoo Community Upgrade page (page-scoped; additive) ---- */
|
||||
.oc-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Top bar (page-scoped: the site has no global header) */
|
||||
.cmp-topbar {
|
||||
background: var(--midnight-2);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.85rem 0;
|
||||
}
|
||||
.cmp-topbar .container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.cmp-brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
}
|
||||
.cmp-brand span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar-links {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
font-size: 0.82rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
.cmp-topbar-links a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar-links a:hover {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar .lang-switch-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.45);
|
||||
}
|
||||
.cmp-topbar .lang-switch {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar .lang-switch a:hover,
|
||||
.cmp-topbar .lang-switch a:focus-visible {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.cmp-topbar .lang-switch a[aria-current="true"] {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* Hero — the same midnight lounge as the rest of the site, with our own
|
||||
Amsterdam photo behind the copy. */
|
||||
.oc-hero {
|
||||
min-height: 0;
|
||||
padding: 3.5rem 0 3rem;
|
||||
}
|
||||
.oc-hero .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.oc-hero h1 span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.oc-hero .hero-sub {
|
||||
max-width: 700px;
|
||||
}
|
||||
.oc-hero-img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
opacity: 0.25;
|
||||
filter: brightness(1.15) saturate(1.1);
|
||||
}
|
||||
|
||||
.oc-body {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.75;
|
||||
}
|
||||
.section-dark .oc-body {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.oc-body p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oc-body strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-dark .oc-body strong {
|
||||
color: #fff;
|
||||
}
|
||||
.oc-pull {
|
||||
max-width: 760px;
|
||||
margin: 2rem auto 0;
|
||||
padding-top: 1.25rem;
|
||||
border-top: 1px solid var(--line-brass);
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.05rem;
|
||||
color: var(--ink);
|
||||
text-align: center;
|
||||
}
|
||||
.section-dark .oc-pull {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
|
||||
/* Numbered process list */
|
||||
.oc-steps {
|
||||
max-width: 820px;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
counter-reset: oc-step;
|
||||
}
|
||||
.oc-steps li {
|
||||
position: relative;
|
||||
counter-increment: oc-step;
|
||||
padding: 0 0 1.4rem 3.2rem;
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
line-height: 1.7;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.25);
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.oc-steps li::before {
|
||||
content: counter(oc-step);
|
||||
position: absolute;
|
||||
left: -1.05rem;
|
||||
top: -0.15rem;
|
||||
width: 2.1rem;
|
||||
height: 2.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1rem;
|
||||
color: var(--midnight);
|
||||
background: var(--brass);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.oc-steps li strong {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.oc-steps li:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* Technical section: code cards + substitution notes */
|
||||
.oc-code {
|
||||
background: var(--midnight);
|
||||
border: 1px solid var(--line-brass);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1rem 1.15rem;
|
||||
margin: 1.1rem 0 0;
|
||||
overflow-x: auto;
|
||||
box-shadow: var(--shadow-rest);
|
||||
}
|
||||
.section-dark .oc-code {
|
||||
background: var(--midnight-2);
|
||||
}
|
||||
/* R1 moved the process list onto a light band and the technical section onto a
|
||||
dark one, so their text colours have to follow the band, not their old parent. */
|
||||
.section-light .oc-steps li {
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
.section-light .oc-steps li strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-dark .oc-sub h3 {
|
||||
color: var(--cream);
|
||||
}
|
||||
.section-dark .oc-sub > p,
|
||||
.section-dark .oc-note {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.section-dark .oc-note strong {
|
||||
color: #fff;
|
||||
}
|
||||
/* R3 puts the "See the plans" link inside the dark offer band. */
|
||||
.section-dark .oc-body a {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.oc-code code {
|
||||
display: block;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.7;
|
||||
color: #ece6da;
|
||||
white-space: pre;
|
||||
tab-size: 2;
|
||||
}
|
||||
.oc-note {
|
||||
margin: 0.9rem 0 0;
|
||||
padding: 0.15rem 0 0.15rem 1rem;
|
||||
border-left: 2px solid var(--brass);
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
}
|
||||
.oc-note p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oc-sub {
|
||||
margin-top: 2.25rem;
|
||||
}
|
||||
.oc-sub h3 {
|
||||
color: var(--ink);
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
.oc-sub > p {
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
/* FAQ */
|
||||
.cmp-faq-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cmp-faq {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.4rem 1.25rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
transition: box-shadow 0.25s;
|
||||
}
|
||||
.cmp-faq[open],
|
||||
.cmp-faq:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
.cmp-faq summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.85rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.98rem;
|
||||
color: var(--midnight);
|
||||
}
|
||||
.cmp-faq summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.cmp-faq summary::after {
|
||||
content: "+";
|
||||
font-family: Inter, sans-serif;
|
||||
color: var(--brass);
|
||||
font-size: 1.15rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
.cmp-faq[open] summary::after {
|
||||
content: "\2212";
|
||||
}
|
||||
.cmp-faq summary:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.cmp-faq .cmp-a {
|
||||
font-size: 0.87rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.cmp-faq .cmp-a p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.cmp-faq-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Final CTA band */
|
||||
.cmp-cta {
|
||||
text-align: center;
|
||||
}
|
||||
.cmp-cta .oc-lead {
|
||||
font-size: 1.1rem;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
max-width: 700px;
|
||||
margin: 0 auto 1.5rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
.cmp-cta-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.cmp-cta-actions .btn {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/* Focus states on every CTA */
|
||||
.btn:focus-visible,
|
||||
.cmp-topbar-links a:focus-visible {
|
||||
outline: 3px solid var(--brass-bright);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.btn-brass:focus-visible {
|
||||
outline-color: #fff;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.oc-hero {
|
||||
padding: 3rem 0 2.5rem;
|
||||
}
|
||||
.oc-steps li {
|
||||
padding-left: 2.6rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "WebPage",
|
||||
"@id": "https://odoo4projects.com/odoo-community-upgrade.html#webpage",
|
||||
"url": "https://odoo4projects.com/odoo-community-upgrade.html",
|
||||
"name": "Odoo Community Upgrade — gestionado para usted",
|
||||
"description": "Un cambio de versión de Odoo Community explicado: qué cambia, qué se rompe, los comandos reales y cómo migramos su base de datos a nuestros servidores.",
|
||||
"inLanguage": "es",
|
||||
"isPartOf": { "@id": "https://odoo4projects.com/#organization" }
|
||||
},
|
||||
{
|
||||
"@type": "Service",
|
||||
"name": "Migración de la base de datos de Odoo Community al hosting de ODOO4projects",
|
||||
"provider": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"url": "https://odoo4projects.com/odoo-community-upgrade.html"
|
||||
},
|
||||
{
|
||||
"@type": "FAQPage",
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "¿Es lo mismo un cambio de versión que una actualización?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No. Una actualización le da la última revisión del software que ya utiliza. Un cambio de versión lleva su base de datos a una nueva versión mayor (18 a 19, o 19 a 20) y transforma los propios datos. Es en un solo sentido: no existe una vuelta atrás con soporte, y no es un cambio de licencia, ni de edición, ni de hosting."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "¿Podemos pasar directamente de Odoo 14 a Odoo 20?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No. Se hace una versión mayor a la vez: 14 a 15 a 16 a 17 a 18 a 19 a 20. Saltarse una versión no es un camino con soporte. Nuestro propio servicio de migración documenta soporte para bases de datos en Odoo 17, 18 y 19, solo versiones principales, sin versiones de parche; las bases más antiguas necesitan antes una revisión de compatibilidad, que empieza con una incidencia de soporte."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "¿Qué pasa con mi historial: las facturas, los pagos, los archivos adjuntos?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Esa es la pregunta correcta, y la respuesta honesta es que depende de la ruta. La ruta de OpenUpgrade — una migración de versión ejecutada en su propio servidor — lleva la base de datos consigo y conserva el historial y los enlaces entre registros. La documentación de OpenUpgrade advierte de que la otra ruta, trasladar documentos a un sistema nuevo, recupera solo parte de sus datos y pierde el historial y los enlaces entre registros, por ejemplo las facturas de cada cliente. Nuestro servicio le construye una base de datos nueva y traslada sus datos a ella, así que la nuestra es la ruta por la que preguntar: antes de aprobar nada, pídanos que enumeremos exactamente qué registros estarán en la nueva base de datos y cuáles no. Preferimos que la haga a que la dé por supuesta."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "¿Seguirán funcionando mis módulos personalizados?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No por sí solos. Un módulo escrito para su negocio tiene que llevar su código a la versión de destino, y los cambios de nombre que de otro modo perderían datos necesitan sus propios scripts de migración. La documentación de Odoo es tajante al respecto: un cambio de versión queda bloqueado hasta que exista una versión de sus módulos personalizados para la versión a la que se muda. Los módulos que vienen con Odoo y los de la asociación de la comunidad traen sus propios scripts de migración; los suyos no, y alguien tiene que escribirlos."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "¿Cuánto cuesta y cuánto tarda?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No publicamos ni precio ni duración para el servicio de cambio de versión, y no vamos a inventarnos ninguno aquí. Lo que sí publicamos es cómo empieza: usted abre una incidencia de soporte, revisamos la compatibilidad de su base de datos y le respondemos. Si lo compara con hacerlo usted mismo, la comparación honesta no es el alquiler del servidor, sino sus propias horas, que nunca aparecen en esa factura."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "¿Necesito un desarrollador?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Para ejecutar los comandos de la sección técnica, sí; o alguien que se maneje en una terminal con PostgreSQL. Para que lo hagamos nosotros, no: de eso se trata el servicio. Usted envía la base de datos, nosotros montamos el sistema nuevo en nuestra infraestructura y usted recibe las credenciales."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "¿Puedo ver el sistema con la nueva versión antes de ponerlo en producción?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Sí, y debería hacerlo. Quien hace el trabajo migra primero una copia; esa es la primera regla de todo el proceso, tanto en la documentación de Odoo como en el proyecto OpenUpgrade. Y la copia migrada es lo que usted revisa antes de que le ocurra nada al sistema con el que funciona su negocio. Nuestro servicio sigue el mismo principio: montamos el sistema nuevo en nuestros propios servidores y usted lo compara con el antiguo."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Estamos alojados en otro sitio. ¿Pueden cambiar de versión igualmente?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Sí, exactamente para eso está nuestro servicio de migración. Usted abre una incidencia de soporte, le enviamos un formulario seguro para subir su base de datos, le montamos un servidor nuevo en nuestra infraestructura y le damos las credenciales. Bases de datos en Odoo 17, 18 y 19, solo versiones principales; las más antiguas, tras una revisión de compatibilidad."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="cmp-topbar">
|
||||
<div class="container">
|
||||
<a class="cmp-brand" href="/es/">ODOO4<span>projects</span></a>
|
||||
<nav class="cmp-topbar-links" aria-label="Enlaces de la página">
|
||||
<a href="/es/#pricing">Planes y precios</a>
|
||||
<a href="/es/support.html">Soporte</a>
|
||||
</nav>
|
||||
<div data-lang-switcher class="lang-switch-slot"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero oc-hero">
|
||||
<div class="hero-bg">
|
||||
<img
|
||||
class="oc-hero-img"
|
||||
src="/images/hero/amsterdam.webp"
|
||||
alt="Ámsterdam al atardecer — una de las seis regiones en las que funcionan nuestros servidores"
|
||||
width="1920"
|
||||
height="768"
|
||||
fetchpriority="high"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="container">
|
||||
<p class="hero-kicker">ODOO COMMUNITY UPGRADE</p>
|
||||
<h1><span>Odoo Community Upgrade</span>: qué cambia y cómo lo hacemos por usted</h1>
|
||||
<p class="hero-sub">
|
||||
Subir a una nueva versión mayor de Odoo no es una actualización: es un cambio en un solo sentido de su base de datos, y no es algo que quiera hacer mal. Aquí está cómo lo hacemos por usted — un sistema nuevo en nuestros propios servidores, el actual intacto mientras trabajamos — y, debajo, los comandos exactos que ejecutaría un desarrollador.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="/es/support.html#contact" class="btn btn-brass btn-lg">Abra una incidencia: díganos qué versión utiliza</a>
|
||||
<a href="/es/#pricing" class="btn btn-outline btn-lg">Ver los planes</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What an upgrade is -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">La diferencia que importa</p>
|
||||
<h2 class="section-title">Qué es realmente un cambio de versión de Odoo Community</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Odoo usa dos palabras que suenan igual y no lo son. Una <strong>actualización</strong> le da la última revisión del software que ya utiliza. Un <strong>cambio de versión</strong> lleva su base de datos a una nueva versión mayor (18 a 19, o 19 a 20) y transforma los propios datos. Es en un solo sentido: no existe una vuelta atrás con soporte, y no es un cambio de licencia, ni de edición, ni de proveedor de hosting.
|
||||
</p>
|
||||
<p>Hay tres cosas que conviene saber antes de que alguien toque su sistema.</p>
|
||||
<p>
|
||||
<strong>Se hace una versión mayor a la vez.</strong> Un salto de 17 a 20 son tres migraciones, no una: 17 → 18, 18 → 19, 19 → 20. Saltarse una versión no es un camino con soporte en ningún punto del ecosistema Odoo.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Se hace sobre una copia, nunca sobre la base de datos en producción.</strong> Todos los que han escrito sobre esto (la propia documentación de Odoo, el proyecto OpenUpgrade de la OCA y cada profesional que hemos visto) empiezan haciendo una copia de seguridad y trabajando sobre un duplicado. Lo que se rompe lo descubre en la copia, no delante de sus clientes.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Sus propias personalizaciones son la parte que da trabajo.</strong> Un módulo hecho para su negocio no se mueve solo: hay que llevar su código a la versión de destino, y los cambios de nombre que de otro modo perderían datos necesitan sus propios scripts de migración. La documentación de Odoo lo dice sin rodeos: un cambio de versión queda bloqueado hasta que exista una versión de sus módulos personalizados para la versión a la que se muda.
|
||||
</p>
|
||||
<p>
|
||||
Y luego la ruta en sí. Odoo vende una ruta de actualización para Enterprise; para Odoo Community, la respuesta de código abierto es el proyecto OpenUpgrade de la OCA. La documentación de OpenUpgrade afirma que Odoo Community Edition no da soporte a migraciones entre versiones mayores y deja constancia de que OpenUpgrade es la solución que el propio fundador de Odoo recomienda para ello. Es un proyecto real, mantenido por la asociación de la comunidad, y es la ruta que usará un desarrollador sobre una base de datos Community.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Our way -->
|
||||
<section class="section-dark" id="our-way">
|
||||
<div class="container">
|
||||
<p class="section-kicker">La forma de ODOO4projects</p>
|
||||
<h2 class="section-title">La forma de ODOO4projects: una base de datos nueva, y el trabajo lo hacemos nosotros</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
No tiene que hacer nada de esto usted mismo. Si su negocio funciona con Odoo Community y quiere cambiar de versión sin contratar a alguien que recorra la secuencia de esta página, esto es lo que hacemos nosotros.
|
||||
</p>
|
||||
<p>
|
||||
Usted abre una incidencia de soporte y nos cuenta qué tiene. Primero miramos su base de datos (su versión, sus personalizaciones, si es algo que podemos mover) y le decimos qué encontramos. Luego le enviamos un enlace a un formulario seguro donde sube su base de datos. Cuando la tenemos, le montamos un servidor nuevo en nuestra propia infraestructura y le entregamos las credenciales. Su sistema actual sigue funcionando todo el tiempo, porque no lo tocamos: trabajamos sobre la base de datos que nos envió y sobre el servidor nuevo que montamos.
|
||||
</p>
|
||||
<p>
|
||||
Si prefiere ver antes una cifra: qué plan necesita depende de los módulos que use, y los planes están aquí — <a href="/es/#pricing">Ver los planes</a>. El cambio de versión en sí no tiene precio en esa página; le respondemos después de haber mirado su base de datos.
|
||||
</p>
|
||||
<p>
|
||||
Ese último punto es toda la razón de hacerlo así. Con nuestro servicio no migra su base de datos en producción por la noche, después de cerrar. Está viendo un segundo sistema, en una versión nueva, con sus datos dentro, y puede comparar los dos antes de decidir nada.
|
||||
</p>
|
||||
<p>
|
||||
Nuestro servicio de migración documenta soporte para bases de datos en Odoo 17, 18 y 19, solo versiones principales; las versiones de parche como 18.1 o 17.2 no tienen soporte en ningún punto de nuestro servicio. Si su base de datos es anterior a la 17, también podemos ayudarle a llevarla a una versión con soporte, pero solo tras revisarla para comprobar la compatibilidad. Las instancias nuevas en nuestros servidores pueden crearse en Odoo 19 u Odoo 20, así que si se muda a la 20 en concreto, dígalo en la incidencia: la versión a la que va importa más que la versión en la que está.
|
||||
</p>
|
||||
<p>
|
||||
En el terreno de la IA, aquí hay un caso que hemos publicado de verdad. Copiar facturas a mano de una instancia de Odoo a otra es lento y fácil de hacer mal, así que lo hicimos con un flujo de trabajo: registros escritos desde un sistema Odoo 19 a un sistema Odoo 20 nuevo, impulsados por un flujo de automatización y un servidor MCP apuntando al sistema nuevo. Tres reglas lo hicieron seguro (el número y la fecha de la factura nunca cambian, el contacto se busca en lugar de suponerse, el producto se busca en lugar de suponerse) y una restricción firme: si falta un contacto o un producto, la ejecución falla de forma sonora en lugar de crear un casi duplicado. Antes de soltarlo sobre el resto, revisamos una factura de principio a fin: número, fecha, contacto y líneas de producto.
|
||||
</p>
|
||||
<p>
|
||||
Hay algo que no vamos a difuminar, porque es la diferencia entre nosotros y un vendedor. El servidor MCP que incluimos dentro de nuestra propia consola de gestión hace operaciones de hosting. Reinicia un servidor, sube un módulo, añade o comprueba un dominio, gestiona copias de seguridad y lee un archivo de registro; esa es la lista publicada, y es una comodidad real si usa un asistente de IA. No es un motor de migración de datos y no lo describimos como tal. El trabajo de importación de arriba se hizo con un flujo de automatización y un MCP de terceros; la IA hacía la parte tediosa y un humano la revisaba, justo como debe ser.
|
||||
</p>
|
||||
<p>
|
||||
Y el límite honesto, en palabras del proyecto que mejor lo conoce. La documentación de OpenUpgrade menciona la alternativa de exportar e importar y le pone precio sin rodeos: recupera solo parte de sus datos y, en particular, no obtiene el historial ni los enlaces entre registros, por ejemplo las facturas de cada cliente. Ese es el riesgo de cualquier ruta que traslade documentos a un sistema nuevo, y por eso, si toma esa ruta con nosotros, nos hace una pregunta antes de aprobar nada: qué registros estarán en la nueva base de datos y cuáles no. Preferimos que la haga a que la dé por supuesta.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Process -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">La ruta documentada</p>
|
||||
<h2 class="section-title">El proceso de cambio de versión, paso a paso</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Esta es la secuencia en la que coinciden la documentación de Odoo, el proyecto OpenUpgrade y los talleres grabados. Nada de esto es nuestro ni es secreto: es la ruta documentada, en el orden en que se hace.
|
||||
</p>
|
||||
</div>
|
||||
<ol class="oc-steps">
|
||||
<li>
|
||||
<strong>Haga una copia de seguridad de la base de datos y sepa dónde está el filestore.</strong> Antes que nada. La documentación del proyecto OpenUpgrade dice que debe hacer sin falta una copia de la base de datos en producción, y todo profesional empieza por aquí.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Trabaje sobre una copia.</strong> Restaure la copia en una base de datos de prueba y migre esa. Su sistema en producción queda intacto hasta que la copia funcione.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Ponga en marcha primero la versión de destino.</strong> Instale el Odoo más reciente y coloque el código de OpenUpgrade para la versión de destino en su ruta de add-ons, junto a los módulos que ya utiliza.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Adapte sus módulos personalizados.</strong> Lleve su código a la nueva versión antes de que se ejecute la migración.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Ejecute la migración sobre la copia.</strong> Un módulo a la vez, en orden de dependencias; cada uno ejecuta su pre-script, luego carga y luego su post-script.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Cuente con ejecutarla más de una vez.</strong> Esto es iterativo. En el taller grabado, el entorno (repositorios, ramas, la lista de módulos) es la parte que lleva tiempo; la ejecución de la migración en sí es rápida una vez que existe el entorno, y usted reinicia y vuelve a ejecutar hasta que el registro esté limpio.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Termine con una actualización simple.</strong> Ejecutar la actualización una vez más sin los parámetros de migración es lo que elimina el estado "incompatible" y deja la base de datos utilizable.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Compruebe por los datos, no por el número de versión.</strong> Abra la copia migrada y revise lo que importa: un cliente, un producto, un pedido, una factura, un pago. Así lo verifican los profesionales en pantalla.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Limpie después.</strong> Las tablas, columnas y vistas obsoletas que deja una migración cuestan rendimiento, así que se eliminan una vez que el sistema lleva un tiempo en marcha y nadie ha reportado un problema.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Después, pase a producción.</strong> Restaure la base de datos migrada donde corresponda, o haga que el cambio de versión se ejecute sobre la base de datos en producción en el momento que usted elija.
|
||||
</li>
|
||||
</ol>
|
||||
<p class="oc-pull">
|
||||
Esa es su forma honesta: la preparación es la parte larga, la migración en sí es la corta, y la copia es lo que se le permite romper.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Technical section -->
|
||||
<section class="section-dark" id="commands">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Para su desarrollador</p>
|
||||
<h2 class="section-title">Para su desarrollador: los comandos reales</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Si gestiona Odoo Community usted mismo y prefiere hacerlo en casa en lugar de dejárnoslo, estos son los comandos. Están citados de la documentación de la que proceden, y cada uno indica qué debe sustituir y de qué advierte esa fuente. Nada de lo que sigue lo hemos ejecutado nosotros contra su base de datos, y ningún comando publicado por nosotros se ejecuta en nuestros servidores: nuestro servicio empieza con una incidencia de soporte, no con una terminal.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="oc-sub">
|
||||
<h3>La plataforma de cambio de versión de Odoo</h3>
|
||||
<p>
|
||||
Odoo documenta una plataforma de cambio de versión que funciona para instalaciones on-premise desde la línea de comandos. La documentación de Odoo indica que los scripts de migración que ejecuta no son de código abierto y vienen con Enterprise; pero la plataforma en sí sí lleva a una nueva versión una base de datos autoalojada.
|
||||
</p>
|
||||
<pre class="oc-code"><code># upgraded TEST database
|
||||
python <(curl -s https://upgrade.odoo.com/upgrade) test -d <your db name> -t <target version>
|
||||
|
||||
# production upgrade
|
||||
python <(curl -s https://upgrade.odoo.com/upgrade) production -d <your db name> -t <target version>
|
||||
|
||||
# general help
|
||||
python <(curl -s https://upgrade.odoo.com/upgrade) --help</code></pre>
|
||||
<div class="oc-note">
|
||||
<p>
|
||||
<strong>Sustituya:</strong> <code><your db name></code> es la base de datos de la máquina desde la que ejecuta el comando, y <code><target version></code> es la versión a la que se muda — 17.0, 18.0 o 19.0, según el selector de versión de nuestra propia página de planes.
|
||||
</p>
|
||||
<p>
|
||||
Lo que la documentación de Odoo exige junto a esas tres líneas, porque de ello depende que funcionen: el script necesita los comandos Linux habituales presentes en la máquina; el usuario del sistema que lo ejecuta necesita acceso a su base de datos PostgreSQL (el entorno de cliente PostgreSQL estándar, como <code>.pgpass</code>); y la máquina debe alcanzar la plataforma de cambio de versión en TCP 443 y en un puerto del rango 32768-60999, así que puede hacer falta una excepción en el cortafuegos. La copia que sube se envía sin filestore, así que hay que fusionar el filestore de producción en la base de datos actualizada antes de probarla. La descarga contiene <code>dump.sql</code> y una carpeta de filestore, y solo quien solicitó el cambio de versión puede descargar el resultado.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oc-sub">
|
||||
<h3>La ruta Community: OCA OpenUpgrade</h3>
|
||||
<pre class="oc-code"><code># 1. OpenUpgrade for the TARGET version (the branch is the target major version)
|
||||
git clone --depth 1 --branch <TARGET>.0 https://github.com/OCA/OpenUpgrade.git
|
||||
|
||||
# 2. helper library — the line the OpenUpgrade docs use
|
||||
pip install "git+https://github.com/OCA/openupgradelib.git@master#egg=openupgradelib"
|
||||
|
||||
# 3. put the clone on the add-ons path of the <TARGET> Odoo config
|
||||
# addons_path = <your own addons>,</abs/path>/OpenUpgrade
|
||||
|
||||
# 4. migrate the copy of the database
|
||||
<odoo-bin> -c /etc/odoo/<TARGET>.conf \
|
||||
-d <DB> \
|
||||
--upgrade-path=/abs/path/OpenUpgrade/openupgrade_scripts/scripts \
|
||||
-u all --stop-after-init \
|
||||
--load=base,web,openupgrade_framework
|
||||
|
||||
# 5. finish: a plain update, no migration parameters
|
||||
<odoo-bin> -c /etc/odoo/<TARGET>.conf -d <DB> -u all --stop-after-init</code></pre>
|
||||
<div class="oc-note">
|
||||
<p>
|
||||
<strong>Sustituya cuatro cosas:</strong> <code><TARGET></code> es la versión mayor de destino (17, 18 o 19 — no la versión de la que viene); <code><DB></code> es la copia que migra, nunca la base de datos en producción; <code><odoo-bin></code> es el binario de la versión de destino, y cómo se llama depende de cómo instaló Odoo (<code>odoo-bin</code>, <code>odoo</code> o el equivalente de Docker); y ambas rutas absolutas son suyas — la ruta de add-ons y la ubicación del clon de OpenUpgrade.
|
||||
</p>
|
||||
<p>
|
||||
Dos detalles que conviene llevarse de la documentación del propio proyecto: la parte <code>openupgrade_framework</code> de ese comando es un conjunto de parches que, entre otras cosas, impide que Odoo elimine las columnas y tablas de campos que ya no existen — una de las formas en que una migración pierde datos. Y la variable de entorno <code>OPENUPGRADE_USE_DEMO=yes</code> conserva los datos de demostración en la base de datos migrada cuando usted los quiere.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oc-sub">
|
||||
<h3>Sus módulos personalizados</h3>
|
||||
<pre class="oc-code"><code># Odoo's own code-rewrite command (it runs the scripts in odoo/upgrade_code)
|
||||
<odoo-bin> upgrade_code --from <FROM> --to <TO> --dry-run</code></pre>
|
||||
<div class="oc-note">
|
||||
<p>
|
||||
<strong>Sustituya</strong> <code><FROM></code> y <code><TO></code> por las dos versiones mayores (18 y 19, por ejemplo). Ejecútelo primero con <code>--dry-run</code>. La propia referencia de comandos de Odoo llama a este comando una herramienta de "mejor esfuerzo" y advierte de que "no son balas de plata": reescribe lo que puede y le deja una lista de lo que un humano todavía tiene que cambiar. El equivalente de la comunidad OpenUpgrade para el código de módulos es <code>odoo-module-migrator</code>, que registra INFO para los cambios automáticos, WARNING para lo que hay que revisar y ERROR para lo que no funcionará en absoluto. Ambas herramientas informan; ninguna piensa.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oc-sub">
|
||||
<h3>Copias de seguridad y el filestore</h3>
|
||||
<pre class="oc-code"><code># stop the service while you work (packaged install; the Odoo docs show this pattern)
|
||||
sudo service odoo<TARGET> stop
|
||||
|
||||
# database dump (PostgreSQL's own tool)
|
||||
sudo -u postgres pg_dump -Fc -d <DB> -f /path/backup/<DB>.dump
|
||||
|
||||
# restore a dump into a fresh database
|
||||
sudo -u postgres createdb -O <DB_OWNER> <DB_NEW>
|
||||
sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
|
||||
# the filestore lives under Odoo's data directory:
|
||||
# default on Unix: $XDG_DATA_HOME or ~/.local/share/Odoo or /var/lib/Odoo
|
||||
# filestore path: <data_dir>/filestore/<DB></code></pre>
|
||||
<div class="oc-note">
|
||||
<p>
|
||||
<strong>Sustituya</strong> los nombres de las bases de datos, el propietario, la ruta de copia y el directorio de datos del filestore por los suyos; el filestore es lo que contiene los archivos adjuntos y documentos a los que apuntan sus registros, y una base de datos restaurada sin él es una base de datos a la que le faltan archivos. Son los procedimientos documentados de PostgreSQL y de Odoo, no los nuestros: no publicamos un comando que se ejecute en nuestros servidores, porque nuestro servicio empieza con una incidencia.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Self-hosting cost -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Trabajo propio</p>
|
||||
<h2 class="section-title">Lo que de verdad cuesta hacerlo usted mismo</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Un servidor alquilado es barato. Esa es la cifra más pequeña de esta decisión. Odoo Community en sí es gratis: no encontrará una licencia por usuario en ninguna parte de esta ruta, porque Community no la tiene.
|
||||
</p>
|
||||
<p>
|
||||
Lo que no está en esa cifra es la persona. Un cambio de versión en su propio servidor significa que alguien instala la versión nueva, coloca el código de migración en la ruta correcta, adapta los módulos que su negocio usa de verdad, ejecuta la migración hasta que el registro deja de quejarse, comprueba que los clientes, los pedidos y las facturas siguen ahí, limpia lo que dejó la migración y luego lo repite en la base de datos en producción en un momento que le venga bien al negocio. La propia documentación de Odoo dice que la actualización la hace mejor quien instaló Odoo en su día. En un servidor alquilado, esa persona es usted o alguien a quien paga por horas, y ninguna de esas líneas aparece en la factura. Esa es la mitad de la cuenta que nadie imprime, y la mitad que acaba en sus noches.
|
||||
</p>
|
||||
<p>
|
||||
No vamos a poner una cifra a sus horas, porque no las hemos medido y una cifra de marketing sería peor que ninguna. Lo que sí diremos es la parte que no va realmente de dinero: mientras hace ese trabajo, no hace el trabajo por el que le pagan, y si la migración está mal, se entera por un cliente.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section class="section-dark" id="faq">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Respuestas claras</p>
|
||||
<h2 class="section-title">Preguntas sobre el cambio de versión</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">¿Es lo mismo un cambio de versión que una actualización?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
No. Una actualización le da la última revisión del software que ya utiliza. Un cambio de versión lleva su base de datos a una nueva versión mayor (18 a 19, o 19 a 20) y transforma los propios datos. Es en un solo sentido: no existe una vuelta atrás con soporte, y no es un cambio de licencia, ni de edición, ni de hosting.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">¿Podemos pasar directamente de Odoo 14 a Odoo 20?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
No. Se hace una versión mayor a la vez: 14 a 15 a 16 a 17 a 18 a 19 a 20. Saltarse una versión no es un camino con soporte. Nuestro propio servicio de migración documenta soporte para bases de datos en Odoo 17, 18 y 19, solo versiones principales, sin versiones de parche; las bases más antiguas necesitan antes una revisión de compatibilidad, que empieza con una incidencia de soporte.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">¿Qué pasa con mi historial: las facturas, los pagos, los archivos adjuntos?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Esa es la pregunta correcta, y la respuesta honesta es que depende de la ruta. La ruta de OpenUpgrade — una migración de versión ejecutada en su propio servidor — lleva la base de datos consigo y conserva el historial y los enlaces entre registros. La documentación de OpenUpgrade advierte de que la otra ruta, trasladar documentos a un sistema nuevo, recupera solo parte de sus datos y pierde el historial y los enlaces entre registros, por ejemplo las facturas de cada cliente. Nuestro servicio le construye una base de datos nueva y traslada sus datos a ella, así que la nuestra es la ruta por la que preguntar: antes de aprobar nada, pídanos que enumeremos exactamente qué registros estarán en la nueva base de datos y cuáles no. Preferimos que la haga a que la dé por supuesta.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">¿Seguirán funcionando mis módulos personalizados?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
No por sí solos. Un módulo escrito para su negocio tiene que llevar su código a la versión de destino, y los cambios de nombre que de otro modo perderían datos necesitan sus propios scripts de migración. La documentación de Odoo es tajante al respecto: un cambio de versión queda bloqueado hasta que exista una versión de sus módulos personalizados para la versión a la que se muda. Los módulos que vienen con Odoo y los de la asociación de la comunidad traen sus propios scripts de migración; los suyos no, y alguien tiene que escribirlos.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">¿Cuánto cuesta y cuánto tarda?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
No publicamos ni precio ni duración para el servicio de cambio de versión, y no vamos a inventarnos ninguno aquí. Lo que sí publicamos es cómo empieza: usted abre una incidencia de soporte, revisamos la compatibilidad de su base de datos y le respondemos. Si lo compara con hacerlo usted mismo, la comparación honesta no es el alquiler del servidor, sino sus propias horas, que nunca aparecen en esa factura.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">¿Necesito un desarrollador?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Para ejecutar los comandos de la sección técnica, sí; o alguien que se maneje en una terminal con PostgreSQL. Para que lo hagamos nosotros, no: de eso se trata el servicio. Usted envía la base de datos, nosotros montamos el sistema nuevo en nuestra infraestructura y usted recibe las credenciales.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">¿Puedo ver el sistema con la nueva versión antes de ponerlo en producción?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Sí, y debería hacerlo. Quien hace el trabajo migra primero una copia; esa es la primera regla de todo el proceso, tanto en la documentación de Odoo como en el proyecto OpenUpgrade. Y la copia migrada es lo que usted revisa antes de que le ocurra nada al sistema con el que funciona su negocio. Nuestro servicio sigue el mismo principio: montamos el sistema nuevo en nuestros propios servidores y usted lo compara con el antiguo.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Estamos alojados en otro sitio. ¿Pueden cambiar de versión igualmente?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Sí, exactamente para eso está nuestro servicio de migración. Usted abre una incidencia de soporte, le enviamos un formulario seguro para subir su base de datos, le montamos un servidor nuevo en nuestra infraestructura y le damos las credenciales. Bases de datos en Odoo 17, 18 y 19, solo versiones principales; las más antiguas, tras una revisión de compatibilidad.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Final CTA band -->
|
||||
<section class="section-dark cmp-cta" id="start">
|
||||
<div class="container">
|
||||
<p class="oc-lead">
|
||||
Usted abre una incidencia de soporte, revisamos la compatibilidad de su base de datos y le respondemos.
|
||||
</p>
|
||||
<div class="cmp-cta-actions">
|
||||
<a href="/es/support.html#contact" class="btn btn-brass btn-lg">Abra una incidencia: díganos qué versión utiliza</a>
|
||||
<a href="/es/#pricing" class="btn btn-outline btn-lg">Ver los planes</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Enlaces útiles</h4>
|
||||
<ul>
|
||||
<li><a href="/es/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/es/odoo-hosting-2027.html">ODOO Hosting en 2027</a></li>
|
||||
<li><a href="/es/support.html">Soporte</a></li>
|
||||
<li><a href="/legal.html">Aviso legal</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Socios</h4>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
<a href="https://OD8N.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OD8N</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>Sobre nosotros</h4>
|
||||
<p>Creamos soluciones de negocio inteligentes y escalables combinando la <strong>estabilidad</strong> de Odoo ERP con la <strong>potencia</strong> de los agentes de IA y las automatizaciones N8N.</p>
|
||||
<p>Desde unas ventas ágiles hasta despliegues globales, nuestro enfoque <strong>lean y ecológico</strong> ayuda a las empresas a reducir costes, ganar eficiencia y crecer sin límites.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Síganos</h4>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="oc-sr-only" for="footerContactEmail">Su dirección de correo</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Su dirección de correo" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
<label class="oc-sr-only" for="footerContactText">Su mensaje</label>
|
||||
<textarea id="footerContactText" name="message" placeholder="Su mensaje..." required></textarea>
|
||||
<button type="submit" class="footer-send-btn" aria-label="Enviar mensaje"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M2 21l21-9L2 3v7l15 2-15 2z" /></svg></button>
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -31,8 +31,9 @@
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
||||
<link rel="preload" as="image" href="/images/hero/bootcamp-hero-mobile-900.webp" media="(max-width: 640px)" fetchpriority="high" />
|
||||
<link rel="preload" as="image" href="/images/hero/bootcamp-hero-desktop-1920.webp" media="(min-width: 641px)" fetchpriority="high" />
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- ODOO ERP Automation Bootcamp landing page (page-scoped; additive) ---- */
|
||||
.bc-sr-only {
|
||||
@@ -192,6 +193,14 @@
|
||||
form[action$="/shop/post_basket"] .btn {
|
||||
line-height: inherit;
|
||||
}
|
||||
/* At 0 seats /static/bootcamp-availability.js disables these Buy buttons; make the
|
||||
disabled state read as disabled — quiet dimming in the page's own CI, never an
|
||||
alert banner. */
|
||||
form[action$="/shop/post_basket"] .btn:disabled,
|
||||
form[action$="/shop/post_basket"] .btn[aria-disabled="true"] {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Grids — auto-fit so no breakpoint is needed */
|
||||
.bc-list {
|
||||
@@ -223,7 +232,7 @@
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-rest);
|
||||
padding: 1.4rem 1.4rem 1.4rem 3.4rem;
|
||||
transition: box-shadow 0.25s, transform 0.25s;
|
||||
transition: transform 0.25s; /* box-shadow kept, not transitioned (non-composited) */
|
||||
}
|
||||
.bc-lessons li:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
@@ -313,7 +322,7 @@
|
||||
.bc-schedule dt {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.92rem;
|
||||
color: var(--brass-deep);
|
||||
color: #876c1e; /* 4.68:1 on --ivory (was --brass-deep 4.49:1) */
|
||||
}
|
||||
.bc-schedule dd {
|
||||
margin: 0;
|
||||
@@ -452,6 +461,109 @@
|
||||
.btn-brass:focus-visible {
|
||||
outline-color: #fff;
|
||||
}
|
||||
/* Waiting list — for someone who cannot attend the January cohort.
|
||||
Deliberately quieter than the Buy button: outline button, smaller type, no brass fill. */
|
||||
.bc-waitlist {
|
||||
/* Component-scoped error colour: the site has no shared token for it. */
|
||||
--wl-error: #b02a37;
|
||||
max-width: 720px;
|
||||
margin: 2.5rem auto 0;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: var(--ivory);
|
||||
text-align: left;
|
||||
}
|
||||
.bc-wl-title {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 1.1rem;
|
||||
color: var(--ink);
|
||||
}
|
||||
.bc-wl-lead {
|
||||
margin: 0 0 1.1rem;
|
||||
font-size: 0.88rem;
|
||||
line-height: 1.6;
|
||||
color: rgba(23, 28, 38, 0.78); /* the page's own .bc-note value, on the same cream */
|
||||
}
|
||||
.bc-wl-form input,
|
||||
.bc-wl-form textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 0.6rem;
|
||||
padding: 0.6rem 0.75rem;
|
||||
font-family: Inter, sans-serif;
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink);
|
||||
background: #fff;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.bc-wl-form textarea {
|
||||
min-height: 3.4rem;
|
||||
resize: vertical;
|
||||
}
|
||||
.bc-wl-btn {
|
||||
padding: 0.6rem 1.5rem;
|
||||
font-size: 0.8rem;
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
border-color: rgba(23, 28, 38, 0.35);
|
||||
}
|
||||
.bc-wl-btn:hover {
|
||||
border-color: var(--brass);
|
||||
background: rgba(201, 162, 39, 0.12);
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.bc-wl-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
.bc-wl-success {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: var(--success);
|
||||
}
|
||||
.bc-wl-error {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--wl-error);
|
||||
}
|
||||
|
||||
/* --- 2026-11-02 PageSpeed pass (page-scoped, additive) ---------------------
|
||||
1. The footer <h4>s became <h3>s so the heading order descends after the last
|
||||
section h2 (a11y "heading-order"); these rules keep their look identical to
|
||||
the shared .footer h4 in /style.css.
|
||||
2. A link inside an on-dark note is the lighter brass (7.15:1 on midnight,
|
||||
A11y "color-contrast") and underlined, so it is distinguishable without
|
||||
colour (A11y "link-in-text-block"). */
|
||||
.footer h3 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
color: #fff;
|
||||
margin-bottom: 0.8rem;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
.bc-note.on-dark a {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
}
|
||||
/* the footer copyright line at .35 alpha was 3.2:1 on midnight */
|
||||
.footer .fcopy {
|
||||
color: rgba(255, 255, 255, 0.5); /* 5.17:1 */
|
||||
}
|
||||
/* no-JS footer fallback (rendered only when JavaScript is off) */
|
||||
.footer .bc-noscript {
|
||||
margin-top: 0.6rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.footer .bc-noscript a {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
@@ -482,8 +594,9 @@
|
||||
"@type": "CourseInstance",
|
||||
"courseMode": "online",
|
||||
"courseWorkload": "PT1H",
|
||||
"startDate": "2026-01-22",
|
||||
"endDate": "2026-03-26",
|
||||
"maximumAttendeeCapacity": 6,
|
||||
"startDate": "2027-01-21",
|
||||
"endDate": "2027-03-25",
|
||||
"instructor": {
|
||||
"@type": "Person",
|
||||
"name": "Oliver Arnold",
|
||||
@@ -500,7 +613,7 @@
|
||||
},
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "465.00",
|
||||
"price": "595.00",
|
||||
"priceCurrency": "USD",
|
||||
"category": "Paid",
|
||||
"url": "https://odoo4projects.com/odoo-erp-automation-bootcamp/"
|
||||
@@ -554,12 +667,18 @@
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="bc-topbar">
|
||||
<div class="container">
|
||||
<a class="bc-brand" href="/">ODOO4<span>projects</span></a>
|
||||
<a class="bc-brand" href="/es/">ODOO4<span>projects</span></a>
|
||||
<nav class="bc-topbar-links" aria-label="Enlaces de página">
|
||||
<a href="/es/#pricing">Planes y precios</a>
|
||||
<a href="/es/support.html">Soporte</a>
|
||||
@@ -569,9 +688,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero bc-hero">
|
||||
<div class="container">
|
||||
<p class="hero-kicker">Q1 2026 · 10 SESIONES EN DIRECTO · OLIVER ARNOLD</p>
|
||||
<p class="hero-kicker">Q1 2027 · 10 SESIONES EN DIRECTO · OLIVER ARNOLD</p>
|
||||
<h1>ODOO ERP Automation Bootcamp</h1>
|
||||
<p class="hero-sub">
|
||||
Sin programar. Sin servidor que instalar. Si lleva su negocio con una hoja de cálculo, esto también es para usted.
|
||||
@@ -579,19 +699,26 @@
|
||||
<div class="hero-stats">
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> 10 sesiones en directo, de una hora cada una</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Jueves, 18:00–19:00, hora del centro de EE. UU.</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Empieza el jueves 22 de enero de 2026</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Empieza el jueves 21 de enero de 2027</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Un año de Odoo Community Edition incluido</span>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<input type="hidden" name="basket" value='[{"product_id":12,"qty":1}]' />
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":17,"qty":1,"info":"Q1 2027, English"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Comprar por 465.00 USD</button>
|
||||
<button type="submit" class="btn btn-brass btn-lg">Comprar por 595.00 USD</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Live remaining-seat count, immediately below the hero. One seat element only on
|
||||
the page; /static/bootcamp-availability.js fills it from the availability webhook
|
||||
and leaves it empty+hidden if that fetch fails. -->
|
||||
<div class="container">
|
||||
<p class="bc-note bc-seats" data-bc-seats hidden></p>
|
||||
</div>
|
||||
|
||||
<!-- From zero to a running ERP -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
@@ -604,10 +731,10 @@
|
||||
</p>
|
||||
<p class="bc-subline">Tres meses. Diez horas de clases. Un sistema que dirige su empresa.</p>
|
||||
<div class="bc-action">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<input type="hidden" name="basket" value='[{"product_id":12,"qty":1}]' />
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":17,"qty":1,"info":"Q1 2027, English"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Comprar por 465.00 USD</button>
|
||||
<button type="submit" class="btn btn-brass btn-lg">Comprar por 595.00 USD</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -720,22 +847,24 @@
|
||||
<dt>Sesiones</dt>
|
||||
<dd>10, todos los jueves de 18:00–19:00, hora del centro de EE. UU.</dd>
|
||||
<dt>Periodo</dt>
|
||||
<dd>Q1 2026</dd>
|
||||
<dd>Q1 2027</dd>
|
||||
<dt>Primera sesión</dt>
|
||||
<dd>Jueves 22 de enero de 2026</dd>
|
||||
<dd>Jueves 21 de enero de 2027</dd>
|
||||
<dt>Última sesión</dt>
|
||||
<dd>Jueves 26 de marzo de 2026</dd>
|
||||
<dd>Jueves 25 de marzo de 2027</dd>
|
||||
<dt>Fechas</dt>
|
||||
<dd>22 de enero · 29 de enero · 5 de febrero · 12 de febrero · 19 de febrero · 26 de febrero · 5 de marzo · 12 de marzo · 19 de marzo · 26 de marzo de 2026</dd>
|
||||
<dd>21 de enero · 28 de enero · 4 de febrero · 11 de febrero · 18 de febrero · 25 de febrero · 4 de marzo · 11 de marzo · 18 de marzo · 25 de marzo de 2027</dd>
|
||||
<dt>Duración</dt>
|
||||
<dd>1 hora por sesión, 10 horas en total</dd>
|
||||
<dt>Dónde</dt>
|
||||
<dd>En directo y online</dd>
|
||||
<dt>Tamaño del grupo</dt>
|
||||
<dd>Limitado a 6 participantes</dd>
|
||||
<dt>Instructor</dt>
|
||||
<dd>Oliver - The OC Guy - Arnold, Technical Lead de ODOO4projects</dd>
|
||||
</dl>
|
||||
<p class="bc-note">
|
||||
La hora del centro de EE. UU. está en UTC−6 hasta el 8 de marzo y después en UTC−5; las invitaciones de calendario llevan la hora local correcta.
|
||||
La hora del centro de EE. UU. está en UTC−6 hasta el 14 de marzo y después en UTC−5; las invitaciones de calendario llevan la hora local correcta.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -760,17 +889,37 @@
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Precio y reserva</h2>
|
||||
<p class="bc-price">El programa cuesta USD 465.00 por las diez sesiones.</p>
|
||||
<p class="bc-price">El programa cuesta USD 595.00 por las diez sesiones.</p>
|
||||
<p class="bc-note"><strong>Limitado a 6 participantes</strong> — el grupo es reducido, para que el instructor pueda trabajar sobre su propia configuración.</p>
|
||||
<p class="bc-note">Una plaza se puede <strong>transferir en cualquier momento</strong> y <strong>cancelar hasta dos semanas antes</strong> de la primera sesión, el 21 de enero de 2027.</p>
|
||||
<p class="bc-lead">
|
||||
Cubre el programa completo: diez sesiones en directo, un año de Odoo Community Edition alojado, la comunidad de antiguos alumnos y la revisión experta.
|
||||
</p>
|
||||
<div class="bc-action">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<input type="hidden" name="basket" value='[{"product_id":12,"qty":1}]' />
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":17,"qty":1,"info":"Q1 2027, English"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Comprar por 465.00 USD</button>
|
||||
<button type="submit" class="btn btn-brass btn-lg">Comprar por 595.00 USD</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Waiting list: for a visitor who cannot attend the January cohort.
|
||||
Secondary to the Buy button above. Same CRM webhook and same payload shape as the
|
||||
site's footer contact form (area:'message'); the copy lives here, in the page's
|
||||
language, and /static/bootcamp-waitlist.js carries no strings. -->
|
||||
<div class="bc-waitlist">
|
||||
<h3 class="bc-wl-title">¿Otra zona horaria u otro idioma?</h3>
|
||||
<p class="bc-wl-lead">El grupo de enero se reúne los jueves, 18:00–19:00, hora del centro de EE. UU., en inglés. Si necesita otro horario u otro idioma, apúntese a la lista de espera y le escribiremos cuando se abra un grupo que le encaje.</p>
|
||||
<form id="bcWaitlistForm" class="bc-wl-form" action="https://n8n.odoo4projects.com/webhook/ODOO4projects/crm" method="post" enctype="text/plain">
|
||||
<label class="bc-sr-only" for="bcWaitlistEmail">Su dirección de correo electrónico</label>
|
||||
<input type="email" id="bcWaitlistEmail" name="email" placeholder="Su dirección de correo electrónico" required />
|
||||
<label class="bc-sr-only" for="bcWaitlistComment">Qué zona horaria o idioma necesita</label>
|
||||
<textarea id="bcWaitlistComment" name="comment" rows="2" placeholder="¿Qué zona horaria o idioma necesita?" required></textarea>
|
||||
<button type="submit" class="btn bc-wl-btn" data-sending="Apuntando…">Apuntarme a la lista de espera</button>
|
||||
</form>
|
||||
<p class="bc-wl-success" id="bcWaitlistSuccess" role="status" style="display:none">Está en la lista de espera. Le escribiremos en cuanto se anuncie un grupo en su zona horaria o idioma.</p>
|
||||
<p class="bc-wl-error" id="bcWaitlistError" role="alert" style="display:none">Algo ha fallado. Inténtelo de nuevo.</p>
|
||||
</div>
|
||||
<ul class="bc-related">
|
||||
<li><a href="/es/support.html#contact">¿Preguntas antes de reservar? Hable antes con nosotros</a></li>
|
||||
<li><a href="/es/odoo-hosting-2027.html">Cómo es el hosting después de su año con nosotros</a></li>
|
||||
@@ -786,31 +935,31 @@
|
||||
<h2 class="section-title">Preguntas que suelen surgir primero</h2>
|
||||
<div class="bc-faq-grid">
|
||||
<details class="bc-faq">
|
||||
<summary>¿Necesito conocimientos técnicos?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Necesito conocimientos técnicos?</summary>
|
||||
<div class="bc-a">
|
||||
<p>No. Las sesiones no exigen conocimientos de ERP ni de programación, y usted trabaja con sus propios datos en lugar de seguir una demostración vacía.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>¿Y si me pierdo una sesión?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Y si me pierdo una sesión?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Las sesiones son en directo y cada una se apoya en la anterior, así que asista siempre que pueda. Si se pierde una, el chat de antiguos alumnos y el taller abierto de la última sesión son el lugar para ponerse al día.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>¿El hosting está incluido después del curso?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿El hosting está incluido después del curso?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Sí, durante un año, incluido en el programa. Pasado ese año, su sistema pasa a uno de nuestros planes de hosting habituales, al precio publicado en nuestro sitio.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>¿Qué necesito instalar?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Qué necesito instalar?</summary>
|
||||
<div class="bc-a">
|
||||
<p>No hay nada que instalar ni nada que ejecutar usted mismo. Bastan un ordenador y un navegador, el sistema en funcionamiento lo ponemos nosotros. n8n, que se usa en la lección 9, es una cuenta gratuita que usted abre con el propio plan gratuito de n8n.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>¿Es un curso sobre Odoo?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Es un curso sobre Odoo?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Es un curso sobre su negocio en marcha. Odoo es el motor que hay bajo el sistema que construye; las diez lecciones tratan de su inventario, sus facturas, sus clientes y las horas que esto le devuelve.</p>
|
||||
</div>
|
||||
@@ -818,6 +967,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
@@ -825,16 +975,16 @@
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Enlaces útiles</h4>
|
||||
<h3>Enlaces útiles</h3>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/es/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/es/odoo-hosting-2027.html">ODOO Hosting en 2027</a></li>
|
||||
<li><a href="/es/support.html">Soporte</a></li>
|
||||
<li><a href="/legal.html">Aviso legal</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Socios</h4>
|
||||
<h3>Socios</h3>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
@@ -842,17 +992,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>Sobre nosotros</h4>
|
||||
<h3>Sobre nosotros</h3>
|
||||
<p>Creamos soluciones de negocio inteligentes y escalables combinando la <strong>estabilidad</strong> de Odoo ERP con la <strong>potencia</strong> de los agentes de IA y las automatizaciones N8N.</p>
|
||||
<p>Desde unas ventas ágiles hasta despliegues globales, nuestro <strong>lean y ecológico</strong> enfoque ayuda a las empresas a reducir costes, ganar eficiencia y crecer sin límites.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Síganos</h4>
|
||||
<h3>Síganos</h3>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:hello@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<form class="footer-contact-form" id="footerContactForm" action="https://n8n.odoo4projects.com/webhook/ODOO4projects/crm" method="post" enctype="text/plain" data-ok="¡Gracias! Le responderemos en breve." data-err="Algo ha fallado. Inténtelo de nuevo.">
|
||||
<label class="bc-sr-only" for="footerContactEmail">Su dirección de correo</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Su dirección de correo" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
@@ -862,12 +1012,15 @@
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
<noscript><p class="bc-noscript">JavaScript está desactivado. Escríbanos directamente a <a href="mailto:support@odoo4projects.com">support@odoo4projects.com</a>.</p></noscript>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script defer src="/static/buy.js"></script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/buy.js?v=31314de600"></script>
|
||||
<script defer src="/static/bootcamp-availability.js?v=94dfd8cd7c"></script>
|
||||
<script defer src="/static/bootcamp-waitlist.js?v=6c2e2fbd33"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -31,8 +31,7 @@
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- Odoo Hosting 2027 landing page (page-scoped; additive) ---- */
|
||||
.cmp-sr-only {
|
||||
@@ -479,7 +478,7 @@
|
||||
{
|
||||
"@type": "Product",
|
||||
"name": "Hosting gestionado de Odoo Community",
|
||||
"description": "Hosting gestionado de Odoo Community: el servidor, las copias de seguridad, el certificado SSL y las actualizaciones de versión corren por nuestra cuenta a un precio anual, sin licencia por usuario en Odoo Community.",
|
||||
"description": "Hosting gestionado de Odoo Community: el servidor, las copias de seguridad y el certificado SSL corren por nuestra cuenta, y mantenemos su Odoo al día dentro de su versión, a un precio anual, sin licencia por usuario en Odoo Community. Cambiar a una nueva versión mayor es una migración y se presupuesta por separado.",
|
||||
"brand": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"offers": [
|
||||
{
|
||||
@@ -560,7 +559,7 @@
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
@@ -576,6 +575,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero cmp-hero">
|
||||
<div class="container">
|
||||
<p class="hero-kicker">Hosting de Odoo Community totalmente gestionado</p>
|
||||
@@ -583,7 +583,7 @@
|
||||
<p class="hero-sub">
|
||||
Un sistema Odoo Community gestionado: su inventario, sus pedidos, sus facturas y sus clientes en un
|
||||
solo sistema. Nosotros nos ocupamos del servidor, las copias de seguridad, el certificado y las
|
||||
actualizaciones. Usted introduce sus datos y se dedica a su negocio.
|
||||
actualizaciones dentro de su versión de Odoo. Usted introduce sus datos y se dedica a su negocio.
|
||||
</p>
|
||||
<div class="hero-stats">
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Unos 5 minutos hasta tener el sistema funcionando</span>
|
||||
@@ -606,8 +606,10 @@
|
||||
<p class="cmp-lead">
|
||||
No debería tener que convertirse en el departamento de informática para saber qué hay en su
|
||||
inventario. Un sistema de gestión se contrata como un servicio, no se construye como un proyecto. El
|
||||
servidor, los parches, las copias de seguridad, el certificado, la actualización de versión: eso es
|
||||
servidor, los parches, las copias de seguridad, el certificado, las actualizaciones dentro de su versión de Odoo: eso es
|
||||
nuestro trabajo, de forma permanente, y no una tarde que usted le devuelve a su empresa.
|
||||
Llevar la base de datos a una nueva versión mayor es una migración que
|
||||
presupuestamos por separado.
|
||||
</p>
|
||||
<p class="cmp-lead">
|
||||
Por eso reunimos su inventario, sus pedidos, sus facturas y quién le debe dinero en un solo lugar, y
|
||||
@@ -704,7 +706,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Actualizaciones de versión</th>
|
||||
<td class="is-us">Un ticket de soporte. Migramos las versiones 17, 18 y 19.</td>
|
||||
<td class="is-us">Las actualizaciones y las mejoras dentro de su versión están incluidas. Cambiar a una nueva versión mayor es una migración y se presupuesta por separado.</td>
|
||||
<td>Lo hace usted, después de una copia de seguridad completa.</td>
|
||||
<td>Suba la rama; si falla la actualización de un módulo, Odoo revierte el servidor y restaura la base de datos.</td>
|
||||
<td>Automáticas y obligatorias según el calendario de Odoo.</td>
|
||||
@@ -918,37 +920,37 @@
|
||||
<h2 class="section-title">Preguntas que plantea la tabla</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary>¿Qué significa realmente «cinco minutos»?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Qué significa realmente «cinco minutos»?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Cinco minutos es el tiempo hasta tener el sistema funcionando, no hasta tener el sistema terminado. Cargar sus propios clientes, productos e inventario es el trabajo de la primera semana, y esa semana es igual de larga en todas las rutas de arriba.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>¿Dan soporte a Odoo Online?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Dan soporte a Odoo Online?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No. Odoo Online solo ejecuta las apps estándar de Odoo y es incompatible con módulos personalizados o módulos de la Odoo Apps Store, así que no puede añadir ninguna app que no esté en la lista de Odoo. Las actualizaciones son automáticas y obligatorias según el calendario de Odoo. Si las apps estándar de Odoo cubren todo lo que va a necesitar, Odoo Online es la respuesta más barata y sencilla y nosotros no somos la opción correcta.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>¿Puedo añadir mis propias apps o módulos OCA?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Puedo añadir mis propias apps o módulos OCA?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Las apps propias de Odoo están en todos los planes. Los módulos personalizados y OCA se instalan desde On the Rise, con Git o con un clic. Side Hustle no permite instalar módulos.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>¿Necesito un asistente de IA para usar ODOO4projects?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Necesito un asistente de IA para usar ODOO4projects?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No. Entregamos nuestro servidor MCP directamente en las apps, así que un asistente de IA como Claude Code o Hermes puede reiniciar el servidor, subir un módulo, añadir un dominio o leer el registro por usted, y nunca abrirá un panel de hosting. Es opcional: el negocio funciona exactamente igual sin él.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>¿Podemos pasar a Odoo Enterprise más adelante?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Podemos pasar a Odoo Enterprise más adelante?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Sí. Traiga su propia licencia de Odoo Enterprise y mantenga el mismo sistema. Sin migración.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>¿Hay licencia por usuario?</summary>
|
||||
<summary class="plausible-event-name=FAQ">¿Hay licencia por usuario?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No. Odoo Community no tiene licencia por usuario; nuestros planes son un precio anual fijo. Odoo Enterprise, si lo trae, se licencia por usuario a través de Odoo S.A.</p>
|
||||
</div>
|
||||
@@ -978,13 +980,14 @@
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Enlaces útiles</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/es/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/es/odoo-hosting-2027.html">ODOO Hosting en 2027</a></li>
|
||||
<li><a href="/es/support.html">Soporte</a></li>
|
||||
<li><a href="/legal.html">Aviso legal</a></li>
|
||||
@@ -1009,7 +1012,7 @@
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:hello@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="cmp-sr-only" for="footerContactEmail">Su dirección de correo</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Su dirección de correo" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* Language selector — the page's top row: the back-link stays left, the selector travels right.
|
||||
Cream canvas, so lang.js's own dark-brass active colour is the correct one (no override). */
|
||||
@@ -268,9 +268,16 @@
|
||||
.contact-form { padding: 1.25rem; }
|
||||
}
|
||||
</style>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="/es/">← Volver al inicio</a>
|
||||
@@ -285,7 +292,9 @@
|
||||
<p>
|
||||
Para una ayuda más rápida, lea primero nuestras <strong>preguntas frecuentes</strong>: nuestro
|
||||
bot de soporte le ayuda con soluciones rápidas como <strong>git pull</strong> o reinicios — o
|
||||
envíe simplemente un <strong>ticket</strong> a nuestro equipo de soporte.
|
||||
envíe simplemente un <strong>ticket</strong> a nuestro equipo de soporte. Los temas urgentes los puede
|
||||
atender el <strong>agente de IA</strong> que ofrecemos, y el soporte por correo responde
|
||||
en un plazo de <strong>24 horas</strong>.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -321,7 +330,7 @@
|
||||
<!-- First Steps -->
|
||||
<div class="faq-panel active" id="panel-first-steps">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Mi Odoo parece vacío. ¿Qué puedo hacer con él?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -341,7 +350,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Cómo instalo una app nueva?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -351,7 +360,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Cómo añado mi servidor de correo para enviar mensajes desde Odoo?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -361,7 +370,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Cómo cambio mi nombre de usuario o mi contraseña?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -375,7 +384,7 @@
|
||||
<!-- Advanced Users -->
|
||||
<div class="faq-panel" id="panel-advanced">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Tengo acceso SSH a mi servicio?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -384,7 +393,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Cómo configuro la frecuencia de mis copias de seguridad?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -393,7 +402,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Cuánto tiempo se guardan las copias de seguridad?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -402,7 +411,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Cómo dirijo mi dominio a mi Odoo?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -412,7 +421,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Cómo puedo instalar Odoo Enterprise?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -425,7 +434,7 @@
|
||||
<!-- Trouble Shooting -->
|
||||
<div class="faq-panel" id="panel-trouble">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Después de un git check in, mi servidor no arranca o muestra un error 500</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -434,7 +443,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Por qué mi dominio muestra «Unknown Certificate» o «Bad Gateway»?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -447,7 +456,7 @@
|
||||
<!-- Commercial -->
|
||||
<div class="faq-panel" id="panel-commercial">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Está incluida la Odoo Enterprise License?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -456,7 +465,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Cómo puedo cambiar de plan?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -469,7 +478,7 @@
|
||||
<!-- Bring your Database -->
|
||||
<div class="faq-panel" id="panel-migrate">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Cómo puedo migrar mi base de datos de Odoo desde otro proveedor?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -479,7 +488,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>¿Puedo actualizar mi base de datos de Odoo desde una versión anterior, p. ej., 14 → 19?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -576,6 +585,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,486 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Freelancer signup feedback — ODOO4projects</title>
|
||||
<meta name="description" content="Tell us how the ODOO4projects freelancer signup went — every answer helps us improve the process before the directory opens." />
|
||||
|
||||
<!-- Private utility page. It is reached ONLY by the link we send, never by search.
|
||||
noindex+nofollow here, absent from sitemap.xml and llms.txt, and linked from nowhere
|
||||
on the site. See [[draft-page-convention]] for the same five rule. -->
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<!-- Nothing in this page's address is a credential, but the page is private and the
|
||||
feedback is a person's words: keep the URL out of any third party's logs. -->
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
<link rel="canonical" href="https://odoo4projects.com/feedback/" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/feedback/" />
|
||||
<meta property="og:title" content="Freelancer signup feedback — ODOO4projects" />
|
||||
<meta property="og:description" content="Tell us how the ODOO4projects freelancer signup went — every answer helps us improve the process." />
|
||||
<meta property="og:type" content="website" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
|
||||
<style>
|
||||
/* Utility page, same shell as /freelancer-edit/ and the top bar of
|
||||
/odoo-community-developers/: brand line, one card, the site tokens (:root in style.css)
|
||||
and the CI palette only. No hero, no footer, no site chrome beyond the brand line. */
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--cream);
|
||||
color: var(--ink);
|
||||
font-family: Inter, "Segoe UI", sans-serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.wrap { width: 86%; max-width: 1200px; margin: 0 auto; }
|
||||
.topbar { background: var(--midnight); border-bottom: 1px solid var(--line-brass); padding: 0.85rem 0; }
|
||||
.brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
.brand span { color: var(--brass); }
|
||||
main { padding: 2.5rem 0 4rem; }
|
||||
.card-wrap { max-width: 760px; margin: 0 auto; }
|
||||
h1 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-weight: 400;
|
||||
font-size: clamp(1.5rem, 4vw, 2.2rem);
|
||||
letter-spacing: 0.02em;
|
||||
margin: 0 0 0.4rem;
|
||||
}
|
||||
.lede { color: var(--ink-soft); margin: 0 0 1rem; }
|
||||
.panel {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.5rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
}
|
||||
.panel + .panel { margin-top: 1.25rem; }
|
||||
h2 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-weight: 400;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.02em;
|
||||
margin: 0 0 0.6rem;
|
||||
}
|
||||
.state { margin: 0; font-weight: 500; }
|
||||
.state-warn, .state-err { color: var(--brass-deep); }
|
||||
.state-ok { color: var(--success); }
|
||||
.detail { margin: 0.5rem 0 0; font-size: 0.9rem; color: var(--ink-soft); }
|
||||
|
||||
/* ---- Forms ---- */
|
||||
.field { margin: 0 0 1.1rem; }
|
||||
.field > label { display: block; font-weight: 600; font-size: 0.9rem; margin: 0 0 0.35rem; }
|
||||
input[type="text"], input[type="email"], textarea, select {
|
||||
width: 100%;
|
||||
font: inherit;
|
||||
padding: 0.6rem 0.7rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
}
|
||||
textarea { resize: vertical; }
|
||||
input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible,
|
||||
input[type="radio"]:focus-visible, input[type="checkbox"]:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.hint { font-size: 0.82rem; color: var(--ink-soft); margin: 0.35rem 0 0; }
|
||||
fieldset { border: 1px solid var(--line); border-radius: var(--radius); padding: 0.9rem 1rem 0.4rem; margin: 0 0 1.1rem; }
|
||||
legend { font-weight: 600; font-size: 0.9rem; padding: 0 0.35rem; }
|
||||
.choice { display: flex; align-items: flex-start; gap: 0.55rem; margin: 0 0 0.5rem; font-size: 0.9rem; }
|
||||
.choice input { margin-top: 0.28rem; flex: 0 0 auto; }
|
||||
.field[data-bad="1"] input, .field[data-bad="1"] textarea, .field[data-bad="1"] select,
|
||||
fieldset[data-bad="1"] { border-color: var(--brass-deep); }
|
||||
.err { font-size: 0.82rem; color: var(--brass-deep); font-weight: 600; margin: 0.35rem 0 0; }
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 0.04em;
|
||||
border: 0;
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--brass);
|
||||
color: var(--midnight);
|
||||
padding: 0.7rem 1.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn:hover { background: var(--brass-bright); }
|
||||
.btn:focus-visible { outline: 2px solid var(--midnight); outline-offset: 2px; }
|
||||
.btn[disabled] { opacity: 0.6; cursor: default; }
|
||||
.status { margin: 0.9rem 0 0; font-weight: 500; min-height: 1.2em; }
|
||||
.status.state-warn, .status.state-err { color: var(--brass-deep); }
|
||||
.status.state-ok { color: var(--success); }
|
||||
|
||||
/* ---- Progress bar (two steps) ---- */
|
||||
.progress { margin: 0 0 1.15rem; }
|
||||
.steps-bar {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.3rem 0.6rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.steps-bar .step { display: flex; align-items: center; gap: 0.4rem; color: var(--ink-soft); }
|
||||
.steps-bar .step + .step::before { content: "·"; margin-right: 0.6rem; color: var(--line-brass); }
|
||||
.step-mark {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1.55rem;
|
||||
height: 1.55rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--line);
|
||||
background: #fff;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1;
|
||||
}
|
||||
/* The current step is the brass pill and the bolder label, and it is said out loud
|
||||
("(current step)", .vh below) — weight and a word, so it is never colour alone. */
|
||||
.steps-bar .step-current { color: var(--ink); font-weight: 600; }
|
||||
.steps-bar .step-current .step-mark { background: var(--brass); border-color: var(--brass); color: var(--midnight); }
|
||||
.link-signup { color: var(--brass-deep); font-weight: 600; }
|
||||
/* Visually hidden, still read aloud. */
|
||||
.vh {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
clip: rect(0 0 0 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- The one wire name and shape this page uses, in ONE place. POST only — the page reads
|
||||
nothing on load. SHAPE (match this in the n8n workflow):
|
||||
|
||||
POST submitUrl { "form": "feedback", <one key per question, the answer> }
|
||||
-> any 2xx = receipt shown; a non-2xx is reported as a failure, never as success.
|
||||
|
||||
The body carries the answers and nothing else: no name, no email, no identifier of any
|
||||
kind. An unexpected shape is named, never guessed. -->
|
||||
<script>
|
||||
window.O4F = {
|
||||
// The one route that receives the feedback form.
|
||||
submitUrl: "https://n8n.odoo4projects.com/webhook/feedback"
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Privacy-friendly analytics by Plausible (verbatim; the page carries no query). -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="wrap">
|
||||
<a class="brand" href="https://odoo4projects.com/">ODOO<span>4</span>projects</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="wrap">
|
||||
<div class="card-wrap">
|
||||
<h1>Freelancer signup feedback</h1>
|
||||
<p class="lede">
|
||||
We opened a free freelancer portal on ODOO4projects.com. Sign up there, then tell us how
|
||||
it went — every answer helps us improve the process.
|
||||
</p>
|
||||
<!-- The portal link, visible next to the intro and not buried in step copy. It opens in
|
||||
a new window and says so. It is a plain link, not the page's primary action —
|
||||
the feedback form still is. -->
|
||||
<p class="detail">
|
||||
The directory opens on <strong>1 December</strong>. Signing up is free for freelancers
|
||||
and clients, and the feedback you give here is what we fix before then.
|
||||
<a
|
||||
class="link-signup"
|
||||
href="https://odoo4projects.com/odoo-community-developers/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Sign up on the freelancer portal (opens in a new window)</a>.
|
||||
</p>
|
||||
|
||||
<!-- Filled by the script at the foot of the page. Empty on purpose: with JavaScript off
|
||||
there is no form to render, so an empty container plus the noscript note below is
|
||||
the honest picture. -->
|
||||
<div id="app"></div>
|
||||
|
||||
<noscript>
|
||||
<div class="panel">
|
||||
<p class="state state-warn">This page needs JavaScript to show the feedback form.</p>
|
||||
<p class="detail">
|
||||
Turn JavaScript on in your browser and open this page again — or reply to the message
|
||||
that brought you here.
|
||||
</p>
|
||||
</div>
|
||||
</noscript>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var C = window.O4F;
|
||||
var app = document.getElementById("app");
|
||||
// The freelancer portal — the directory page, at its TOP (its own introduction), not the
|
||||
// directory's apply anchor: that anchor drops the visitor at the application form,
|
||||
// mid-page, past the page's own intro. There is no separate login or account page, so this
|
||||
// is the one target. The static .link-signup link in the markup above is the ONE source of
|
||||
// this URL; the script-written link in step 1 reads it back, so the two can never disagree.
|
||||
var PORTAL_URL = document.querySelector(".link-signup").href;
|
||||
|
||||
function el(tag, cls, text) {
|
||||
var n = document.createElement(tag);
|
||||
if (cls) n.className = cls;
|
||||
if (text != null) n.textContent = text; // textContent only: a reply is never markup
|
||||
return n;
|
||||
}
|
||||
function show(nodes) {
|
||||
while (app.firstChild) app.removeChild(app.firstChild);
|
||||
for (var i = 0; i < nodes.length; i++) app.appendChild(nodes[i]);
|
||||
return nodes;
|
||||
}
|
||||
function status(text, kind) {
|
||||
var p = el("p", "status" + (kind ? " state-" + kind : ""), text);
|
||||
p.setAttribute("role", "status");
|
||||
p.setAttribute("aria-live", "polite");
|
||||
return p;
|
||||
}
|
||||
function fetchJson(url, opts) {
|
||||
return fetch(url, opts).then(function (r) {
|
||||
return r.text().then(function (t) {
|
||||
var body = null;
|
||||
try { body = JSON.parse(t); } catch (e) { body = null; }
|
||||
return { ok: r.ok, status: r.status, body: body };
|
||||
});
|
||||
});
|
||||
}
|
||||
function msgOf(body) {
|
||||
if (!body || typeof body !== "object") return "";
|
||||
var m = body.message || body.error || body.detail;
|
||||
return typeof m === "string" ? m : "";
|
||||
}
|
||||
// A link to the freelancer portal. Opens in a new window and says so, so a screen-reader
|
||||
// user is not surprised by a new tab.
|
||||
function portalLink() {
|
||||
var p = el("p", "detail");
|
||||
var a = el("a", "link-signup");
|
||||
a.href = PORTAL_URL;
|
||||
a.target = "_blank";
|
||||
a.rel = "noopener noreferrer";
|
||||
a.textContent = "Sign up on the freelancer portal (opens in a new window)";
|
||||
p.appendChild(a);
|
||||
return p;
|
||||
}
|
||||
|
||||
// ---- Progress bar (two steps) ---------------------------------------------------------
|
||||
// Step 1 is the signup on the portal, step 2 is this form. The page has no honest way to
|
||||
// know the visitor has used the portal link, so step 1 stays current and nothing is
|
||||
// guessed: the number, the bolder label and the spoken "(current step)" say which one is
|
||||
// current, so it is never colour alone.
|
||||
var STEP_LABELS = ["Sign up", "Give feedback"];
|
||||
function progressBar(current) {
|
||||
var nav = el("nav", "progress");
|
||||
nav.setAttribute("aria-label", "Progress");
|
||||
var ol = el("ol", "steps-bar");
|
||||
STEP_LABELS.forEach(function (label, i) {
|
||||
var n = i + 1;
|
||||
var li = el("li", "step");
|
||||
var mark = el("span", "step-mark");
|
||||
mark.setAttribute("aria-hidden", "true");
|
||||
mark.textContent = String(n);
|
||||
li.appendChild(mark);
|
||||
li.appendChild(el("span", "step-label", label));
|
||||
if (n === current) {
|
||||
li.className = "step step-current";
|
||||
li.setAttribute("aria-current", "step");
|
||||
li.appendChild(el("span", "vh", " (current step)"));
|
||||
} else {
|
||||
li.className = "step step-next";
|
||||
}
|
||||
ol.appendChild(li);
|
||||
});
|
||||
nav.appendChild(ol);
|
||||
return nav;
|
||||
}
|
||||
|
||||
// ---- Step 1 — the portal link, again, in the step's own copy -------------------------
|
||||
function signupPanel() {
|
||||
var box = el("div", "panel");
|
||||
box.appendChild(el("h2", "", "Step 1 — sign up on the freelancer portal"));
|
||||
box.appendChild(el("p", "detail",
|
||||
"Sign up on the ODOO4projects freelancer portal and add your profile. The directory opens on 1 December."));
|
||||
box.appendChild(portalLink());
|
||||
return box;
|
||||
}
|
||||
|
||||
// ---- The feedback form ----------------------------------------------------------------
|
||||
// The n8n form's questions, with the copy corrected. The identity block (name, email,
|
||||
// anonymous tick) and the publish-consent question are gone — do not bring them back.
|
||||
// None of these questions is compulsory: the form submits with any subset answered, or none.
|
||||
// The error nodes (.err) and their CSS are kept, but nothing sets them any more.
|
||||
var FIELDS = [
|
||||
{ id: "finalized", label: "Did you finalize the signup?", type: "select", options: [["yes", "Yes"], ["no", "No"]] },
|
||||
{ id: "difficulty", label: "How hard was the signup?", type: "select", options: [["easy", "Easy"], ["ok", "OK"], ["hard", "Hard"]] },
|
||||
{ id: "signup_feedback", label: "What is your feedback on the signup?", type: "textarea" },
|
||||
{ id: "understood_scale", label: "Did you understand how we ask you to rate your skills? (the 15-point scale)", type: "select", options: [["yes", "Yes"], ["no", "No"]] },
|
||||
{ id: "scale_feedback", label: "What is your feedback on the 15-point skill scale?", type: "textarea" },
|
||||
{ id: "almost_stopped", label: "What almost stopped you from signing up?", type: "textarea", hint: "If nothing did, say so." },
|
||||
{ id: "broke_or_confused", label: "Did anything break or confuse you?", type: "textarea" },
|
||||
{ id: "design_shows_work", label: "Do you think our profile design shows what you do well?", type: "select", options: [["yes", "Yes"], ["so-so", "So-so"], ["no", "No"]] },
|
||||
{ id: "design_feedback", label: "What can we improve about the profile design?", type: "textarea" },
|
||||
{ id: "will_stay", label: "Will you stay on the platform?", type: "select", options: [["yes", "Yes"], ["no", "No"]] },
|
||||
{ id: "improve_offer", label: "How can we improve what we offer you?", type: "textarea" },
|
||||
{ id: "recommend", label: "Would you recommend this platform to a freelance colleague?", type: "select", options: [["yes", "Yes, good idea"], ["maybe", "Maybe"], ["no", "Preferably not"]] },
|
||||
{ id: "expect_next", label: "What do you expect to happen next — and how soon?", type: "textarea" }
|
||||
];
|
||||
|
||||
function fieldBlock(spec) {
|
||||
var f = el("div", "field");
|
||||
f.setAttribute("data-field", spec.id);
|
||||
if (spec.type === "radio") {
|
||||
var fs = el("fieldset");
|
||||
fs.setAttribute("data-field", spec.id);
|
||||
var lg = el("legend", "", spec.label);
|
||||
fs.appendChild(lg);
|
||||
spec.options.forEach(function (pair) {
|
||||
var lab = el("label", "choice");
|
||||
var r = el("input");
|
||||
r.type = "radio";
|
||||
r.name = spec.id;
|
||||
r.value = pair[0];
|
||||
r.id = spec.id + "-" + pair[0];
|
||||
lab.appendChild(r);
|
||||
lab.appendChild(el("span", "", pair[1]));
|
||||
fs.appendChild(lab);
|
||||
});
|
||||
var er = el("p", "err", "");
|
||||
er.hidden = true;
|
||||
fs.appendChild(er);
|
||||
return fs;
|
||||
}
|
||||
var lb = el("label", "", spec.label);
|
||||
lb.setAttribute("for", "fb-" + spec.id);
|
||||
var ctl;
|
||||
if (spec.type === "select") {
|
||||
ctl = el("select");
|
||||
ctl.appendChild(new Option("— choose —", ""));
|
||||
spec.options.forEach(function (pair) { ctl.appendChild(new Option(pair[1], pair[0])); });
|
||||
} else if (spec.type === "textarea") {
|
||||
ctl = el("textarea");
|
||||
ctl.rows = 4;
|
||||
} else {
|
||||
ctl = el("input");
|
||||
ctl.type = "text";
|
||||
}
|
||||
ctl.id = "fb-" + spec.id;
|
||||
ctl.name = spec.id;
|
||||
f.appendChild(lb);
|
||||
f.appendChild(ctl);
|
||||
if (spec.hint) f.appendChild(el("p", "hint", spec.hint));
|
||||
var e = el("p", "err", "");
|
||||
e.hidden = true;
|
||||
f.appendChild(e);
|
||||
return f;
|
||||
}
|
||||
|
||||
function feedbackPanel() {
|
||||
var box = el("div", "panel");
|
||||
box.appendChild(el("h2", "", "How did it go?"));
|
||||
box.appendChild(el("p", "detail", "Answer in your own words. Your answers come to us — nothing here is published."));
|
||||
var form = el("form");
|
||||
form.setAttribute("novalidate", "novalidate");
|
||||
|
||||
FIELDS.forEach(function (spec) { form.appendChild(fieldBlock(spec)); });
|
||||
|
||||
var line = status("", "");
|
||||
var btn = el("button", "btn", "Send feedback");
|
||||
btn.type = "submit";
|
||||
form.appendChild(btn);
|
||||
form.appendChild(line);
|
||||
|
||||
form.addEventListener("submit", function (ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
// Nothing here is compulsory, so there is nothing to validate and nothing to announce.
|
||||
// The .err nodes and their CSS are kept in place in case a question is ever made
|
||||
// compulsory again, but nothing here sets them: an empty form submits like any other.
|
||||
|
||||
// Build the body. Only the questions that were answered, and nothing else — no
|
||||
// name, no email, no identifier, and no empty string for a question left blank.
|
||||
var body = { form: "feedback" };
|
||||
FIELDS.forEach(function (spec) {
|
||||
var v = "";
|
||||
if (spec.type === "radio") {
|
||||
var checked = form.querySelector('input[name="' + spec.id + '"]:checked');
|
||||
v = checked ? checked.value : "";
|
||||
} else {
|
||||
var ctl = form.querySelector("#fb-" + spec.id);
|
||||
v = ctl ? ctl.value.trim() : "";
|
||||
}
|
||||
if (v) body[spec.id] = v;
|
||||
});
|
||||
|
||||
btn.disabled = true;
|
||||
line.className = "status";
|
||||
line.textContent = "Sending…";
|
||||
fetchJson(C.submitUrl, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body)
|
||||
}).then(function (res) {
|
||||
if (!res.ok) {
|
||||
btn.disabled = false;
|
||||
line.className = "status state-warn";
|
||||
line.textContent = "We could not send your feedback — the service answered " + res.status +
|
||||
(msgOf(res.body) ? " — " + msgOf(res.body) : "") + ". Your answers are still here; try again.";
|
||||
return;
|
||||
}
|
||||
line.className = "status state-ok";
|
||||
line.textContent = "Thank you — your feedback reached us.";
|
||||
btn.disabled = true;
|
||||
form.querySelectorAll("input, textarea, select, button").forEach(function (n) {
|
||||
if (n !== btn) n.disabled = true;
|
||||
});
|
||||
}).catch(function () {
|
||||
btn.disabled = false;
|
||||
line.className = "status state-warn";
|
||||
line.textContent = "We could not reach the service. Your answers are still here; try again.";
|
||||
});
|
||||
});
|
||||
|
||||
box.appendChild(form);
|
||||
return box;
|
||||
}
|
||||
|
||||
// ---- Render ---------------------------------------------------------------------------
|
||||
// One state, always: the form. Nothing is read on load, so there is no fetch here.
|
||||
show([progressBar(1), signupPanel(), feedbackPanel()]);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,468 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Answer a question — ODOO4projects</title>
|
||||
<meta name="description" content="Private page: an Odoo freelancer answers a client's question." />
|
||||
|
||||
<!-- Private utility page. It is reached ONLY by a link we email, never by search.
|
||||
noindex+nofollow here, absent from sitemap.xml and llms.txt, and linked from nowhere
|
||||
on the site. See [[draft-page-convention]] for the same five rule. -->
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<!-- While the link is open the address carries a credential. No claim-by-subdomain of the
|
||||
hash travels to a third party (Google Fonts, and every other cross-origin request). -->
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
<link rel="canonical" href="https://odoo4projects.com/freelancer-answer/" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
|
||||
<style>
|
||||
/* Utility page. Deliberately small: no hero, no footer, no site chrome beyond a
|
||||
brand line. Reuses the site tokens (:root in style.css) and the CI palette only. */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--cream);
|
||||
color: var(--ink);
|
||||
font-family: Inter, "Segoe UI", sans-serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.wrap {
|
||||
width: 86%;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.topbar {
|
||||
background: var(--midnight);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.85rem 0;
|
||||
}
|
||||
.brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
.brand span {
|
||||
color: var(--brass);
|
||||
}
|
||||
main {
|
||||
padding: 2.5rem 0 4rem;
|
||||
}
|
||||
.card-wrap {
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
h1 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-weight: 400;
|
||||
font-size: clamp(1.5rem, 4vw, 2.2rem);
|
||||
letter-spacing: 0.02em;
|
||||
margin: 0 0 0.4rem;
|
||||
}
|
||||
.lede {
|
||||
color: var(--ink-soft);
|
||||
margin: 0 0 1.75rem;
|
||||
}
|
||||
.panel {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.5rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
}
|
||||
.state {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
.state-warn,
|
||||
.state-err {
|
||||
color: var(--brass-deep);
|
||||
}
|
||||
.state-ok {
|
||||
color: var(--success);
|
||||
}
|
||||
.detail {
|
||||
margin: 0.5rem 0 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
.qcard {
|
||||
background: var(--midnight);
|
||||
color: var(--cream);
|
||||
border-radius: var(--radius);
|
||||
padding: 1.1rem 1.25rem;
|
||||
margin: 0 0 1.5rem;
|
||||
}
|
||||
.qcard-label {
|
||||
font-size: 0.78rem;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--brass);
|
||||
margin: 0 0 0.4rem;
|
||||
}
|
||||
.qcard-text {
|
||||
margin: 0;
|
||||
font-size: 1.05rem;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.field label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
margin: 0 0 0.4rem;
|
||||
}
|
||||
textarea {
|
||||
width: 100%;
|
||||
font: inherit;
|
||||
padding: 0.7rem 0.8rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
resize: vertical;
|
||||
}
|
||||
textarea:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.hint {
|
||||
font-size: 0.82rem;
|
||||
color: var(--ink-soft);
|
||||
margin: 0.4rem 0 0;
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
margin-top: 1rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 0.04em;
|
||||
border: 0;
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--brass);
|
||||
color: var(--midnight);
|
||||
padding: 0.7rem 1.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn:hover {
|
||||
background: var(--brass-bright);
|
||||
}
|
||||
.btn:focus-visible {
|
||||
outline: 2px solid var(--midnight);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.btn[disabled] {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
.status {
|
||||
margin: 0.9rem 0 0;
|
||||
font-weight: 500;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 1) Read the credential, then take it OUT of the address bar.
|
||||
The hash arrives as ?has=... or ?hash=... (both spellings accepted, 'has' first).
|
||||
The page keeps it in memory for the GET, the PATCH and a retry; it must never sit in
|
||||
the URL, because Plausible reports location.href and a shared/forwarded link would
|
||||
leak it. Stripping the query BEFORE the tracker is loaded is what keeps it out of
|
||||
analytics. All wire names and key lists live here, in one place. -->
|
||||
<script>
|
||||
window.O4P = {
|
||||
// The node webhook: holds the question (GET) and receives the answer (PATCH).
|
||||
webhook: "https://n8n.odoo4projects.com/webhook/ODOO4projects/odoo_experts_quote",
|
||||
// Query-string spellings to read, in order. The brief wrote "has" twice, so "has"
|
||||
// wins; "hash" is accepted as the identical fallback. Confirm with the owner which
|
||||
// spelling the emailed links will carry.
|
||||
hashKeys: ["has", "hash"],
|
||||
// Wire name used OUTWARD, both directions: GET query param and PATCH body key.
|
||||
hashWireKey: "has",
|
||||
// PATCH body key carrying the freelancer's answer.
|
||||
answerWireKey: "answer",
|
||||
// The ONLY response keys this page may render. Anything not listed is never read,
|
||||
// so a client's email/name/phone sitting in the same object cannot reach the page.
|
||||
questionKeys: ["question", "brief", "message", "text"]
|
||||
};
|
||||
|
||||
(function () {
|
||||
var params = new URLSearchParams(location.search);
|
||||
var hash = "";
|
||||
for (var i = 0; i < window.O4P.hashKeys.length; i++) {
|
||||
var v = params.get(window.O4P.hashKeys[i]);
|
||||
if (v) { hash = v; break; }
|
||||
}
|
||||
window.__ANSWER_HASH = hash;
|
||||
// Drop the query string from the address + history. No reload loses anything:
|
||||
// the hash now lives in memory above.
|
||||
if (location.search) history.replaceState(null, "", location.pathname);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- 2) Privacy-friendly analytics by Plausible (verbatim; the page now has no query). -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="wrap">
|
||||
<a class="brand" href="https://odoo4projects.com/">ODOO<span>4</span>projects</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="wrap">
|
||||
<div class="card-wrap">
|
||||
<h1>Answer a question</h1>
|
||||
<p class="lede">
|
||||
A client asked you a question through ODOO4projects. Write your answer below and it
|
||||
goes back to us — we pass it on to them.
|
||||
</p>
|
||||
|
||||
<!-- Filled by the script at the foot of the page. Empty on purpose: with
|
||||
JavaScript off there is no way to read the question or send an answer, so an
|
||||
empty container + the noscript note below is the honest picture. -->
|
||||
<div id="app"></div>
|
||||
|
||||
<noscript>
|
||||
<div class="panel">
|
||||
<p class="state state-warn">This page needs JavaScript to load the question and to send your answer.</p>
|
||||
<p class="detail">
|
||||
Turn JavaScript on in your browser and open the link again — or reply to the email
|
||||
that brought you here.
|
||||
</p>
|
||||
</div>
|
||||
</noscript>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var C = window.O4P;
|
||||
var app = document.getElementById("app");
|
||||
var hash = window.__ANSWER_HASH || "";
|
||||
|
||||
function el(tag, cls, text) {
|
||||
var n = document.createElement(tag);
|
||||
if (cls) n.className = cls;
|
||||
if (text != null) n.textContent = text; // textContent only: a question is never markup
|
||||
return n;
|
||||
}
|
||||
function show(nodes) {
|
||||
while (app.firstChild) app.removeChild(app.firstChild);
|
||||
var box = el("div", "panel");
|
||||
for (var i = 0; i < nodes.length; i++) box.appendChild(nodes[i]);
|
||||
app.appendChild(box);
|
||||
}
|
||||
function status(text, kind) {
|
||||
var p = el("p", "state" + (kind ? " state-" + kind : ""), text);
|
||||
p.setAttribute("role", "status");
|
||||
p.setAttribute("aria-live", "polite");
|
||||
return p;
|
||||
}
|
||||
function retryButton() {
|
||||
var b = el("button", "btn", "Try again");
|
||||
b.type = "button";
|
||||
b.addEventListener("click", load);
|
||||
return b;
|
||||
}
|
||||
|
||||
// The GET reply may be a bare object, an array, or wrapped in .data. Unwrap the
|
||||
// envelope only — the field names inside are decided by questionKeys.
|
||||
function unwrap(payload) {
|
||||
if (Array.isArray(payload)) return payload[0] || null;
|
||||
if (payload && typeof payload === "object") {
|
||||
if (Array.isArray(payload.data)) return payload.data[0] || null;
|
||||
if (Array.isArray(payload.items)) return payload.items[0] || null;
|
||||
return payload;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function pickQuestion(obj) {
|
||||
if (!obj) return "";
|
||||
for (var i = 0; i < C.questionKeys.length; i++) {
|
||||
var v = obj[C.questionKeys[i]];
|
||||
if (typeof v === "string" && v.trim()) return v.trim();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function load() {
|
||||
if (!hash) {
|
||||
show([
|
||||
status("This link is incomplete — it arrived without its code.", "warn"),
|
||||
el("p", "detail", "Open it again from the email that brought you here.")
|
||||
]);
|
||||
return;
|
||||
}
|
||||
show([status("Loading your question…")]);
|
||||
|
||||
fetch(C.webhook + "?" + encodeURIComponent(C.hashWireKey) + "=" + encodeURIComponent(hash), {
|
||||
headers: { Accept: "application/json" }
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res.ok) {
|
||||
// Live behaviour for an unknown hash: 500 {"code":0,"message":"No item to return was found"}.
|
||||
return res.text().then(function (body) {
|
||||
var msg = "";
|
||||
try { msg = (JSON.parse(body) || {}).message || ""; } catch (e) { /* not json */ }
|
||||
show([
|
||||
status("This link is not valid, or it has expired.", "warn"),
|
||||
el("p", "detail", "The service answered " + res.status + (msg ? " — " + msg : "") + "."),
|
||||
el("p", "detail", "If you think that is wrong, reply to the email that brought you here.")
|
||||
]);
|
||||
});
|
||||
}
|
||||
return res.json().then(renderQuestion).catch(function () {
|
||||
show([
|
||||
status("We could not read the reply from the service.", "warn"),
|
||||
el("p", "detail", "The reply was not in a form we understand. Please try again."),
|
||||
retryButton()
|
||||
]);
|
||||
});
|
||||
})
|
||||
.catch(function () {
|
||||
// Network failure: the hash is still in memory, so a retry needs no new link.
|
||||
show([
|
||||
status("We could not load your question just now.", "warn"),
|
||||
el("p", "detail", "Your link has been kept, so you can try again."),
|
||||
retryButton()
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
function renderQuestion(payload) {
|
||||
var obj = unwrap(payload);
|
||||
var question = pickQuestion(obj);
|
||||
if (!question) {
|
||||
// Honest about a shape we did not expect: name the fields, never a value. A
|
||||
// field name cannot identify the client; a value might.
|
||||
var names = obj && typeof obj === "object" ? Object.keys(obj) : [];
|
||||
show([
|
||||
status("We could not read the question from the reply from the service.", "warn"),
|
||||
el("p", "detail",
|
||||
names.length
|
||||
? "The reply carried these fields: " + names.join(", ") + "."
|
||||
: "The reply carried no readable data.")
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
var card = el("div", "qcard");
|
||||
card.appendChild(el("p", "qcard-label", "The question"));
|
||||
card.appendChild(el("blockquote", "qcard-text", question));
|
||||
|
||||
var form = el("form", "answer-form");
|
||||
form.setAttribute("novalidate", "novalidate"); // JS does the check, announced below
|
||||
|
||||
var field = el("div", "field");
|
||||
var label = el("label", "", "Your answer");
|
||||
label.setAttribute("for", "answerText");
|
||||
var ta = el("textarea");
|
||||
ta.id = "answerText";
|
||||
ta.name = C.answerWireKey;
|
||||
ta.rows = 8;
|
||||
ta.required = true;
|
||||
ta.setAttribute("aria-describedby", "answerHint");
|
||||
var hint = el("p", "hint", "Your answer goes back to ODOO4projects, who pass it on. Write it as you would to the client.");
|
||||
hint.id = "answerHint";
|
||||
field.appendChild(label);
|
||||
field.appendChild(ta);
|
||||
field.appendChild(hint);
|
||||
|
||||
var btn = el("button", "btn", "Send answer");
|
||||
btn.type = "submit";
|
||||
var line = el("p", "status");
|
||||
line.id = "answerStatus";
|
||||
line.setAttribute("role", "status");
|
||||
line.setAttribute("aria-live", "polite");
|
||||
|
||||
function setLine(text, kind) {
|
||||
line.className = "status" + (kind ? " state-" + kind : "");
|
||||
line.textContent = text;
|
||||
}
|
||||
|
||||
form.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
var answer = ta.value.trim();
|
||||
if (!answer) {
|
||||
ta.setAttribute("aria-invalid", "true");
|
||||
setLine("Please write your answer first.", "warn");
|
||||
ta.focus();
|
||||
return;
|
||||
}
|
||||
ta.removeAttribute("aria-invalid");
|
||||
|
||||
// The body shape, in one constant (C.hashWireKey + C.answerWireKey):
|
||||
// {"has":"<hash>","answer":"<text>"}
|
||||
// PATCH, not POST: the question record already exists (the client's submission
|
||||
// created it), so this answer is a PARTIAL UPDATE of it — POST risks creating a
|
||||
// second record. Match this method and these two keys in the n8n workflow.
|
||||
var body = {};
|
||||
body[C.hashWireKey] = hash;
|
||||
body[C.answerWireKey] = answer;
|
||||
|
||||
btn.disabled = true;
|
||||
setLine("Sending…", null);
|
||||
fetch(C.webhook, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
.then(function (res) {
|
||||
if (res.ok) {
|
||||
// A RECEIPT, not a delivery claim: n8n answers 200 before the workflow
|
||||
// runs, so this page cannot know the answer reached anyone. No time is
|
||||
// promised. The receipt shows ONLY on a 2xx.
|
||||
setLine("Thank you — we have your answer.", "ok");
|
||||
form.reset();
|
||||
return;
|
||||
}
|
||||
// Non-2xx: never show the receipt. A method the route refuses (404/405/501)
|
||||
// is a clear failure, not a transient one — say so plainly and KEEP the
|
||||
// answer in the box so it can be retried.
|
||||
var refused = res.status === 404 || res.status === 405 || res.status === 501;
|
||||
setLine(
|
||||
refused
|
||||
? "We could not save your answer. Please reply to the email that brought you here."
|
||||
: "That did not send. Please try again.",
|
||||
"err"
|
||||
);
|
||||
})
|
||||
.catch(function () {
|
||||
// Network failure: the hash stays in memory, the answer stays in the box.
|
||||
setLine("That did not send. Please try again.", "err");
|
||||
})
|
||||
.then(function () { btn.disabled = false; });
|
||||
});
|
||||
|
||||
form.appendChild(field);
|
||||
form.appendChild(btn);
|
||||
form.appendChild(line);
|
||||
|
||||
show([card, form]);
|
||||
}
|
||||
|
||||
load();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,179 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Your email is confirmed — ODOO4projects</title>
|
||||
<meta name="description" content="Private page: your email is confirmed and your card is in the Odoo Freelancer Directory." />
|
||||
|
||||
<!-- Private utility page. It is reached ONLY by the confirmation link we email, never by
|
||||
search. noindex+nofollow here, absent from sitemap.xml and llms.txt, and linked from
|
||||
nowhere on the site. See [[draft-page-convention]] for the same five rule. -->
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<!-- The confirmation is completed by the workflow, so this address may carry anything the
|
||||
redirect appends. Nothing from the query string is ever rendered or read: the page is
|
||||
identical with a bare URL and with something appended, and the query is dropped from the
|
||||
address (below) before the tracker loads. -->
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
<link rel="canonical" href="https://odoo4projects.com/freelancer-confirmed/" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/freelancer-confirmed/" />
|
||||
<meta property="og:title" content="Your email is confirmed — ODOO4projects" />
|
||||
<meta property="og:description" content="Your card is in the Odoo Freelancer Directory." />
|
||||
<meta property="og:type" content="website" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
|
||||
<style>
|
||||
/* Utility page, same shell as /freelancer-edit/ and /feedback/: brand line, one card, the
|
||||
site tokens (:root in style.css) and the CI palette only. No hero, no footer, no site
|
||||
chrome beyond the brand line. */
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--cream);
|
||||
color: var(--ink);
|
||||
font-family: Inter, "Segoe UI", sans-serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.wrap { width: 86%; max-width: 1200px; margin: 0 auto; }
|
||||
.topbar { background: var(--midnight); border-bottom: 1px solid var(--line-brass); padding: 0.85rem 0; }
|
||||
.brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
.brand span { color: var(--brass); }
|
||||
main { padding: 2.5rem 0 4rem; }
|
||||
.card-wrap { max-width: 760px; margin: 0 auto; }
|
||||
h1 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-weight: 400;
|
||||
font-size: clamp(1.5rem, 4vw, 2.2rem);
|
||||
letter-spacing: 0.02em;
|
||||
margin: 0 0 0.4rem;
|
||||
}
|
||||
.lede { color: var(--ink-soft); margin: 0 0 1rem; }
|
||||
.panel {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.5rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
}
|
||||
.panel + .panel { margin-top: 1.25rem; }
|
||||
h2 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-weight: 400;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.02em;
|
||||
margin: 0 0 0.6rem;
|
||||
}
|
||||
.detail { margin: 0.5rem 0 0; font-size: 0.9rem; color: var(--ink-soft); }
|
||||
.detail:first-of-type { margin-top: 0; }
|
||||
|
||||
/* The page's ONE primary action is the feedback link; the directory link is a plain link. */
|
||||
.btn {
|
||||
display: inline-block;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 0.04em;
|
||||
border: 0;
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--brass);
|
||||
color: var(--midnight);
|
||||
padding: 0.85rem 2rem;
|
||||
margin-top: 1rem;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
.btn:hover { background: var(--brass-bright); }
|
||||
/* The anchor needs the text colour kept on hover: the site's global a:hover ({color:
|
||||
var(--brass)}) outranks a lone .btn, and brass on brass-bright is unreadable. */
|
||||
a.btn, a.btn:hover { color: var(--midnight); }
|
||||
.btn:focus-visible { outline: 2px solid var(--midnight); outline-offset: 2px; }
|
||||
.link-plain { color: var(--brass-deep); font-weight: 600; }
|
||||
</style>
|
||||
|
||||
<!-- The confirmation redirect may append anything (a name, an id, a tracking token). NOTHING
|
||||
from the query string is read or rendered: this page has one state, whatever it is handed.
|
||||
The query is dropped from the address + the history entry BEFORE the tracker is loaded —
|
||||
Plausible reports location.href, so stripping it first is what keeps anything appended out
|
||||
of the analytics payload (the same care as /freelancer-edit/). With JavaScript off the
|
||||
query stays in the address bar and still nothing renders it. -->
|
||||
<script>
|
||||
(function () {
|
||||
if (location.search) history.replaceState(null, "", location.pathname);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Privacy-friendly analytics by Plausible (verbatim; the page now carries no query). -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="wrap">
|
||||
<a class="brand" href="https://odoo4projects.com/">ODOO<span>4</span>projects</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="wrap">
|
||||
<div class="card-wrap">
|
||||
<h1>Your email is confirmed</h1>
|
||||
<p class="lede">
|
||||
Thank you — your email address is confirmed, and your card is now in the Odoo Freelancer
|
||||
Directory.
|
||||
</p>
|
||||
|
||||
<!-- 1. The page's primary action: the feedback. On its own panel, first, brass and larger. -->
|
||||
<div class="panel">
|
||||
<h2>How did the signup go?</h2>
|
||||
<p class="detail">
|
||||
The signup is the part we most want to get right, and you have just been through it.
|
||||
Tell us how it went — every answer helps us improve it.
|
||||
</p>
|
||||
<a class="btn" href="https://odoo4projects.com/feedback/">Give feedback on the signup</a>
|
||||
</div>
|
||||
|
||||
<!-- 2. See yourself in the directory. -->
|
||||
<div class="panel">
|
||||
<h2>See your card in the directory</h2>
|
||||
<p class="detail">
|
||||
Everything on a card is the freelancer's own words.
|
||||
</p>
|
||||
<p class="detail">
|
||||
<a
|
||||
class="link-plain"
|
||||
href="https://odoo4projects.com/odoo-community-developers/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Open the Odoo Freelancer Directory (opens in a new window)</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 3. Nobody is stuck with what they typed. One line, and the credential stays where it
|
||||
belongs: the edit link is the one we email, so it is not linked from here. -->
|
||||
<p class="detail">
|
||||
You can change or remove your profile at any time — the link for that is in the email we
|
||||
send you.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,813 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Edit your listing — ODOO4projects</title>
|
||||
<meta name="description" content="Private page: a listed Odoo freelancer edits or deletes their own listing." />
|
||||
|
||||
<!-- Private utility page. It is reached ONLY by a link we email, never by search.
|
||||
noindex+nofollow here, absent from sitemap.xml and llms.txt, and linked from nowhere
|
||||
on the site. See [[draft-page-convention]] for the same five rule. -->
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<!-- While the link is open the address carries a credential. No claim-by-subdomain of the
|
||||
hash travels to a third party (Google Fonts, and every other cross-origin request). -->
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
<link rel="canonical" href="https://odoo4projects.com/freelancer-edit/" />
|
||||
<!-- The ONE path the emailed link uses; mirrors /freelancer-answer/ deliberately. -->
|
||||
<meta property="og:url" content="https://odoo4projects.com/freelancer-edit/" />
|
||||
<meta property="og:title" content="Edit your listing — ODOO4projects" />
|
||||
<meta property="og:type" content="website" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
|
||||
<style>
|
||||
/* Utility page. Deliberately small: no hero, no footer, no site chrome beyond a brand
|
||||
line. Reuses the site tokens (:root in style.css) and the CI palette only. */
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--cream);
|
||||
color: var(--ink);
|
||||
font-family: Inter, "Segoe UI", sans-serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.wrap { width: 86%; max-width: 1200px; margin: 0 auto; }
|
||||
.topbar { background: var(--midnight); border-bottom: 1px solid var(--line-brass); padding: 0.85rem 0; }
|
||||
.brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
.brand span { color: var(--brass); }
|
||||
main { padding: 2.5rem 0 4rem; }
|
||||
.card-wrap { max-width: 720px; margin: 0 auto; }
|
||||
h1 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-weight: 400;
|
||||
font-size: clamp(1.5rem, 4vw, 2.2rem);
|
||||
letter-spacing: 0.02em;
|
||||
margin: 0 0 0.4rem;
|
||||
}
|
||||
.lede { color: var(--ink-soft); margin: 0 0 1.75rem; }
|
||||
.panel {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.5rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
}
|
||||
.state { margin: 0; font-weight: 500; }
|
||||
.state-warn, .state-err { color: var(--brass-deep); }
|
||||
.state-ok { color: var(--success); }
|
||||
.detail { margin: 0.5rem 0 0; font-size: 0.9rem; color: var(--ink-soft); }
|
||||
.who {
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: var(--brass-deep);
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
/* ---- The form ---- */
|
||||
.field { margin: 0 0 1.1rem; }
|
||||
.field > label { display: block; font-weight: 600; font-size: 0.9rem; margin: 0 0 0.35rem; }
|
||||
input[type="text"], input[type="url"], input[type="email"], textarea, select {
|
||||
width: 100%;
|
||||
font: inherit;
|
||||
padding: 0.6rem 0.7rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: #fff;
|
||||
color: var(--ink);
|
||||
}
|
||||
textarea { resize: vertical; }
|
||||
input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.hint { font-size: 0.82rem; color: var(--ink-soft); margin: 0.35rem 0 0; }
|
||||
.counter { font-size: 0.78rem; color: var(--ink-soft); margin: 0.3rem 0 0; }
|
||||
.counter[data-over="1"] { color: var(--brass-deep); font-weight: 600; }
|
||||
|
||||
fieldset { border: 1px solid var(--line); border-radius: var(--radius); padding: 0.9rem 1rem 0.4rem; margin: 0 0 1.1rem; }
|
||||
legend { font-weight: 600; font-size: 0.9rem; padding: 0 0.35rem; }
|
||||
.row { display: flex; align-items: center; gap: 0.7rem; margin: 0 0 0.7rem; }
|
||||
.row label { flex: 0 0 6.5rem; font-size: 0.85rem; }
|
||||
.row input[type="range"] { flex: 1 1 auto; min-width: 0; }
|
||||
.row output { flex: 0 0 1.6rem; text-align: center; font-variant-numeric: tabular-nums; font-weight: 600; }
|
||||
.total { font-size: 0.85rem; color: var(--ink-soft); margin: 0 0 0.4rem; }
|
||||
.total[data-bad="1"] { color: var(--brass-deep); font-weight: 600; }
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 0.04em;
|
||||
border: 0;
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--brass);
|
||||
color: var(--midnight);
|
||||
padding: 0.7rem 1.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn:hover { background: var(--brass-bright); }
|
||||
.btn:focus-visible { outline: 2px solid var(--midnight); outline-offset: 2px; }
|
||||
.btn[disabled] { opacity: 0.6; cursor: default; }
|
||||
.status { margin: 0.9rem 0 0; font-weight: 500; min-height: 1.2em; }
|
||||
|
||||
/* ---- Delete ---- */
|
||||
.danger { margin-top: 1.75rem; border-top: 1px solid var(--line); padding-top: 1.25rem; }
|
||||
.danger h2 { font-family: Marcellus, Georgia, serif; font-weight: 400; font-size: 1.1rem; margin: 0 0 0.4rem; }
|
||||
.danger p { font-size: 0.88rem; color: var(--ink-soft); margin: 0 0 0.8rem; }
|
||||
.confirm { display: flex; align-items: flex-start; gap: 0.55rem; margin: 0 0 0.9rem; font-size: 0.88rem; }
|
||||
.confirm input { margin-top: 0.25rem; }
|
||||
.btn-danger { background: transparent; border: 1px solid var(--brass-deep); color: var(--brass-deep); }
|
||||
.btn-danger:hover { background: var(--brass-deep); color: #fff; }
|
||||
.btn-danger:focus-visible { outline: 2px solid var(--midnight); outline-offset: 2px; }
|
||||
.photo-readonly { display: flex; align-items: center; gap: 0.8rem; }
|
||||
.photo-readonly img { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; }
|
||||
.photo-readonly .mono {
|
||||
width: 56px; height: 56px; border-radius: 50%;
|
||||
display: grid; place-items: center;
|
||||
background: var(--midnight); color: var(--brass);
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- The 15-point rule, in ONE copy for both forms (this one and the application form). -->
|
||||
<script src="/static/focus-rule.js?v=22ac72a8f0"></script>
|
||||
<script src="/static/photo-upload.js?v=c17638457b"></script>
|
||||
<script src="/static/expert-image.js?v=bad5d8c733"></script>
|
||||
|
||||
<!-- 1) Read the credential, then take it OUT of the address bar.
|
||||
The hash arrives as ?has=... or ?hash=... (both spellings accepted, 'has' first — the
|
||||
same list the answer page reads, so the two emailed links behave identically). The page
|
||||
keeps it in memory for the GET, the save, the delete and a retry; it must never sit in
|
||||
the URL, because Plausible reports location.href. Stripping the query BEFORE the tracker
|
||||
is loaded is what keeps it out of analytics. All wire names and key lists live here. -->
|
||||
<script>
|
||||
window.O4E = {
|
||||
// The node webhook: holds this person's listing (GET) and receives the save + delete.
|
||||
webhook: "https://n8n.odoo4projects.com/webhook/ODOO4projects/odoo_experts_edit",
|
||||
// Query-string spellings to read, in order. Same list as the answer page: the two
|
||||
// emailed links are one shape. Confirm with the owner which spelling the mails carry.
|
||||
hashKeys: ["has", "hash"],
|
||||
// Wire name used OUTWARD on the GET query string.
|
||||
hashWireKey: "has",
|
||||
// SAVE: PATCH the existing record, carrying BOTH the hash (the credential, same key
|
||||
// the delete already sends) and the record id. An id alone authorises nothing: record
|
||||
// ids are small sequential integers, publicly visible on every directory card, so a
|
||||
// request without the hash is refused before it is sent. Match this method in n8n.
|
||||
saveMethod: "PATCH",
|
||||
// DELETE: unverified. A route that refuses it (404/405/501) is a clear failure and
|
||||
// this page never reports success on a non-2xx. Match this method in the workflow.
|
||||
deleteMethod: "DELETE",
|
||||
// How the GET reply is read, in ONE place. The primary name is what the directory
|
||||
// webhook already returns, so the two endpoints agree; a lower-case variant is taken
|
||||
// as the identical fallback. A key NOT listed here is never read.
|
||||
aliases: {
|
||||
id: ["id"],
|
||||
Name: ["Name", "name"],
|
||||
Focus: ["Focus", "focus"],
|
||||
description: ["description", "Description"],
|
||||
Country: ["Country", "country"],
|
||||
OCA_link: ["OCA_link", "oca_link"],
|
||||
// The four profile links. The primary name is the LIVE wire key, casing and all —
|
||||
// "Linkedin", "github", "upwork", "fiverr" are deliberately mixed and must never be
|
||||
// normalised (a normalised key is the silent-drop class that ate odoo_versions). A
|
||||
// same-word casing variant is the identical fallback, the way Name/name already works;
|
||||
// "github" is lower-case on the wire, so it is read exactly as it is, with no variant.
|
||||
Linkedin: ["Linkedin", "linkedin"], github: ["github"], upwork: ["upwork", "Upwork"], fiverr: ["fiverr", "Fiverr"],
|
||||
functional: ["functional"], system: ["system"], modules: ["modules"],
|
||||
integration: ["integration"], ai: ["ai"],
|
||||
english: ["english"], german: ["german"], spanish: ["spanish"]
|
||||
},
|
||||
focusAxes: ["functional", "system", "modules", "integration", "ai"],
|
||||
focusAxisLabels: {
|
||||
functional: "Functional", system: "System", modules: "Modules",
|
||||
integration: "Integration", ai: "AI"
|
||||
},
|
||||
focusTotal: window.O4PFocus.TOTAL,
|
||||
focusMax: 5,
|
||||
focusMaxChars: 70,
|
||||
descMaxChars: 230,
|
||||
langs: [["english", "English"], ["german", "German"], ["spanish", "Spanish"]],
|
||||
// Country VALUE FORMAT the select sends, same as the other forms: the ISO alpha-2 code.
|
||||
countryValueFormat: "code"
|
||||
};
|
||||
|
||||
(function () {
|
||||
var params = new URLSearchParams(location.search);
|
||||
var hash = "";
|
||||
for (var i = 0; i < window.O4E.hashKeys.length; i++) {
|
||||
var v = params.get(window.O4E.hashKeys[i]);
|
||||
if (v) { hash = v; break; }
|
||||
}
|
||||
window.__EDIT_HASH = hash;
|
||||
// Drop the query from the address + history. The hash lives in memory above.
|
||||
if (location.search) history.replaceState(null, "", location.pathname);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- 2) Privacy-friendly analytics by Plausible (verbatim; the page now has no query). -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="wrap">
|
||||
<a class="brand" href="https://odoo4projects.com/">ODOO<span>4</span>projects</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="wrap">
|
||||
<div class="card-wrap">
|
||||
<h1>Edit your listing</h1>
|
||||
<p class="lede">
|
||||
This is your own listing in the Odoo Freelancer Directory. Change what you like here
|
||||
and save it — or delete the listing for good.
|
||||
</p>
|
||||
|
||||
<!-- Filled by the script at the foot of the page. Empty on purpose: with JavaScript
|
||||
off there is no way to load the listing or save a change, so an empty container +
|
||||
the noscript note below is the honest picture. -->
|
||||
<div id="app"></div>
|
||||
|
||||
<noscript>
|
||||
<div class="panel">
|
||||
<p class="state state-warn">This page needs JavaScript to load your listing and to save your changes.</p>
|
||||
<p class="detail">
|
||||
Turn JavaScript on in your browser and open the link again — or reply to the email
|
||||
that brought you here.
|
||||
</p>
|
||||
</div>
|
||||
</noscript>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
var COUNTRIES = [["AD", "Andorra"], ["AE", "United Arab Emirates"], ["AF", "Afghanistan"], ["AG", "Antigua and Barbuda"], ["AI", "Anguilla"], ["AL", "Albania"], ["AM", "Armenia"], ["AO", "Angola"], ["AQ", "Antarctica"], ["AR", "Argentina"], ["AS", "American Samoa"], ["AT", "Austria"], ["AU", "Australia"], ["AW", "Aruba"], ["AX", "Aland"], ["AZ", "Azerbaijan"], ["BA", "Bosnia and Herzegovina"], ["BB", "Barbados"], ["BD", "Bangladesh"], ["BE", "Belgium"], ["BF", "Burkina Faso"], ["BG", "Bulgaria"], ["BH", "Bahrain"], ["BI", "Burundi"], ["BJ", "Benin"], ["BL", "Saint Barthelemy"], ["BM", "Bermuda"], ["BN", "Brunei"], ["BO", "Bolivia"], ["BQ", "Bonaire"], ["BR", "Brazil"], ["BS", "Bahamas"], ["BT", "Bhutan"], ["BV", "Bouvet Island"], ["BW", "Botswana"], ["BY", "Belarus"], ["BZ", "Belize"], ["CA", "Canada"], ["CC", "Cocos (Keeling) Islands"], ["CD", "Democratic Republic of the Congo"], ["CF", "Central African Republic"], ["CG", "Republic of the Congo"], ["CH", "Switzerland"], ["CI", "Ivory Coast"], ["CK", "Cook Islands"], ["CL", "Chile"], ["CM", "Cameroon"], ["CN", "China"], ["CO", "Colombia"], ["CR", "Costa Rica"], ["CU", "Cuba"], ["CV", "Cape Verde"], ["CW", "Curacao"], ["CX", "Christmas Island"], ["CY", "Cyprus"], ["CZ", "Czech Republic"], ["DE", "Germany"], ["DJ", "Djibouti"], ["DK", "Denmark"], ["DM", "Dominica"], ["DO", "Dominican Republic"], ["DZ", "Algeria"], ["EC", "Ecuador"], ["EE", "Estonia"], ["EG", "Egypt"], ["EH", "Western Sahara"], ["ER", "Eritrea"], ["ES", "Spain"], ["ET", "Ethiopia"], ["FI", "Finland"], ["FJ", "Fiji"], ["FK", "Falkland Islands"], ["FM", "Micronesia"], ["FO", "Faroe Islands"], ["FR", "France"], ["GA", "Gabon"], ["GB", "United Kingdom"], ["GD", "Grenada"], ["GE", "Georgia"], ["GF", "French Guiana"], ["GG", "Guernsey"], ["GH", "Ghana"], ["GI", "Gibraltar"], ["GL", "Greenland"], ["GM", "Gambia"], ["GN", "Guinea"], ["GP", "Guadeloupe"], ["GQ", "Equatorial Guinea"], ["GR", "Greece"], ["GS", "South Georgia and the South Sandwich Islands"], ["GT", "Guatemala"], ["GU", "Guam"], ["GW", "Guinea-Bissau"], ["GY", "Guyana"], ["HK", "Hong Kong"], ["HM", "Heard Island and McDonald Islands"], ["HN", "Honduras"], ["HR", "Croatia"], ["HT", "Haiti"], ["HU", "Hungary"], ["ID", "Indonesia"], ["IE", "Ireland"], ["IL", "Israel"], ["IM", "Isle of Man"], ["IN", "India"], ["IO", "British Indian Ocean Territory"], ["IQ", "Iraq"], ["IR", "Iran"], ["IS", "Iceland"], ["IT", "Italy"], ["JE", "Jersey"], ["JM", "Jamaica"], ["JO", "Jordan"], ["JP", "Japan"], ["KE", "Kenya"], ["KG", "Kyrgyzstan"], ["KH", "Cambodia"], ["KI", "Kiribati"], ["KM", "Comoros"], ["KN", "Saint Kitts and Nevis"], ["KP", "North Korea"], ["KR", "South Korea"], ["KW", "Kuwait"], ["KY", "Cayman Islands"], ["KZ", "Kazakhstan"], ["LA", "Laos"], ["LB", "Lebanon"], ["LC", "Saint Lucia"], ["LI", "Liechtenstein"], ["LK", "Sri Lanka"], ["LR", "Liberia"], ["LS", "Lesotho"], ["LT", "Lithuania"], ["LU", "Luxembourg"], ["LV", "Latvia"], ["LY", "Libya"], ["MA", "Morocco"], ["MC", "Monaco"], ["MD", "Moldova"], ["ME", "Montenegro"], ["MF", "Saint Martin"], ["MG", "Madagascar"], ["MH", "Marshall Islands"], ["MK", "North Macedonia"], ["ML", "Mali"], ["MM", "Myanmar (Burma)"], ["MN", "Mongolia"], ["MO", "Macao"], ["MP", "Northern Mariana Islands"], ["MQ", "Martinique"], ["MR", "Mauritania"], ["MS", "Montserrat"], ["MT", "Malta"], ["MU", "Mauritius"], ["MV", "Maldives"], ["MW", "Malawi"], ["MX", "Mexico"], ["MY", "Malaysia"], ["MZ", "Mozambique"], ["NA", "Namibia"], ["NC", "New Caledonia"], ["NE", "Niger"], ["NF", "Norfolk Island"], ["NG", "Nigeria"], ["NI", "Nicaragua"], ["NL", "Netherlands"], ["NO", "Norway"], ["NP", "Nepal"], ["NR", "Nauru"], ["NU", "Niue"], ["NZ", "New Zealand"], ["OM", "Oman"], ["PA", "Panama"], ["PE", "Peru"], ["PF", "French Polynesia"], ["PG", "Papua New Guinea"], ["PH", "Philippines"], ["PK", "Pakistan"], ["PL", "Poland"], ["PM", "Saint Pierre and Miquelon"], ["PN", "Pitcairn Islands"], ["PR", "Puerto Rico"], ["PS", "Palestine"], ["PT", "Portugal"], ["PW", "Palau"], ["PY", "Paraguay"], ["QA", "Qatar"], ["RE", "Reunion"], ["RO", "Romania"], ["RS", "Serbia"], ["RU", "Russia"], ["RW", "Rwanda"], ["SA", "Saudi Arabia"], ["SB", "Solomon Islands"], ["SC", "Seychelles"], ["SD", "Sudan"], ["SE", "Sweden"], ["SG", "Singapore"], ["SH", "Saint Helena"], ["SI", "Slovenia"], ["SJ", "Svalbard and Jan Mayen"], ["SK", "Slovakia"], ["SL", "Sierra Leone"], ["SM", "San Marino"], ["SN", "Senegal"], ["SO", "Somalia"], ["SR", "Suriname"], ["SS", "South Sudan"], ["ST", "Sao Tome and Principe"], ["SV", "El Salvador"], ["SX", "Sint Maarten"], ["SY", "Syria"], ["SZ", "Eswatini"], ["TC", "Turks and Caicos Islands"], ["TD", "Chad"], ["TF", "French Southern Territories"], ["TG", "Togo"], ["TH", "Thailand"], ["TJ", "Tajikistan"], ["TK", "Tokelau"], ["TL", "East Timor"], ["TM", "Turkmenistan"], ["TN", "Tunisia"], ["TO", "Tonga"], ["TR", "Turkey"], ["TT", "Trinidad and Tobago"], ["TV", "Tuvalu"], ["TW", "Taiwan"], ["TZ", "Tanzania"], ["UA", "Ukraine"], ["UG", "Line truncated
|
||||
</script>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var C = window.O4E;
|
||||
var CG = window.O4PFocus; // the shared 15-point rule (static/focus-rule.js)
|
||||
var app = document.getElementById("app");
|
||||
var hash = window.__EDIT_HASH || "";
|
||||
var rec = null; // this person's record, once loaded
|
||||
|
||||
function el(tag, cls, text) {
|
||||
var n = document.createElement(tag);
|
||||
if (cls) n.className = cls;
|
||||
if (text != null) n.textContent = text; // textContent only: a record is never markup
|
||||
return n;
|
||||
}
|
||||
function show(nodes) {
|
||||
while (app.firstChild) app.removeChild(app.firstChild);
|
||||
var box = el("div", "panel");
|
||||
for (var i = 0; i < nodes.length; i++) box.appendChild(nodes[i]);
|
||||
app.appendChild(box);
|
||||
}
|
||||
function status(text, kind) {
|
||||
var p = el("p", "state" + (kind ? " state-" + kind : ""), text);
|
||||
p.setAttribute("role", "status");
|
||||
p.setAttribute("aria-live", "polite");
|
||||
return p;
|
||||
}
|
||||
function retryButton() {
|
||||
var b = el("button", "btn", "Try again");
|
||||
b.type = "button";
|
||||
b.addEventListener("click", load);
|
||||
return b;
|
||||
}
|
||||
function messageOf(bodyText) {
|
||||
try { return String((JSON.parse(bodyText) || {}).message || ""); }
|
||||
catch (e) { return ""; }
|
||||
}
|
||||
|
||||
// ---- the states -------------------------------------------------------------------
|
||||
function noCode() {
|
||||
show([
|
||||
status("This link is incomplete — it arrived without its code.", "warn"),
|
||||
el("p", "detail", "Open it again from the email that brought you here.")
|
||||
]);
|
||||
}
|
||||
// A MISSING WORKFLOW must not read as an expired invitation. This is our problem.
|
||||
function configError(httpStatus, msg) {
|
||||
show([
|
||||
status("The edit service is not available right now.", "warn"),
|
||||
el("p", "detail",
|
||||
"This is a problem at our end, not with your link. Nothing is wrong with your " +
|
||||
"listing. Please try again later, or reply to the email that brought you here."),
|
||||
el("p", "detail", "The service answered " + httpStatus + (msg ? " — " + msg : "") + ".")
|
||||
]);
|
||||
}
|
||||
// 404 / 500 "No item to return was found" — the hash is wrong or has expired.
|
||||
function invalidLink(httpStatus, msg) {
|
||||
show([
|
||||
status("This link is not valid, or it has expired.", "warn"),
|
||||
el("p", "detail", "The service answered " + httpStatus + (msg ? " — " + msg : "") + "."),
|
||||
el("p", "detail", "If you think that is wrong, reply to the email that brought you here.")
|
||||
]);
|
||||
}
|
||||
function loadFailed(httpStatus, msg) {
|
||||
show([
|
||||
status("We could not load your listing.", "warn"),
|
||||
el("p", "detail", "The service answered " + httpStatus + (msg ? " — " + msg : "") + "."),
|
||||
retryButton()
|
||||
]);
|
||||
}
|
||||
// Honest about a shape we did not expect: name the fields, never a value.
|
||||
function shapeMismatch(names) {
|
||||
show([
|
||||
status("We could not read your listing from the reply from the service.", "warn"),
|
||||
el("p", "detail",
|
||||
names.length
|
||||
? "The reply carried these fields: " + names.join(", ") + "."
|
||||
: "The reply carried no readable data."),
|
||||
retryButton()
|
||||
]);
|
||||
}
|
||||
|
||||
// ---- reading the record -----------------------------------------------------------
|
||||
function unwrap(payload) {
|
||||
if (Array.isArray(payload)) return payload[0] || null;
|
||||
if (payload && typeof payload === "object") {
|
||||
if (Array.isArray(payload.data)) return payload.data[0] || null;
|
||||
if (Array.isArray(payload.items)) return payload.items[0] || null;
|
||||
if (payload.data && typeof payload.data === "object") return payload.data;
|
||||
return payload;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// Read one field by its list of accepted names. NEVER a value we did not expect:
|
||||
// anything not in C.aliases is unreadable.
|
||||
function readField(obj, key) {
|
||||
var names = C.aliases[key] || [key];
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var v = obj[names[i]];
|
||||
if (v !== undefined && v !== null && v !== "") return v;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
function hasAnyMappedField(obj) {
|
||||
for (var key in C.aliases) {
|
||||
if (key === "id") continue;
|
||||
if (readField(obj, key) !== undefined) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function num(value, fallback) {
|
||||
var n = parseInt(value, 10);
|
||||
return isNaN(n) ? fallback : n;
|
||||
}
|
||||
function clamp05(n) { return Math.max(0, Math.min(C.focusMax, n)); }
|
||||
function initials(name) {
|
||||
var parts = String(name || "").trim().split(/\s+/).filter(Boolean);
|
||||
if (!parts.length) return "?";
|
||||
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
|
||||
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
||||
}
|
||||
|
||||
// ---- the form ---------------------------------------------------------------------
|
||||
function textField(id, labelText, value, maxLength, hint) {
|
||||
var wrap = el("div", "field");
|
||||
var label = el("label", "", labelText);
|
||||
label.setAttribute("for", id);
|
||||
var input = el("input");
|
||||
input.type = "text";
|
||||
input.id = id;
|
||||
input.name = id;
|
||||
input.value = value == null ? "" : String(value);
|
||||
if (maxLength) { input.maxLength = maxLength; input.setAttribute("aria-describedby", id + "Count"); }
|
||||
wrap.appendChild(label);
|
||||
wrap.appendChild(input);
|
||||
if (maxLength) {
|
||||
var counter = el("p", "counter", input.value.length + " / " + maxLength);
|
||||
counter.id = id + "Count";
|
||||
input.addEventListener("input", function () {
|
||||
var n = input.value.length;
|
||||
counter.textContent = n + " / " + maxLength;
|
||||
counter.setAttribute("data-over", n > maxLength ? "1" : "0");
|
||||
});
|
||||
counter.setAttribute("data-over", input.value.length > maxLength ? "1" : "0");
|
||||
wrap.appendChild(counter);
|
||||
}
|
||||
if (hint) wrap.appendChild(el("p", "hint", hint));
|
||||
return wrap;
|
||||
}
|
||||
|
||||
// An optional profile link. A real `type="url"` input with the application form's own
|
||||
// label and placeholder, so the two forms ask for a link the same way. No URL check
|
||||
// lives here: the value is passed through untouched, and the ONLY url predicate in the
|
||||
// fleet is the directory card's isLink() (a prefix allowlist) — one check, not two.
|
||||
function linkField(id, name, labelText, value, placeholder) {
|
||||
var wrap = el("div", "field");
|
||||
var label = el("label", "", labelText);
|
||||
label.setAttribute("for", id);
|
||||
label.appendChild(el("span", "hint", " (optional)"));
|
||||
var input = el("input");
|
||||
input.type = "url";
|
||||
input.id = id;
|
||||
input.name = name;
|
||||
input.value = value == null ? "" : String(value);
|
||||
input.placeholder = placeholder;
|
||||
wrap.appendChild(label);
|
||||
wrap.appendChild(input);
|
||||
return wrap;
|
||||
}
|
||||
|
||||
function rangeField(fieldset, name, labelText, value) {
|
||||
var row = el("div", "row");
|
||||
var label = el("label", "", labelText);
|
||||
label.setAttribute("for", "ed-" + name);
|
||||
var input = el("input");
|
||||
input.type = "range";
|
||||
input.id = "ed-" + name;
|
||||
input.name = name;
|
||||
input.min = "0";
|
||||
input.max = String(C.focusMax);
|
||||
input.step = "1";
|
||||
input.value = String(clamp05(num(value, 0)));
|
||||
input.setAttribute("aria-valuetext", input.value + " of " + C.focusMax);
|
||||
var out = el("output", "", input.value);
|
||||
out.setAttribute("for", "ed-" + name);
|
||||
input.addEventListener("input", function () {
|
||||
input.setAttribute("aria-valuetext", input.value + " of " + C.focusMax);
|
||||
out.textContent = input.value;
|
||||
updateTotal();
|
||||
});
|
||||
row.appendChild(label);
|
||||
row.appendChild(input);
|
||||
row.appendChild(out);
|
||||
fieldset.appendChild(row);
|
||||
}
|
||||
|
||||
function countrySelect(selected) {
|
||||
var sel = el("select");
|
||||
sel.id = "edCountry";
|
||||
sel.name = "Country";
|
||||
sel.appendChild(new Option("— choose —", ""));
|
||||
COUNTRIES.forEach(function (pair) {
|
||||
var o = new Option(pair[1], C.countryValueFormat === "name" ? pair[1] : pair[0]);
|
||||
var want = String(selected == null ? "" : selected).trim();
|
||||
if (want && (want.toUpperCase() === pair[0] || want === pair[1])) o.selected = true;
|
||||
sel.appendChild(o);
|
||||
});
|
||||
return sel;
|
||||
}
|
||||
|
||||
var focusTotalLine = null;
|
||||
function focusSum() {
|
||||
var sum = 0;
|
||||
C.focusAxes.forEach(function (axis) {
|
||||
var el2 = document.getElementById("ed-" + axis);
|
||||
sum += el2 ? num(el2.value, 0) : 0;
|
||||
});
|
||||
return sum;
|
||||
}
|
||||
function updateTotal() {
|
||||
if (!focusTotalLine) return;
|
||||
var sum = focusSum();
|
||||
focusTotalLine.textContent = sum + " of " + C.focusTotal + " points";
|
||||
focusTotalLine.setAttribute("data-bad", sum === C.focusTotal ? "0" : "1");
|
||||
}
|
||||
|
||||
function renderForm(record) {
|
||||
rec = record;
|
||||
var who = readField(record, "Name");
|
||||
var nodes = [];
|
||||
nodes.push(el("p", "who", "Listing: " + (who ? String(who) : "(no name)")));
|
||||
|
||||
var form = el("form", "edit-form");
|
||||
form.setAttribute("novalidate", "novalidate"); // JS announces errors instead
|
||||
|
||||
form.appendChild(textField("edName", "Name", readField(record, "Name"), 0, null));
|
||||
form.appendChild(textField("edFocus", "Focus", readField(record, "Focus"),
|
||||
C.focusMaxChars, "One short line — the kind of work you want, at most " + C.focusMaxChars + " characters."));
|
||||
|
||||
var descWrap = el("div", "field");
|
||||
var descLabel = el("label", "", "About you");
|
||||
descLabel.setAttribute("for", "edDescription");
|
||||
var ta = el("textarea");
|
||||
ta.id = "edDescription";
|
||||
ta.name = "edDescription";
|
||||
ta.rows = 6;
|
||||
ta.maxLength = C.descMaxChars;
|
||||
ta.value = String(readField(record, "description") == null ? "" : readField(record, "description"));
|
||||
ta.setAttribute("aria-describedby", "edDescriptionCount");
|
||||
var descCount = el("p", "counter", ta.value.length + " / " + C.descMaxChars);
|
||||
descCount.id = "edDescriptionCount";
|
||||
ta.addEventListener("input", function () {
|
||||
var n = ta.value.length;
|
||||
descCount.textContent = n + " / " + C.descMaxChars;
|
||||
descCount.setAttribute("data-over", n > C.descMaxChars ? "1" : "0");
|
||||
});
|
||||
descCount.setAttribute("data-over", ta.value.length > C.descMaxChars ? "1" : "0");
|
||||
descWrap.appendChild(descLabel);
|
||||
descWrap.appendChild(ta);
|
||||
descWrap.appendChild(descCount);
|
||||
form.appendChild(descWrap);
|
||||
|
||||
// The five axes. An axis the record does not carry keeps the application form's
|
||||
// default of 3, so the block always totals 15 and can be saved.
|
||||
var axesSet = el("fieldset", "");
|
||||
axesSet.appendChild(el("legend", "", CG.LEGEND));
|
||||
// The same directive the application form carries, so both forms state the rule.
|
||||
axesSet.appendChild(el("p", "hint", CG.DIRECTIVE));
|
||||
C.focusAxes.forEach(function (axis) {
|
||||
var v = readField(record, axis);
|
||||
if (v === undefined || v === null || v === "") v = 3; // → the block totals 15
|
||||
rangeField(axesSet, axis, C.focusAxisLabels[axis] || axis, v);
|
||||
});
|
||||
form.appendChild(axesSet);
|
||||
focusTotalLine = el("p", "total", "");
|
||||
focusTotalLine.id = "edFocusTotal";
|
||||
focusTotalLine.setAttribute("role", "status");
|
||||
focusTotalLine.setAttribute("aria-live", "polite");
|
||||
form.appendChild(focusTotalLine);
|
||||
|
||||
var langsSet = el("fieldset", "");
|
||||
langsSet.appendChild(el("legend", "", "Languages (0 = do not use it)"));
|
||||
C.langs.forEach(function (pair) {
|
||||
rangeField(langsSet, pair[0], pair[1], readField(record, pair[0]));
|
||||
});
|
||||
form.appendChild(langsSet);
|
||||
|
||||
var countryWrap = el("div", "field");
|
||||
var countryLabel = el("label", "", "Country");
|
||||
countryLabel.setAttribute("for", "edCountry");
|
||||
countryWrap.appendChild(countryLabel);
|
||||
countryWrap.appendChild(countrySelect(readField(record, "Country")));
|
||||
form.appendChild(countryWrap);
|
||||
|
||||
form.appendChild(textField("edOcaLink", "OCA member profile link", readField(record, "OCA_link"),
|
||||
0, "Your OCA profile URL, if you have one: https://apps.odoo-community.org/community/…"));
|
||||
|
||||
// The four profile links — parity with the application form. Keys are the LIVE wire
|
||||
// keys verbatim ("Linkedin" capital L; "github", "upwork" and "fiverr" lower) and the
|
||||
// labels and placeholders are the application form's own. Each is optional and
|
||||
// pre-filled from the record.
|
||||
form.appendChild(linkField("edLinkedin", "Linkedin", "LinkedIn URL",
|
||||
readField(record, "Linkedin"), "https://www.linkedin.com/in/…"));
|
||||
form.appendChild(linkField("edGithub", "github", "GitHub URL",
|
||||
readField(record, "github"), "https://github.com/…"));
|
||||
form.appendChild(linkField("edUpwork", "upwork", "Upwork URL",
|
||||
readField(record, "upwork"), "https://www.upwork.com/freelancers/…"));
|
||||
form.appendChild(linkField("edFiverr", "fiverr", "Fiverr URL",
|
||||
readField(record, "fiverr"), "https://www.fiverr.com/…"));
|
||||
|
||||
// The photo block is a LOOK, not a field. The photo does not live in this record
|
||||
// any more — the payload carries no `Image` — it comes from its own endpoint,
|
||||
// addressed by the record id (window.O4PExpertImage). So nothing here edits it,
|
||||
// and the save below sends no `Image` key at all: not the value, not null, not "".
|
||||
var photoWrap = el("div", "field");
|
||||
photoWrap.appendChild(el("label", "", "Photo"));
|
||||
var photoRow = el("div", "photo-readonly");
|
||||
var photoMono = el("span", "mono", initials(who));
|
||||
photoRow.appendChild(photoMono);
|
||||
if (rec && rec.id !== undefined && rec.id !== null && rec.id !== "") {
|
||||
// Same fetch the directory card makes: the route answers JSON, not image bytes,
|
||||
// so the value is read from `Image` and only then put on an <img>. Any failure
|
||||
// (or a value that fails isImageSrc) leaves the monogram standing.
|
||||
O4PExpertImage.load(String(rec.id)).then(function (src) {
|
||||
if (!src) return;
|
||||
var photoImg = el("img");
|
||||
photoImg.id = "edImagePreview";
|
||||
photoImg.alt = "";
|
||||
photoImg.decoding = "async";
|
||||
photoImg.addEventListener("load", function () {
|
||||
if (photoMono.parentNode) photoMono.parentNode.replaceChild(photoImg, photoMono);
|
||||
}, { once: true });
|
||||
photoImg.addEventListener("error", function () {
|
||||
// A failing photo is the monogram: no broken-image icon, no empty box.
|
||||
if (photoImg.parentNode) photoImg.parentNode.removeChild(photoImg);
|
||||
}, { once: true });
|
||||
photoImg.src = src;
|
||||
});
|
||||
}
|
||||
photoWrap.appendChild(photoRow);
|
||||
photoWrap.appendChild(el("p", "hint",
|
||||
"Your photo comes from your listing and is not editable here — reply to the email " +
|
||||
"that brought you here if it needs to change."));
|
||||
form.appendChild(photoWrap);
|
||||
|
||||
var save = el("button", "btn", "Save my changes");
|
||||
save.type = "submit";
|
||||
var line = el("p", "status", "");
|
||||
line.id = "editStatus";
|
||||
line.setAttribute("role", "status");
|
||||
line.setAttribute("aria-live", "polite");
|
||||
|
||||
form.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
if (focusSum() !== C.focusTotal) {
|
||||
var sum = focusSum();
|
||||
line.className = "status state-err";
|
||||
line.textContent = CG.message(sum); // names the direction: remove / add / place all
|
||||
focusTotalLine.setAttribute("data-bad", "1");
|
||||
return;
|
||||
}
|
||||
// A save is authorised by the HASH, not by the id. If this page holds no hash there
|
||||
// is nothing to prove ownership, so the request is not fired at all — a PATCH
|
||||
// carrying only an id is exactly the hole this closes. Say why, do not fail silently.
|
||||
if (!hash) {
|
||||
line.className = "status state-err";
|
||||
line.textContent = "This link arrived without its code, so we cannot save your " +
|
||||
"changes. Open it again from the email that brought you here.";
|
||||
return;
|
||||
}
|
||||
save.disabled = true;
|
||||
line.className = "status";
|
||||
line.textContent = "Saving…";
|
||||
// The body shape: READ-MODIFY-WRITE. Start from the record the webhook returned and
|
||||
// overwrite ONLY the fields this form owns. A field-by-field payload is what deletes a
|
||||
// freelancer's own photo and links on save — a partial payload wipes what it leaves
|
||||
// out, so the whole record goes back and only the edited keys are replaced. The
|
||||
// credential rides first: "has" is the SAME key the delete sends (one credential path
|
||||
// for both), then the record's id. Method is C.saveMethod ("PATCH").
|
||||
var payload = { has: hash };
|
||||
if (rec) {
|
||||
Object.keys(rec).forEach(function (k) {
|
||||
if (k === "has") return; // never let the record's own "has" shadow the credential
|
||||
payload[k] = rec[k]; // Image, the links, createdAt/updatedAt and everything else
|
||||
});
|
||||
}
|
||||
payload.id = rec && rec.id !== undefined ? rec.id : undefined;
|
||||
payload.Name = document.getElementById("edName").value.trim();
|
||||
payload.Focus = document.getElementById("edFocus").value.trim();
|
||||
payload.description = document.getElementById("edDescription").value.trim();
|
||||
payload.Country = document.getElementById("edCountry").value;
|
||||
payload.OCA_link = document.getElementById("edOcaLink").value.trim();
|
||||
C.focusAxes.forEach(function (axis) { payload[axis] = num(document.getElementById("ed-" + axis).value, 0); });
|
||||
C.langs.forEach(function (pair) { payload[pair[0]] = num(document.getElementById("ed-" + pair[0]).value, 0); });
|
||||
// The four links, read from their inputs. Only a key we actually have a value for is
|
||||
// touched: an empty optional field must NOT invent an empty string on a record that
|
||||
// never had one — the record's own value (null, or absent) is already in the payload
|
||||
// and is left as it is. A link the record DID carry and the owner cleared is a
|
||||
// deliberate clear and sends "".
|
||||
[["edLinkedin", "Linkedin"], ["edGithub", "github"], ["edUpwork", "upwork"], ["edFiverr", "fiverr"]].forEach(function (pair) {
|
||||
var input = document.getElementById(pair[0]);
|
||||
if (!input) return;
|
||||
var v = input.value.trim();
|
||||
var had = rec && rec[pair[1]] !== undefined && rec[pair[1]] !== null && rec[pair[1]] !== "";
|
||||
if (v) payload[pair[1]] = v;
|
||||
else if (had) payload[pair[1]] = "";
|
||||
});
|
||||
|
||||
// The photo does NOT ride in this record any more: the payload carries no
|
||||
// `Image` key and this form sends none — not the value, not null, not "". The
|
||||
// delete is the guarantee, whatever a reply may one day carry.
|
||||
delete payload.Image;
|
||||
|
||||
fetch(C.webhook, {
|
||||
method: C.saveMethod,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res.ok) throw new Error("HTTP " + res.status);
|
||||
// A RECEIPT, not a delivery claim: n8n answers 200 before the workflow runs.
|
||||
line.className = "status state-ok";
|
||||
line.textContent = "Saved — we have your changes. They go live once confirmed.";
|
||||
})
|
||||
.catch(function () {
|
||||
// Non-2xx or network: never a receipt; the data stays in the form.
|
||||
line.className = "status state-err";
|
||||
line.textContent = "We could not save your changes just now. Your edits are still " +
|
||||
"in the form — please try again, or reply to the email that brought you here.";
|
||||
})
|
||||
.then(function () { save.disabled = false; });
|
||||
});
|
||||
|
||||
form.appendChild(save);
|
||||
form.appendChild(line);
|
||||
nodes.push(form);
|
||||
nodes.push(deleteBlock());
|
||||
show(nodes);
|
||||
// The total needs the fields in the document to sum them — do it after show().
|
||||
updateTotal();
|
||||
}
|
||||
|
||||
// ---- delete -----------------------------------------------------------------------
|
||||
function deleteBlock() {
|
||||
var box = el("div", "danger");
|
||||
box.appendChild(el("h2", "", "Delete this listing"));
|
||||
box.appendChild(el("p", "",
|
||||
"This removes your public listing for good. It cannot be undone from our side. " +
|
||||
"Tick the box and confirm — nothing is deleted until you do."));
|
||||
var confirmWrap = el("label", "confirm");
|
||||
var box_in = el("input");
|
||||
box_in.type = "checkbox";
|
||||
box_in.id = "edConfirmDelete";
|
||||
confirmWrap.appendChild(box_in);
|
||||
confirmWrap.appendChild(el("span", "",
|
||||
"Yes, delete my listing permanently."));
|
||||
box.appendChild(confirmWrap);
|
||||
|
||||
var del = el("button", "btn btn-danger", "Delete my listing");
|
||||
del.type = "button";
|
||||
del.disabled = true;
|
||||
var line = el("p", "status", "");
|
||||
line.id = "deleteStatus";
|
||||
line.setAttribute("role", "status");
|
||||
line.setAttribute("aria-live", "polite");
|
||||
|
||||
// The deliberate second action: the button cannot fire until the box is ticked.
|
||||
box_in.addEventListener("change", function () { del.disabled = !box_in.checked; });
|
||||
|
||||
del.addEventListener("click", function () {
|
||||
if (!box_in.checked) return;
|
||||
del.disabled = true;
|
||||
box_in.disabled = true;
|
||||
line.className = "status";
|
||||
line.textContent = "Deleting…";
|
||||
// DELETE with the credential and the record id. C.deleteMethod is the one place
|
||||
// the method lives; the id wire key is the record's own "id".
|
||||
fetch(C.webhook, {
|
||||
method: C.deleteMethod,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ has: hash, id: rec && rec.id !== undefined ? rec.id : null })
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res.ok) throw new Error("HTTP " + res.status);
|
||||
// Only a 2xx is a success. Anything else fails below.
|
||||
line.className = "status state-ok";
|
||||
line.textContent = "Your listing has been deleted. Thank you for having been listed.";
|
||||
del.hidden = true;
|
||||
confirmWrap.hidden = true;
|
||||
})
|
||||
.catch(function () {
|
||||
box_in.disabled = false;
|
||||
del.disabled = !box_in.checked;
|
||||
line.className = "status state-err";
|
||||
line.textContent = "We could not delete your listing just now — nothing was removed. " +
|
||||
"Please try again, or reply to the email that brought you here.";
|
||||
});
|
||||
});
|
||||
|
||||
box.appendChild(del);
|
||||
box.appendChild(line);
|
||||
return box;
|
||||
}
|
||||
|
||||
// ---- the GET ----------------------------------------------------------------------
|
||||
function load() {
|
||||
if (!hash) { noCode(); return; }
|
||||
show([status("Loading your listing…")]);
|
||||
|
||||
fetch(C.webhook + "?" + encodeURIComponent(C.hashWireKey) + "=" + encodeURIComponent(hash), {
|
||||
headers: { Accept: "application/json" }
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res.ok) {
|
||||
return res.text().then(function (body) {
|
||||
var msg = messageOf(body);
|
||||
// A missing workflow is a CONFIGURATION error — never "your link is invalid".
|
||||
if (/is not registered/i.test(msg)) { configError(res.status, msg); return; }
|
||||
if (res.status === 404 || res.status === 500) { invalidLink(res.status, msg); return; }
|
||||
loadFailed(res.status, msg);
|
||||
});
|
||||
}
|
||||
return res.json().then(function (payload) {
|
||||
var obj = unwrap(payload);
|
||||
if (!obj) { shapeMismatch([]); return; }
|
||||
if (!hasAnyMappedField(obj)) { shapeMismatch(Object.keys(obj)); return; }
|
||||
renderForm(obj);
|
||||
}).catch(function () {
|
||||
shapeMismatch([]);
|
||||
});
|
||||
})
|
||||
.catch(function () {
|
||||
// Network failure: the hash is still in memory, so a retry needs no new link.
|
||||
show([
|
||||
status("We could not load your listing just now.", "warn"),
|
||||
el("p", "detail", "Your link has been kept, so you can try again."),
|
||||
retryButton()
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
load();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 155 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -128,7 +128,9 @@
|
||||
.hero-stats{display:flex;gap:1.5rem;margin-bottom:2rem;flex-wrap:wrap}.hero-stat{display:flex;align-items:center;gap:.4rem;color:rgba(255,255,255,.65);font-size:.85rem}.hero-stat i{color:var(--brass);font-size:.75rem}
|
||||
.hero-actions{display:flex;gap:1rem;flex-wrap:wrap;margin-bottom:2rem}
|
||||
.hero-notice{position:absolute;top:1.25rem;right:1.25rem;z-index:3;display:flex;align-items:center;gap:.55rem;max-width:min(360px,calc(100% - 2rem));padding:.6rem .85rem .6rem 1rem;background:#f5c542;color:var(--midnight);border:1px solid rgba(13,27,46,.14);border-radius:var(--radius);box-shadow:0 8px 24px rgba(13,27,46,.3);font-family:Inter,sans-serif;font-size:.82rem;line-height:1.4;animation:heroNoticeIn .4s cubic-bezier(.16,1,.3,1)}
|
||||
.hero-notice[hidden]{display:none}
|
||||
/* `.hero-notice[hidden]{display:none}` used to live here; the site-wide `[hidden]`
|
||||
rule in /style.css hides it (`.hero-notice` sets `display:flex`, which outranked
|
||||
the UA rule). */
|
||||
.hero-notice i{color:var(--midnight);font-size:.9rem;flex-shrink:0}
|
||||
.hero-notice-text{flex:1;min-width:0;overflow-wrap:anywhere}
|
||||
.hero-notice-close{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:1.35rem;height:1.35rem;padding:0;border:0;border-radius:50%;background:rgba(13,27,46,.12);color:var(--midnight);font-size:1rem;line-height:1;cursor:pointer;transition:background .2s}
|
||||
@@ -219,16 +221,25 @@
|
||||
#customQuoteModal .biz-success h3{color:var(--midnight)}
|
||||
#customQuoteModal .biz-success p{color:var(--midnight)}
|
||||
@media(max-width:600px){.oca-table td,.oca-table th{padding:.5rem .65rem;font-size:.8rem}.ow-panel{left:5%;right:5%}.ow-close{top:.5rem;right:.5rem;font-size:1.6rem}}
|
||||
/* Black Friday 2026 — seasonal top banner. Live 2-30 November 2026 only: remove this rule
|
||||
together with the .bf-topbar markup block at the top of <body> after 30 November 2026.
|
||||
CI: midnight canvas, brass label/code/CTA only, cream-white body text. No script, no tag. */
|
||||
.bf-topbar{display:flex;align-items:center;justify-content:center;gap:.3rem 1rem;flex-wrap:wrap;background:var(--midnight);border-bottom:1px solid var(--line-brass);padding:.65rem 1.25rem;font-family:Inter,sans-serif;font-size:.82rem;line-height:1.5;color:rgba(255,255,255,.82);text-align:center;text-decoration:none}
|
||||
.bf-topbar:hover,.bf-topbar:focus-visible{background:var(--midnight-2);color:#fff}
|
||||
.bf-topbar-badge{font-family:Marcellus,Georgia,serif;font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;color:var(--brass);white-space:nowrap}
|
||||
.bf-topbar strong{color:#fff;font-weight:600}
|
||||
.bf-topbar-code{font-family:Marcellus,Georgia,serif;letter-spacing:.06em;color:var(--brass-bright)}
|
||||
.bf-topbar-cta{color:var(--brass);white-space:nowrap}
|
||||
.bf-topbar:hover .bf-topbar-cta,.bf-topbar:focus-visible .bf-topbar-cta{color:var(--brass-bright)}
|
||||
</style>
|
||||
<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="style.css" /></noscript>
|
||||
<link rel="stylesheet" href="style.css?v=061517baef" />
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!--
|
||||
@@ -239,7 +250,18 @@
|
||||
FORM: The Grand Hotel Business Lounge (model-pick, user-chosen). Seed key: 7db4dced.
|
||||
FINISH: unreviewed and undocumented is unfinished; this build ends with the finish review, the verdict, and DESIGN.md.
|
||||
-->
|
||||
<!-- Black Friday 2026 — seasonal banner. Live 2-30 November 2026 only: remove this whole block
|
||||
(and the .bf-topbar rules in <style>) after 30 November 2026. It is one link to the deal page:
|
||||
no script, no tracking tag, no event. The offer itself lives on /odoo-black-friday/ only. -->
|
||||
<a class="bf-topbar" href="/odoo-black-friday/">
|
||||
<span class="bf-topbar-badge">Black Friday</span>
|
||||
<span><strong>$100 off your first year</strong> · On the Rise: $395 a year list → $295 for your first year</span>
|
||||
<span>Code <span class="bf-topbar-code">HOST27</span> · Ends 30 November 2026</span>
|
||||
<span class="bf-topbar-cta">See the offer →</span>
|
||||
</a>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero">
|
||||
<div class="hero-notice" id="heroConfirmNotice" role="status" aria-live="polite" hidden>
|
||||
<i class="fas fa-check-circle" aria-hidden="true"></i>
|
||||
@@ -362,30 +384,38 @@
|
||||
<div class="container">
|
||||
<h2 class="section-title">Frequently asked questions</h2>
|
||||
<div class="faq-grid">
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>What if I outgrow my plan?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Grow from Side Hustle to Empire without data migration or downtime. Upgrade in your Odoo Settings panel — your instance stays live, your data moves with you.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Can I customize it?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Yes. On the Rise and above support Git-based modules. Install custom apps, build your own, or use Quick GIT for one-click installs.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>How fast can I get started?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Five minutes. Pick a plan, choose your region — your Odoo instance is live. No setup fee. Stripe payment. Cancel anytime.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Can I run Odoo Enterprise?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Powerhouse and Empire are Enterprise-ready. Bring your license; we provide the infrastructure.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>ODOO Community? What can it do?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Inventory, accounting, CRM, sales, manufacturing, HR — all in one system. Free and fully open-source.</p></div>
|
||||
<div class="faq-a"><p>Inventory, accounting, CRM, sales, manufacturing, HR — all in one system. Free and fully open-source. <a href="what-can-i-use-odoo-for/">What you can use Odoo for, in plain English</a>.</p></div>
|
||||
</div>
|
||||
<div class="faq-card" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Do you need an Odoo staging environment?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>Most small businesses do not. If you change Odoo's code you do; if you install a finished module, a backup and a careful test is enough. <a href="odoo-staging-environment/">Do you need an Odoo staging environment?</a></p></div>
|
||||
</div>
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>Do you have an affiliate program?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>No. We believe it is in our best interest to have competitive prices for our shared clients.</p></div>
|
||||
</div>
|
||||
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||
<div class="faq-q"><span>I need a developer for a custom module — where do I find one?</span> <i class="fas fa-chevron-down"></i></div>
|
||||
<div class="faq-a"><p>We keep a directory of independent Odoo freelancers. Each card carries what the freelancer published and their contact details where they published them. <a href="odoo-community-developers/">Browse the Odoo freelancers</a>.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="support.html" class="faq-link">Full FAQ →</a>
|
||||
</div>
|
||||
@@ -415,7 +445,7 @@
|
||||
<small class="price-period">/ year</small>
|
||||
</div>
|
||||
<p class="desc">"ODOO Standard .. that is all my business needs"</p>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy" data-id="6">Buy Now</a>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="6">Buy Now</a>
|
||||
<ul>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Launch Odoo CE in 5 minutes</li>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Automatic backups — no remembering</li>
|
||||
@@ -433,7 +463,7 @@
|
||||
<small class="price-period">/ year</small>
|
||||
</div>
|
||||
<p class="desc">"I need some modules and professional reports"</p>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy" data-id="4">Buy Now</a>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="4">Buy Now</a>
|
||||
<ul>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Launch Odoo CE in 5 minutes</li>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Automatic backups — no remembering</li>
|
||||
@@ -452,7 +482,7 @@
|
||||
<small class="price-period">/ year</small>
|
||||
</div>
|
||||
<p class="desc">"ODOO Enterprise is a must have!"</p>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy" data-id="5">Buy Now</a>
|
||||
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="5">Buy Now</a>
|
||||
<ul>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Launch Odoo CE in 5 minutes</li>
|
||||
<li><i class="fas fa-check" style="color: var(--success)"></i> Automatic backups — no remembering</li>
|
||||
@@ -495,7 +525,7 @@
|
||||
<h2 class="ow-title" id="orderPlanTitle">On the Rise</h2>
|
||||
<p class="ow-price">
|
||||
<span class="ow-price-amount" id="orderPlanPrice">$ 395.00</span> <span id="orderPlanPeriod">/ year</span>
|
||||
<span class="ow-price-tax" id="orderPlanTax">+ tax</span>
|
||||
<span class="ow-price-tax" id="orderPlanTax">tax included</span>
|
||||
</p>
|
||||
<p class="ow-coupon-msg" id="orderCouponMsg">Questions before you buy? Ask the assistant on this page.</p>
|
||||
<p class="ow-yearly-save" id="orderYearlySave">Billed yearly. No setup fee.</p>
|
||||
@@ -563,6 +593,7 @@
|
||||
<div class="container">
|
||||
<p class="section-kicker">OCA Modules</p>
|
||||
<h2 class="section-title">Our Top OCA Module Picks</h2>
|
||||
<p style="max-width:760px;margin:0 auto 1.5rem;text-align:center;color:rgba(255,255,255,.72);font-size:.95rem;line-height:1.7">Every module on this list is checked by our robots daily; <a href="/blog/posts/track-the-oca-modules-you-actually-use.html">why we track OCA modules</a> explains what the columns mean and how to read them before an upgrade.</p>
|
||||
<div class="oca-search-wrap">
|
||||
<input type="text" class="oca-search" id="ocaSearch" placeholder="Search modules..." />
|
||||
</div>
|
||||
@@ -624,6 +655,7 @@
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
@@ -632,6 +664,7 @@
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="legal.html">Legal</a></li>
|
||||
</ul>
|
||||
@@ -670,7 +703,7 @@
|
||||
</footer>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
|
||||
<script src="script.js"></script>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
<script src="script.js?v=d2046e3469"></script>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -25,7 +25,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<link rel="stylesheet" href="style.css?v=061517baef" />
|
||||
<style>
|
||||
.legal-hero {
|
||||
padding: 4rem 0 2.5rem;
|
||||
@@ -115,8 +115,15 @@
|
||||
.legal-card { padding: 1.25rem; }
|
||||
}
|
||||
</style>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="index.html">← Back to Home</a>
|
||||
@@ -139,7 +146,7 @@
|
||||
WY 82801, USA
|
||||
</p>
|
||||
<p style="margin-top: 0.75rem;">
|
||||
Contact: <span class="contact-email">support@ODOO4projects.com</span>
|
||||
Contact: <span class="contact-email">support@odoo4projects.com</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -196,6 +203,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,9 +1,10 @@
|
||||
# ODOO4projects
|
||||
|
||||
> ODOO4projects is a managed Odoo Community hosting service. We run the server, the backups, the
|
||||
> SSL certificate and the version upgrades for a monthly-or-yearly price, so the customer does not
|
||||
> have to administer a server. One login: everything happens inside the customer's own Odoo
|
||||
> instance. We do not sell Odoo itself; we sell a business system that runs.
|
||||
> SSL certificate and the updates that keep your Odoo current within its version, for a monthly-or-
|
||||
> yearly price, so the customer does not have to administer a server. Moving to a new major version
|
||||
> is a migration and is quoted separately. One login: everything happens inside the customer's own
|
||||
> Odoo instance. We do not sell Odoo itself; we sell a business system that runs.
|
||||
|
||||
## Products and pricing (verified 2026-10-21, list prices, USD, VAT excluded)
|
||||
|
||||
@@ -32,9 +33,15 @@
|
||||
|
||||
- [Odoo Community upgrade](https://odoo4projects.com/odoo-community-upgrade.html): what an upgrade changes, the published step-by-step process, the real commands for a developer (Odoo's upgrade platform and the OCA OpenUpgrade route) and how we migrate a database onto our servers. No price and no duration are published for the migration service; it starts with a support ticket.
|
||||
- [Odoo hosting in Australia — Sydney](https://odoo4projects.com/australia.html): managed Odoo Community hosting on our own servers in Sydney, for Australian businesses. The four plans and yearly prices, the checkout with Australia (Sydney) pre-selected, and the one Sydney claim we make — we host in Sydney (no AU support hours, no AU entity, no AUD price published).
|
||||
- [Odoo hosting offers](https://odoo4projects.com/odoo-hosting-offers/) — what a year of managed Odoo Community hosting costs: one flat yearly price, no per-user licence, no setup fee, 30-day free trial.
|
||||
- [Odoo Black Friday](https://odoo4projects.com/odoo-black-friday/) — our yearly Black Friday and Cyber Monday offer on managed Odoo Community hosting.
|
||||
- [Odoo hosting 2027 — comparison landing page](https://odoo4projects.com/odoo-hosting-2027.html): every route to Odoo (managed, VPS, odoo.sh, Odoo Online, own hardware) side by side, with annual and five-year cost comparisons.
|
||||
- [Odoo ERP Automation Bootcamp](https://odoo4projects.com/odoo-erp-automation-bootcamp/): a three-month, ten-session live bootcamp with Oliver Arnold, Technical Lead, that takes a small business from zero to a running ERP. Thursdays, one hour, Q1 2026, starting 8 January 2026; one year of hosted Odoo Community Edition included. The current price is confirmed on registration.
|
||||
- [A briefing for Andrew](https://odoo4projects.com/odooityourself.html): Odoo Community as a first-class citizen — the vision behind our managed Community hosting, the six regions, the management console, the MCP agent that can touch the server, and the plan prices (Empire quoted per setup).
|
||||
- [Odoo ERP Automation Bootcamp](https://odoo4projects.com/odoo-erp-automation-bootcamp/): a three-month, ten-session live bootcamp with Oliver Arnold, Technical Lead, that takes a small business from zero to a running ERP. Thursdays, one hour, Q1 2027, starting 21 January 2027; one year of hosted Odoo Community Edition included. The bootcamp is limited to six participants per cohort. The current price is confirmed on registration.
|
||||
- [ODOO x N8N Masterclass](https://odoo4projects.com/odoo-n8n-masterclass/): a two-hour live masterclass with Oliver Arnold on connecting Odoo to n8n — calling n8n webhooks from Odoo automated actions, how the n8n integration for Odoo works, and website workarounds that extend your automation. Hands-on in a free Odoo trial system; n8n itself runs on n8n's own free plan, which is not included. USD 120.00, next session the four Thursdays of February 2027 at 17:00 Central Time.
|
||||
- [ODOO Workshops and Classes](https://odoo4projects.com/workshops/): the two live courses side by side — the two-hour ODOO x N8N Masterclass (USD 120.00) and the ten-session ODOO ERP Automation Bootcamp (USD 595.00), both taught by Oliver Arnold — which course fits which business, and a full comparison table.
|
||||
- [What can I use Odoo for?](https://odoo4projects.com/what-can-i-use-odoo-for/): plain-English guide to what Odoo is used for — the ten apps and what each is for, what Odoo is used for by business type (manufacturing, retail and trade, services, construction, nonprofits, accounting practices, small business starting out), where it stops (Odoo Online will not take custom code, it will not do your trade's specialist work), what it costs, and how to start. Includes the nine-question FAQ.
|
||||
- [Odoo staging environment](https://odoo4projects.com/odoo-staging-environment/): what an Odoo staging environment is, how odoo.sh's staging branches work, why most small businesses do not need one, and the simpler back-up-install-test route we offer instead.
|
||||
- [Odoo freelancers](https://odoo4projects.com/odoo-community-developers/): independent Odoo freelancers for our clients looking for one. Each card carries what the freelancer published and their contact details where they published them — no rating and no ranking, and the client writes to the freelancer directly.
|
||||
- [Home](https://odoo4projects.com/): plans and pricing, FAQ, server locations.
|
||||
- [Support](https://odoo4projects.com/support.html): support and frequently asked questions.
|
||||
- [Legal](https://odoo4projects.com/legal.html): company details.
|
||||
@@ -43,6 +50,12 @@
|
||||
|
||||
## Blog posts
|
||||
|
||||
- [Your Agent Can Run Your Odoo Hosting: the MCP Server Is Live](https://odoo4projects.com/blog/posts/your-agent-can-run-your-odoo-hosting.html) — 2026-11-05 — This is the piece of the Odoo 20 update we are asked about most: an MCP server that lets your agent work on your Odoo hosting directly, instead of you clicking through menus to do routine things.
|
||||
- [Our freelancer directory opens on 1 December. Help us get the signup right](https://odoo4projects.com/blog/posts/freelancer-directory-soft-launch.html) — 2026-11-04 — We need your help! We are opening our Odoo Community Freelancer directory on 1 December. Before real clients start browsing it, we want the signup to work, and we would like your help to get it right.
|
||||
- [Odoo 20 Is Live on Our Servers — Here Is What Changed](https://odoo4projects.com/blog/posts/odoo-20-is-live-on-our-servers-here-is-what-changed.html) — 2026-11-03 — Two weeks. That is how long it took us to bring up Odoo 20 on our servers, with every new feature that comes with it. It is live now — if your instance runs with us, the engine underneath it just moved forward.
|
||||
- [From a Spreadsheet to a Running ERP in Ten Thursday Sessions](https://odoo4projects.com/blog/posts/from-a-spreadsheet-to-a-running-erp.html) — 2026-11-02 — Most small businesses do not run on an ERP. They run on a spreadsheet, a messaging group, and one person's memory. It works — until that person is on holiday.
|
||||
- [ODOO4projects Supports the OCA Paraguay Internationalization Hackathon](https://odoo4projects.com/blog/posts/oca-paraguay-internationalization-hackathon.html) — 2026-10-29 — Two online days to push Odoo's Paraguayan localisation forward — and we are supporting them.
|
||||
- [How to Install Odoo Modules Using Git — and the Quick Git Route That Skips the Console](https://odoo4projects.com/blog/posts/how-to-install-odoo-modules-using-git.html) — 2026-10-28 — Every business is slightly different, which is why a system that only does the standard thing is only ever half a system.
|
||||
- [ODOO Community Is Going Online on ODOO4projects](https://odoo4projects.com/blog/posts/odoo-community-is-going-online-on-odoo4projects.html) — 2026-10-27 — ODOO Community is online.
|
||||
- [Track the OCA Modules You Actually Use — Without Refreshing GitHub Every Day](https://odoo4projects.com/blog/posts/track-the-oca-modules-you-actually-use.html) — 2026-10-24 — Every new Odoo release starts the same routine.
|
||||
- [This is how i updated my Invoices from Odoo 19 to Odoo 20 with n8n and much MCP](https://odoo4projects.com/blog/posts/odoo-19-to-20-invoice-migration-with-n8n-and-mcp.html) — 2026-10-23 — Copying invoices from one Odoo instance to another by hand is the kind of task that looks small until you are on…
|
||||
@@ -67,11 +80,11 @@
|
||||
## Languages
|
||||
|
||||
- German: https://odoo4projects.com/de/ — the site's pages mirrored under `/de/`:
|
||||
`/de/`, `/de/odoo-hosting-2027.html`, `/de/support.html`,
|
||||
`/de/odoo-erp-automation-bootcamp/`.
|
||||
`/de/`, `/de/odoo-hosting-2027.html`, `/de/odoo-community-upgrade.html`,
|
||||
`/de/support.html`, `/de/odoo-erp-automation-bootcamp/`.
|
||||
- Spanish: https://odoo4projects.com/es/ — the site's pages mirrored under `/es/`:
|
||||
`/es/`, `/es/odoo-hosting-2027.html`, `/es/support.html`,
|
||||
`/es/odoo-erp-automation-bootcamp/`.
|
||||
`/es/`, `/es/odoo-hosting-2027.html`, `/es/odoo-community-upgrade.html`,
|
||||
`/es/support.html`, `/es/odoo-erp-automation-bootcamp/`.
|
||||
- Language selection is client-side (`/static/lang.js`): a German- or
|
||||
Spanish-preferring browser is sent to `/de/` or `/es/` once per session.
|
||||
An explicit choice — `?lang=de|es|en` or the EN | DE | ES switcher — is
|
||||
|
||||
@@ -0,0 +1,942 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Odoo Community + AI Agent: Run It With Your Own Agent</title>
|
||||
<meta name="description" content="Odoo Community + your own AI agent, on our managed hosting. Bring Hermes or Claude Code, keep your keys and your data, no lock-in. Much MCP is free." />
|
||||
<!-- DRAFT: not indexed, not linked, not in sitemap.xml / llms.txt. Remove this robots meta on go-live. -->
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="canonical" href="https://odoo4projects.com/odoo-community-ai/" />
|
||||
<meta property="og:title" content="Run Odoo Community with your own AI agent" />
|
||||
<meta property="og:description" content="Bring the AI agent you already use to your Odoo Community system. It works inside Odoo, we run the server, and you keep your keys." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/odoo-community-ai/" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- "Odoo Community + AI agent" page (page-scoped; additive).
|
||||
Reuses the top bar, band rhythm, hero, FAQ and final-CTA treatment already
|
||||
shipped on odoo-staging-environment/ and what-can-i-use-odoo-for/.
|
||||
Additions this page needs and no other: .oca-table (the two MCP servers shown
|
||||
apart), .oca-fence (the "does not move data" sentence, the page's pivot),
|
||||
.oca-proof (the §3 proof sentence), .oca-dev (the collapsed developer
|
||||
<details>, after the offer) and the light-band CTA re-pointing. ---- */
|
||||
.oca-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Top bar (page-scoped: the site has no global header) */
|
||||
.cmp-topbar {
|
||||
background: var(--midnight-2);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.85rem 0;
|
||||
}
|
||||
.cmp-topbar .container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.cmp-brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
}
|
||||
.cmp-brand span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar-links {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
font-size: 0.82rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
.cmp-topbar-links a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar-links a:hover {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar .lang-switch-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.45);
|
||||
}
|
||||
.cmp-topbar .lang-switch {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar .lang-switch a:hover,
|
||||
.cmp-topbar .lang-switch a:focus-visible {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.cmp-topbar .lang-switch a[aria-current="true"] {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* Hero */
|
||||
.oc-hero {
|
||||
min-height: 0;
|
||||
padding: 3.5rem 0 3rem;
|
||||
}
|
||||
.oc-hero .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.oc-hero .hero-sub {
|
||||
max-width: 760px;
|
||||
}
|
||||
.oc-hero-img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
opacity: 0.25;
|
||||
filter: brightness(1.15) saturate(1.1);
|
||||
}
|
||||
|
||||
/* Prose column */
|
||||
.oc-body {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.75;
|
||||
}
|
||||
.section-dark .oc-body {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.oc-body p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oc-body strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-dark .oc-body strong {
|
||||
color: #fff;
|
||||
}
|
||||
.section-dark .oc-body a {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
/* Sub-headings inside the prose: inherit the site's h3 size (clamp(1.1rem, 2vw, 1.4rem)) */
|
||||
.oc-body h3 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.01em;
|
||||
color: var(--midnight);
|
||||
margin: 1.7rem 0 0.4rem;
|
||||
}
|
||||
.section-dark .oc-body h3 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* The §3 proof sentence, read first: brass rules top and bottom, ink text */
|
||||
.oca-proof {
|
||||
color: var(--ink);
|
||||
border-top: 1px solid var(--line-brass);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.9rem 0;
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
/* The two MCP servers, shown apart (§5) */
|
||||
.oca-table {
|
||||
width: 100%;
|
||||
max-width: 900px;
|
||||
margin: 1.5rem auto;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.88rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.oca-table th,
|
||||
.oca-table td {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
padding: 0.7rem 0.9rem;
|
||||
border-bottom: 1px solid var(--line);
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
.oca-table thead th {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-weight: 400;
|
||||
color: var(--midnight);
|
||||
border-bottom: 1px solid rgba(201, 162, 39, 0.5);
|
||||
}
|
||||
.oca-table tbody th {
|
||||
color: var(--ink);
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.oca-table td strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
/* The fence sentence, the page's pivot: a midnight plaque with a brass hairline */
|
||||
.oca-fence {
|
||||
max-width: 860px;
|
||||
margin: 1.75rem auto 0;
|
||||
padding: 1.35rem 1.5rem;
|
||||
background: var(--midnight);
|
||||
border: 1px solid var(--line-brass);
|
||||
border-radius: var(--radius);
|
||||
color: rgba(255, 255, 255, 0.82);
|
||||
line-height: 1.75;
|
||||
}
|
||||
.oca-fence p {
|
||||
margin: 0;
|
||||
}
|
||||
.oca-fence a {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
|
||||
/* Numbered run-through */
|
||||
.oc-steps {
|
||||
max-width: 820px;
|
||||
margin: 1.5rem auto 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
counter-reset: oc-step;
|
||||
}
|
||||
.oc-steps li {
|
||||
position: relative;
|
||||
counter-increment: oc-step;
|
||||
padding: 0 0 1.4rem 3.2rem;
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
line-height: 1.7;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.25);
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.oc-steps li::before {
|
||||
content: counter(oc-step);
|
||||
position: absolute;
|
||||
left: -1.05rem;
|
||||
top: -0.15rem;
|
||||
width: 2.1rem;
|
||||
height: 2.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1rem;
|
||||
color: var(--midnight);
|
||||
background: var(--brass);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.oc-steps li strong {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.oc-steps li:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.section-light .oc-steps li {
|
||||
color: var(--ink-soft);
|
||||
border-left-color: rgba(138, 111, 31, 0.3);
|
||||
}
|
||||
.section-light .oc-steps li strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
/* FAQ */
|
||||
.cmp-faq-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cmp-faq {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.4rem 1.25rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
transition: box-shadow 0.25s;
|
||||
}
|
||||
.cmp-faq[open],
|
||||
.cmp-faq:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
.cmp-faq summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.85rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.98rem;
|
||||
color: var(--midnight);
|
||||
}
|
||||
.cmp-faq summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.cmp-faq summary::after {
|
||||
content: "+";
|
||||
font-family: Inter, sans-serif;
|
||||
color: var(--brass);
|
||||
font-size: 1.15rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
.cmp-faq[open] summary::after {
|
||||
content: "\2212";
|
||||
}
|
||||
.cmp-faq summary:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.cmp-faq .cmp-a {
|
||||
font-size: 0.87rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.cmp-faq .cmp-a p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Final CTA (the block odoo-hosting-2027.html uses), run on the light band here */
|
||||
.cmp-cta {
|
||||
text-align: center;
|
||||
}
|
||||
.cmp-cta .cmp-lead {
|
||||
font-size: 1.1rem;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
max-width: 720px;
|
||||
line-height: 1.75;
|
||||
margin: 0 auto 1.5rem;
|
||||
}
|
||||
/* .cmp-cta and .section-light sit on the SAME element, so the override must be a
|
||||
compound selector, not a descendant one. */
|
||||
.cmp-cta.section-light .cmp-lead {
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
.cmp-cta.section-light .cmp-lead p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.cmp-cta-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.section-light .cmp-cta-actions .btn-outline {
|
||||
color: var(--ink);
|
||||
border-color: rgba(23, 28, 38, 0.22);
|
||||
}
|
||||
.section-light .cmp-cta-actions .btn-outline:hover {
|
||||
color: var(--brass-deep);
|
||||
border-color: var(--brass-deep);
|
||||
background: rgba(201, 162, 39, 0.08);
|
||||
}
|
||||
.oca-recap {
|
||||
max-width: 820px;
|
||||
margin: 1.75rem auto 0;
|
||||
font-size: 0.87rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
/* For your developer: the collapsed technical block, after the offer */
|
||||
.oca-dev {
|
||||
max-width: 860px;
|
||||
margin: 0 auto;
|
||||
background: var(--midnight-2);
|
||||
border: 1px solid var(--line-brass);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.5rem 1.5rem;
|
||||
}
|
||||
.oca-dev summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.95rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.05rem;
|
||||
color: #fff;
|
||||
}
|
||||
.oca-dev summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.oca-dev summary::after {
|
||||
content: "+";
|
||||
font-family: Inter, sans-serif;
|
||||
color: var(--brass);
|
||||
font-size: 1.15rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.oca-dev[open] summary::after {
|
||||
content: "\2212";
|
||||
}
|
||||
.oca-dev summary:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.oca-dev .oca-dev-body {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
font-size: 0.87rem;
|
||||
line-height: 1.75;
|
||||
padding-bottom: 1.25rem;
|
||||
}
|
||||
.oca-dev .oca-dev-body p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oca-dev .oca-dev-body ol {
|
||||
padding-left: 1.2rem;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
.oca-dev .oca-dev-body li {
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
.oca-dev .oca-dev-body li:last-child {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.oca-dev .oca-dev-body li::marker {
|
||||
color: var(--brass);
|
||||
}
|
||||
|
||||
/* Focus states on every CTA */
|
||||
.btn:focus-visible,
|
||||
.cmp-topbar-links a:focus-visible {
|
||||
outline: 3px solid var(--brass-bright);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.btn-brass:focus-visible {
|
||||
outline-color: #fff;
|
||||
}
|
||||
.section-light .btn-brass:focus-visible {
|
||||
outline-color: var(--midnight);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.cmp-faq-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.oc-hero {
|
||||
padding: 3rem 0 2.5rem;
|
||||
}
|
||||
.oc-steps li {
|
||||
padding-left: 2.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Below 640px the two MCP columns cannot hold text side by side, so each row
|
||||
becomes a card: the row label is the title, each value carries its own column
|
||||
label (data-label). The two servers stay visibly apart. */
|
||||
@media (max-width: 640px) {
|
||||
.oca-table {
|
||||
border-collapse: separate;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.oca-table thead {
|
||||
display: none;
|
||||
}
|
||||
.oca-table tr {
|
||||
display: block;
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.35rem 1rem 0.85rem;
|
||||
margin-bottom: 0.9rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
}
|
||||
.oca-table tbody th {
|
||||
display: block;
|
||||
padding: 0.6rem 0 0.5rem;
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
white-space: normal;
|
||||
}
|
||||
.oca-table td {
|
||||
display: block;
|
||||
padding: 0.6rem 0 0;
|
||||
border-bottom: 0;
|
||||
color: var(--ink);
|
||||
}
|
||||
.oca-table td::before {
|
||||
content: attr(data-label);
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
font-size: 0.82rem;
|
||||
color: var(--midnight);
|
||||
margin-bottom: 0.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "WebPage",
|
||||
"@id": "https://odoo4projects.com/odoo-community-ai/#webpage",
|
||||
"url": "https://odoo4projects.com/odoo-community-ai/",
|
||||
"name": "Odoo Community + AI Agent: Run It With Your Own Agent",
|
||||
"description": "Odoo Community + your own AI agent, on our managed hosting. Bring Hermes or Claude Code, keep your keys and your data, no lock-in. Much MCP is free.",
|
||||
"inLanguage": "en-US",
|
||||
"isPartOf": {
|
||||
"@id": "https://odoo4projects.com/#organization"
|
||||
},
|
||||
"breadcrumb": {
|
||||
"@id": "https://odoo4projects.com/odoo-community-ai/#breadcrumb"
|
||||
},
|
||||
"mainEntity": {
|
||||
"@id": "https://odoo4projects.com/odoo-community-ai/#article"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Article",
|
||||
"@id": "https://odoo4projects.com/odoo-community-ai/#article",
|
||||
"headline": "Odoo Community + AI Agent: Run It With Your Own Agent",
|
||||
"description": "Odoo Community + your own AI agent, on our managed hosting. Bring Hermes or Claude Code, keep your keys and your data, no lock-in. Much MCP is free.",
|
||||
"articleSection": [
|
||||
"What you get",
|
||||
"Why Odoo Community is ready for this now",
|
||||
"What you need",
|
||||
"A run-through: connect your agent, then install a module",
|
||||
"Why your own agent beats a provider's closed AI",
|
||||
"Questions owners ask",
|
||||
"Start"
|
||||
],
|
||||
"inLanguage": "en-US",
|
||||
"datePublished": "2026-11-01",
|
||||
"dateModified": "2026-11-01",
|
||||
"author": {
|
||||
"@id": "https://odoo4projects.com/#organization"
|
||||
},
|
||||
"publisher": {
|
||||
"@id": "https://odoo4projects.com/#organization"
|
||||
},
|
||||
"mainEntityOfPage": {
|
||||
"@id": "https://odoo4projects.com/odoo-community-ai/#webpage"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "FAQPage",
|
||||
"@id": "https://odoo4projects.com/odoo-community-ai/#faq",
|
||||
"isPartOf": {
|
||||
"@id": "https://odoo4projects.com/odoo-community-ai/#webpage"
|
||||
},
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Do I need to be technical?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No. You need to already use an AI agent, and that is the only precondition. Two of our own clients run theirs with no IT background at all. If you can ask for something in plain words, you can use this."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What do I need to already have?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "An AI agent you already run (Hermes or Claude Code), and an Odoo Community system with us — or the plans to start one. There is nothing to install by hand: we set up the two MCP connections for the agent, and the free Much MCP gives it the Odoo skills."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "How much of my time does this take?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Once the two connections are set up, the next thing you do is ask the agent for something. You point your agent at the two MCP servers once, or send us a short message and we set them up for you. From then on the agent works inside your Odoo and you read and approve the result. There is nothing to build or train on your side."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Is my data locked in?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No. Your keys stay yours, your agent stays yours, and your Odoo database stays yours. We run the hosting; we do not hold your agent or the work you have built with it."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Which agent does this work with?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Hermes or Claude Code, today. Those are the two we support now."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What can the agent actually do, and what can’t it?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Inside Odoo, the agent can read and write your records through the Odoo MCP (an invoice, a customer, a product line), because the free Much MCP gives it those Odoo skills. Around Odoo, it can run the hosting through our MCP: start, stop and restart services, install a module, add or check a domain, manage backups, and read the logfiles. What our MCP does not do is move your data. It does not migrate or import records; it runs the server. Moving data is a different job with its own route."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Do I need Enterprise to get AI in Odoo?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No. Odoo’s own built-in AI is an Enterprise feature. On Community you bring your own agent instead, which is the point of this page, and the free community modules and MCP servers cover much of the ground Enterprise used to hold back."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What does it cost?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Much MCP is free and comes bundled with our service, so it is not an extra you buy. You pay for the hosting, on the same four plans as always, and Odoo Community carries no per-user licence, so the agent’s own account costs nothing extra."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "BreadcrumbList",
|
||||
"@id": "https://odoo4projects.com/odoo-community-ai/#breadcrumb",
|
||||
"itemListElement": [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"name": "Home",
|
||||
"item": "https://odoo4projects.com/"
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "Odoo Community + AI",
|
||||
"item": "https://odoo4projects.com/odoo-community-ai/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="cmp-topbar">
|
||||
<div class="container">
|
||||
<a class="cmp-brand" href="/index.html">ODOO4<span>projects</span></a>
|
||||
<nav class="cmp-topbar-links" aria-label="Page links">
|
||||
<a href="/index.html#pricing">Plans & pricing</a>
|
||||
<a href="/support.html">Support</a>
|
||||
</nav>
|
||||
<div data-lang-switcher class="lang-switch-slot"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero oc-hero">
|
||||
<div class="hero-bg">
|
||||
<img
|
||||
class="oc-hero-img"
|
||||
src="/images/hero/amsterdam.webp"
|
||||
alt="Amsterdam at dusk, one of the six regions our servers run in"
|
||||
width="1920"
|
||||
height="768"
|
||||
fetchpriority="high"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="container">
|
||||
<p class="hero-kicker">ODOO COMMUNITY + AI</p>
|
||||
<h1>Run your Odoo Community business with your own AI agent</h1>
|
||||
<p class="hero-sub">You already use an AI agent — Hermes or Claude Code. Connect it to your Odoo and it can do the work you keep putting off: write the invoice, update the customer, add the stock item, install the module. You answer the question once, and the agent does the typing. Your keys stay yours, and your data stays yours.</p>
|
||||
<div class="hero-actions">
|
||||
<a href="/support.html#contact" class="btn btn-brass btn-lg">Ask us a question</a>
|
||||
<a href="/index.html#pricing" class="btn btn-outline btn-lg">See the plans</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What you get -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">What you get</h2>
|
||||
<div class="oc-body">
|
||||
<p class="oca-proof">Two of our clients know nothing about IT, and they use Claude Code to implement modules in their Odoo. Not developers, not IT staff. Business owners with an agent, the same as you.</p>
|
||||
<!-- OPEN-SLOT (O1): the two non-technical Claude Code clients stay unnamed until naming permission is confirmed. -->
|
||||
<p>You did not start a business to type the same invoice forty times, or to hunt for a record you know is in there somewhere. An agent removes that kind of work, because the work is repetitive and the rules are simple, which is exactly what an agent is good at and a person is bad at.</p>
|
||||
<p>Ask for something in plain words. The invoice gets written, the customer record gets updated, the missing stock item gets added, the module you wanted gets installed. You read the result and approve it, instead of building it by hand.</p>
|
||||
<p>Here is how that lands during a week. The supplier invoices that used to pile up until the weekend are entered on the day they arrive, because you hand them to the agent and check the first one. The product you forgot to add is added when you notice it, not when someone finally complains. The new menu you asked your developer about last quarter is installed this afternoon.</p>
|
||||
<p>None of this is a promise about your numbers. It is the plain shape of it: the repetitive part moves off your desk, and you keep the judgement.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Why Odoo Community is ready for this now -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Why Odoo Community is ready for this now</h2>
|
||||
<div class="oc-body">
|
||||
<p>Odoo's best AI features used to be Enterprise-only. On Community you get there a different way — with your own agent — and that route works today, for three reasons. Odoo's own built-in AI still lives in the Enterprise edition, and Community does not ship it; that used to be a real gap.</p>
|
||||
<p>First, the community modules. The Odoo Community Association, the group that writes and maintains free Odoo modules, now builds modules that cover a lot of what Enterprise used to hold back. Enterprise's newest features are increasingly matched by free community modules. It is not a mirror image, and we are not going to claim it is, but the distance is much shorter than it was.</p>
|
||||
<p>Second, the agent side. MCP is the plug that lets an AI agent use an outside tool. Free MCP servers now exist that give an AI agent the skills to work inside Odoo. That is the piece that lets your agent, which you already have, do real work in the system rather than just talk about it.</p>
|
||||
<p>Third, the hosting side. We run your Odoo for you on our own servers, and we ship our own MCP server so your agent can run the hosting tasks as well. You do not need a server of your own to make any of this work.</p>
|
||||
<p>One more difference worth knowing, because it decides whether this is affordable at all. Odoo Community has no per-user licence. So giving your agent its own user account, with its own limits on what it may touch, costs you nothing extra.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What you need -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">What you need</h2>
|
||||
<div class="oc-body">
|
||||
<p>There are four things. You bring one, and we bring the other three.</p>
|
||||
<h3>(1) An agent you already run.</h3>
|
||||
<p>Hermes or Claude Code, today. That is the only technical precondition on this whole page. The rest we do for you. If you are already using one of those, you are ready.</p>
|
||||
<h3>(2) Two MCP connections — and it matters that there are two.</h3>
|
||||
<p>You point your agent at an MCP server, and the agent can use whatever that server offers. You will set up two of them, and they do two different jobs. Keep them apart in your head, because blurring them is the mistake.</p>
|
||||
</div>
|
||||
<table class="oca-table">
|
||||
<caption class="oca-sr-only">The two MCP servers, side by side</caption>
|
||||
<thead>
|
||||
<tr><th scope="col"></th><th scope="col">The Odoo MCP</th><th scope="col">The hosting MCP</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><th scope="row">What it is</th><td data-label="The Odoo MCP">A free MCP server that gives your agent Odoo skills (we use Much MCP)</td><td data-label="The hosting MCP">Our own MCP server, shipped inside our service</td></tr>
|
||||
<tr><th scope="row">What it does</th><td data-label="The Odoo MCP">The agent works <strong>inside Odoo</strong>: reads and writes records, such as an invoice, a customer or a product line</td><td data-label="The hosting MCP">The agent runs <strong>the server around Odoo</strong>: start, stop and restart services, install a module, add or check a domain, manage backups, read the logfiles</td></tr>
|
||||
<tr><th scope="row">What it touches</th><td data-label="The Odoo MCP">Your business records</td><td data-label="The hosting MCP">The hosting, not your records</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="oc-body">
|
||||
<h3>(3) Much MCP is free, and it comes with our service.</h3>
|
||||
<p>Much MCP is the free MCP server that gives your agent its Odoo skills. It comes bundled with our service. You do not buy it separately, and it is not a third-party cost on top of your plan.</p>
|
||||
<h3>(4) Our hosting.</h3>
|
||||
<p>Your Odoo runs on our servers, managed by us: the server, the backups, the certificate and the updates are our job, not yours. Our MCP server is the piece your agent uses to run the hosting tasks, which is why there is no server of your own to look after.</p>
|
||||
</div>
|
||||
<div class="oca-fence">
|
||||
<p>Our MCP does hosting operations only. It does not move your data, and it does not perform migrations. Moving records between two systems is a different job with a different route; this page is about running your business with an agent, not about upgrading a version. (Upgrading an Odoo version is a separate job. That is on <a href="/odoo-community-upgrade.html">our upgrade page</a>.)</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- A real run-through -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">A run-through: connect your agent, then install a module</h2>
|
||||
<!-- DRAFT(R1): steps reconstructed from the published capability list; awaiting the user's real steps. -->
|
||||
<div class="oc-body">
|
||||
<p>Here is one task, start to finish: you connect the agent you already run to your Odoo, then ask it to install a module. It is two connections, then one request. Nothing here needs a server of your own, and nothing here is a migration. No records move.</p>
|
||||
<p>Your agent reaches Odoo through MCP, the plug that lets an agent use an outside tool, and this task uses two of them: one for your Odoo system, one for the hosting. They are the two §5 describes, set up in the order below.</p>
|
||||
</div>
|
||||
<ol class="oc-steps">
|
||||
<li>
|
||||
<strong>Check what you need, three things.</strong> Hermes or Claude Code already installed and answering you. An Odoo Community system with us on a plan from On the Rise upward (module installation is not part of Side Hustle, so on that plan this task stops here). And the module you want, or just a plain description of what you want it to do. You do not need its technical name; the agent can find the module from what you describe.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Open the management console and find the two MCP settings.</strong> The console is the app we preinstall on your service, and it is where our side of the setup lives. It shows two MCP settings. One points at your Odoo system (that is Much MCP, the free one we bundle). The other points at operations (that is our own MCP). Keep them apart: the first works inside your Odoo, the second runs the server around it.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Connect the Odoo setting to your agent.</strong> Take the Odoo MCP connection details from the console and add them where your agent keeps its MCP servers. This is the connection that gives your agent its Odoo skills, which is what lets it read and write records. You add a server to your agent once, and both Hermes and Claude Code have a place to list one.
|
||||
<!-- OPEN-SLOT: the exact Odoo MCP connection details from the console, the server address and the key. -->
|
||||
</li>
|
||||
<li>
|
||||
<strong>Connect the operations setting, the same way.</strong> Add the operations MCP from the console beside the first. This is the connection that lets the agent run the hosting, and installing a module is one of those operations.
|
||||
<!-- OPEN-SLOT: the exact operations MCP connection details from the console, the server address and the key. -->
|
||||
</li>
|
||||
<li>
|
||||
<strong>Confirm both connections landed.</strong> Ask the agent, in plain words, what it can do in Odoo. It should answer with two kinds of work: inside the system (records, invoices, customers, products) and on the server (restart a service, install a module, domains, backups, logfiles). If one of the two is missing, that setting did not take, and you add it again from step 3 or step 4.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Ask for the install in plain words.</strong> Now say something like: install the module that adds what you did not have. Installing a module is a hosting operation, so it runs through the operations MCP, not the Odoo one. If you want a way back before any change, ask the agent to take a backup first, because managing backups is one of the operations.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Read what the agent reports, then check it in Odoo.</strong> The agent tells you the module is installed, or tells you plainly what stopped it. Then open your Odoo, log in, and open the app menu. The module is listed as installed and its new menu or feature is there. That is the whole task: you asked, the agent did the steps, and you checked the result.
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Why your own agent beats a provider's closed AI -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Why your own agent beats a provider's closed AI</h2>
|
||||
<div class="oc-body">
|
||||
<p>Some hosts give you their own AI, and it only works inside their product. The tasks you teach it, and the way you set it up, stay with them — not with you. Leave, and the AI stays behind.</p>
|
||||
<p>We do the opposite. We bring the hosting, the Odoo system and the MCP servers that connect them, and you bring your own agent.</p>
|
||||
<p>That means your keys are yours. Your agent is yours. The rules you teach it, the tasks you build, the way it works with your business: none of that is locked inside our product. If you leave us tomorrow, you take your agent and everything you built with it. And because it can also run the hosting tasks, there is very little you cannot do yourself. That is the whole point.</p>
|
||||
<p>We would rather sell you the thing that runs, and let the agent be yours.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section class="section-dark" id="faq">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Questions owners ask</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Do I need to be technical?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No. You need to already use an AI agent, and that is the only precondition. Two of our own clients run theirs with no IT background at all. If you can ask for something in plain words, you can use this.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">What do I need to already have?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>An AI agent you already run (Hermes or Claude Code), and an Odoo Community system with us — or the plans to start one. There is nothing to install by hand: we set up the two MCP connections for the agent, and the free Much MCP gives it the Odoo skills.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">How much of my time does this take?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Once the two connections are set up, the next thing you do is ask the agent for something. You point your agent at the two MCP servers once, or send us a short message and we set them up for you. From then on the agent works inside your Odoo and you read and approve the result. There is nothing to build or train on your side.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Is my data locked in?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No. Your keys stay yours, your agent stays yours, and your Odoo database stays yours. We run the hosting; we do not hold your agent or the work you have built with it.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Which agent does this work with?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Hermes or Claude Code, today. Those are the two we support now.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">What can the agent actually do, and what can’t it?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Inside Odoo, the agent can read and write your records through the Odoo MCP (an invoice, a customer, a product line), because the free Much MCP gives it those Odoo skills. Around Odoo, it can run the hosting through our MCP: start, stop and restart services, install a module, add or check a domain, manage backups, and read the logfiles. What our MCP does not do is move your data. It does not migrate or import records; it runs the server. Moving data is a different job with its own route.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Do I need Enterprise to get AI in Odoo?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No. Odoo’s own built-in AI is an Enterprise feature. On Community you bring your own agent instead, which is the point of this page, and the free community modules and MCP servers cover much of the ground Enterprise used to hold back.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">What does it cost?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Much MCP is free and comes bundled with our service, so it is not an extra you buy. You pay for the hosting, on the same four plans as always, and Odoo Community carries no per-user licence, so the agent’s own account costs nothing extra.</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Start -->
|
||||
<section class="section-light cmp-cta" id="start">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Start</h2>
|
||||
<div class="cmp-lead">
|
||||
<p>If you already run an agent and your business runs on Odoo Community with us, you are one connection away from handing it work. Send us a message and we will point you at the two MCP connections, or tell you plainly what fits your situation.</p>
|
||||
<p>If you are not hosted with us yet, the plans are here, and you can bring your own agent from the first day.</p>
|
||||
</div>
|
||||
<div class="cmp-cta-actions">
|
||||
<a href="/support.html#contact" class="btn btn-brass btn-lg">Ask us a question</a>
|
||||
<a href="/index.html#pricing" class="btn btn-outline btn-lg">See the plans</a>
|
||||
</div>
|
||||
<p class="oca-recap">On Odoo Community you can run your business with your own AI agent. The agent works inside Odoo through an MCP server, and your host runs the server. ODOO4projects bundles the free Much MCP, which gives the agent Odoo skills, and ships its own hosting MCP for operations: starting and stopping services, uploading modules, domains, backups and logfiles. Your keys and your data stay yours.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- For your developer (collapsed, after the offer) -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<details class="oca-dev">
|
||||
<summary>For your developer: which MCP does what</summary>
|
||||
<div class="oca-dev-body">
|
||||
<p>Two MCP servers connect to the agent.</p>
|
||||
<ol>
|
||||
<li>The Odoo MCP, "Much MCP" (free; bundled with the hosted service). Points the agent at Odoo and gives it the Odoo skills to read and write records inside the system. This is the MCP that touches business data.</li>
|
||||
<li>The hosting MCP, ours, shipped inside the ODOO4projects management console (the app preinstalled on the service). Its published operations: restart the server, upload/install modules, add or check domains, manage backups, read and download logfiles. It does running the server and nothing else. It does not move, import or migrate data.</li>
|
||||
</ol>
|
||||
<p>Both connect the same way: you add each MCP server to your agent (Hermes or Claude Code) and the agent can then use the tools that server exposes.</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer (copied from odoo-staging-environment/; no link to this page is added anywhere) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Useful Links</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Legal</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Partners</h4>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
<a href="https://OD8N.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OD8N</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>About us</h4>
|
||||
<p>We build smart, scalable business solutions by combining the <strong>stability</strong> of Odoo ERP with the <strong>power</strong> of AI Agents and N8N automations.</p>
|
||||
<p>From streamlined sales to global rollouts, our <strong>lean, eco-friendly</strong> approach helps businesses cut costs, boost efficiency, and grow without limits.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Follow us on</h4>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="oca-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
<label class="oca-sr-only" for="footerContactText">Your message</label>
|
||||
<textarea id="footerContactText" name="message" placeholder="Your message..." required></textarea>
|
||||
<button type="submit" class="footer-send-btn" aria-label="Send message"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M2 21l21-9L2 3v7l15 2-15 2z" /></svg></button>
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -38,8 +38,7 @@
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="style.css" /></noscript>
|
||||
<link rel="stylesheet" href="style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- Odoo Community Upgrade page (page-scoped; additive) ---- */
|
||||
.oc-sr-only {
|
||||
@@ -217,6 +216,31 @@
|
||||
overflow-x: auto;
|
||||
box-shadow: var(--shadow-rest);
|
||||
}
|
||||
.section-dark .oc-code {
|
||||
background: var(--midnight-2);
|
||||
}
|
||||
/* R1 moved the process list onto a light band and the technical section onto a
|
||||
dark one, so their text colours have to follow the band, not their old parent. */
|
||||
.section-light .oc-steps li {
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
.section-light .oc-steps li strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-dark .oc-sub h3 {
|
||||
color: var(--cream);
|
||||
}
|
||||
.section-dark .oc-sub > p,
|
||||
.section-dark .oc-note {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.section-dark .oc-note strong {
|
||||
color: #fff;
|
||||
}
|
||||
/* R3 puts the "See the plans" link inside the dark offer band. */
|
||||
.section-dark .oc-body a {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.oc-code code {
|
||||
display: block;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
||||
@@ -393,7 +417,7 @@
|
||||
"name": "Can we upgrade straight from Odoo 14 to Odoo 20?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No. It is one major version at a time: 14 to 15 to 16 to 17 to 18 to 19 to 20. Skipping a version is not a supported path. Our own migration service documents support for databases on Odoo 17, 18 and 19, main releases only — no patch releases — and older databases need a compatibility review first, which starts with a support ticket."
|
||||
"text": "No. It is one major version at a time: 14 → 15 → 16 → 17 → 18 → 19 → 20. Skipping a version is not a supported path. Our own migration service documents support for databases on Odoo 17, 18 and 19, main releases only — no patch releases — and older databases need a compatibility review first, which starts with a support ticket."
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -401,7 +425,7 @@
|
||||
"name": "What happens to my history — the invoices, the payments, the attachments?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "That is the right question to ask, and the answer depends on which route you take. A version migration carries the database across and keeps the history and the links between records; that is the point of it. A route that moves documents into a fresh system does not, and the OpenUpgrade documentation says so plainly: export and import recovers only some of your data, and you lose the history and the links — the invoices for each customer, for example. If your upgrade runs on our service, ask us to list exactly which records will be in the new database before you approve anything."
|
||||
"text": "That is the right question to ask, and the honest answer is that it depends on the route. The OpenUpgrade route — a version migration run on your own server — carries the database across and keeps the history and the links between records. The OpenUpgrade documentation warns that the other route, moving documents into a fresh system, recovers only some of your data and loses the history and the links between records — the invoices for each customer, for example. Our service builds you a new database and moves your data into it, so ours is the route to ask about: before you approve anything, ask us to list exactly which records will be in the new database, and which will not. We would rather you ask it than assume it."
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -455,7 +479,7 @@
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
@@ -471,6 +495,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero oc-hero">
|
||||
<div class="hero-bg">
|
||||
<img
|
||||
@@ -487,9 +512,10 @@
|
||||
<p class="hero-kicker">ODOO COMMUNITY UPGRADE</p>
|
||||
<h1><span>Odoo Community Upgrade</span>: What Changes, and How We Do It For You</h1>
|
||||
<p class="hero-sub">
|
||||
Moving up a major Odoo version is not an update — it is a one-way transformation of your database,
|
||||
and it is the one job where a mistake costs you your history. Here is what actually happens, the
|
||||
commands a developer will run, and how we do it for you on our own servers.
|
||||
Moving up a major Odoo version is not an update: it is a one-way change to your database, and it
|
||||
is not something you want to get wrong. Here is how we do it for you — a new system on our own
|
||||
servers, your current one left untouched while we work — and, underneath, the exact commands a
|
||||
developer would run.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="support.html#contact" class="btn btn-brass btn-lg">Open a ticket — tell us which version you run</a>
|
||||
@@ -541,8 +567,76 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Our way -->
|
||||
<section class="section-dark" id="our-way">
|
||||
<div class="container">
|
||||
<p class="section-kicker">The ODOO4projects way</p>
|
||||
<h2 class="section-title">The ODOO4projects way: a new database, and we do the work</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
You do not have to do any of this yourself. If your business runs on Odoo Community and you want
|
||||
the version moved without hiring someone to work through the sequence on this page, this is what we
|
||||
do instead.
|
||||
</p>
|
||||
<p>
|
||||
You open a support ticket and tell us what you have. We look at your database first — its version,
|
||||
its customisations, whether it is something we can move — and we tell you what we find. Then we send
|
||||
you a link to a secure form where you upload your database. When we have it, we spin up a new server
|
||||
for you on our own infrastructure and hand you the credentials. Your existing system keeps running
|
||||
the whole time, because we are not touching it: we work on the database you sent us and the new
|
||||
server we built.
|
||||
</p>
|
||||
<p>
|
||||
If you would rather see a number first: which plan you need depends on the modules you run, and the
|
||||
plans are here — <a href="index.html#pricing">See the plans</a>. The upgrade itself is not priced on
|
||||
that page; we come back to you after we have looked at your database.
|
||||
</p>
|
||||
<p>
|
||||
That last point is the whole reason to do it this way. On our service you are not migrating your
|
||||
live database in the evening after the shop closes. You are looking at a second system, in a new
|
||||
version, with your data in it, and you can compare the two before you decide anything.
|
||||
</p>
|
||||
<p>
|
||||
Our migration service documents support for databases on Odoo 17, 18 and 19, main releases only —
|
||||
patch releases such as 18.1 or 17.2 are not supported anywhere in our service. If your database is
|
||||
older than 17, we can still help you get it to a supported release, but only after reviewing it to
|
||||
check compatibility. New instances on our servers can be created on Odoo 19 or Odoo 20, so if you
|
||||
are moving to 20 specifically, say so in the ticket: the version you are going to matters more than
|
||||
the version you are on.
|
||||
</p>
|
||||
<p>
|
||||
On the AI side, here is a case we have actually published. Copying invoices from one Odoo instance
|
||||
to another by hand is slow and easy to get wrong, so we did it with a workflow instead: records
|
||||
written from an Odoo 19 system into a new Odoo 20 system, driven by an automation workflow and an
|
||||
MCP server pointed at the new system. Three rules made it safe — the invoice number and date never
|
||||
change, the contact is looked up rather than guessed, the product is looked up rather than guessed —
|
||||
and one hard constraint: if a contact or a product is missing, the run fails loudly rather than
|
||||
creating a near-duplicate. Before releasing it on the rest, we checked one invoice end to end:
|
||||
number, date, contact, product lines.
|
||||
</p>
|
||||
<p>
|
||||
One thing we will not blur, because it is the difference between us and a salesman. The MCP server
|
||||
we ship inside our own management console does hosting operations. It restarts a server, uploads a
|
||||
module, adds or checks a domain, manages backups and reads a log file — that is the published list,
|
||||
and it is a real convenience if you use an AI assistant. It is not a data-migration engine and we do
|
||||
not describe it as one. The import work above was done with an automation workflow and a third-party
|
||||
MCP; the AI was doing the tedious part and being checked by a human, exactly as it should be.
|
||||
</p>
|
||||
<p>
|
||||
And the honest limit, in the words of the project that knows this best. The OpenUpgrade
|
||||
documentation names the export-and-import alternative and prices it plainly: you recover only some
|
||||
of your data, and in particular you do not get the history and the links between records — the
|
||||
invoices for each customer, for example. That is the risk of any route that moves documents into a
|
||||
fresh system, and it is why, if you take that route with us, you ask us one question before you
|
||||
approve anything: which records will be in the new database, and which will not. We would rather you
|
||||
ask it than assume it.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Process -->
|
||||
<section class="section-dark">
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">The published path</p>
|
||||
<h2 class="section-title">The upgrade process, step by step</h2>
|
||||
@@ -608,13 +702,14 @@
|
||||
</section>
|
||||
|
||||
<!-- Technical section -->
|
||||
<section class="section-light" id="commands">
|
||||
<section class="section-dark" id="commands">
|
||||
<div class="container">
|
||||
<p class="section-kicker">For your developer</p>
|
||||
<h2 class="section-title">For your developer: the actual commands</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
If you are running Odoo Community yourself and you want to do this in-house, these are the commands.
|
||||
If you are running Odoo Community yourself and you would rather do this in-house than have us do
|
||||
it, these are the commands.
|
||||
They are quoted from the documentation they come from, and each one is labelled with what you must
|
||||
substitute and what that source warns about. Nothing below has been run by us against your database,
|
||||
and no command published by us runs on our own servers — our service starts with a support ticket,
|
||||
@@ -740,67 +835,6 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Our way -->
|
||||
<section class="section-dark" id="our-way">
|
||||
<div class="container">
|
||||
<p class="section-kicker">The ODOO4projects way</p>
|
||||
<h2 class="section-title">The ODOO4projects way: a new database, and we do the work</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
You do not have to run any of the above. If your business runs on Odoo Community and you want the
|
||||
version moved without hiring the developer who wrote the ten steps, this is what we do instead.
|
||||
</p>
|
||||
<p>
|
||||
You open a support ticket and tell us what you have. We look at your database first — its version,
|
||||
its customisations, whether it is something we can move — and we tell you what we find. Then we send
|
||||
you a link to a secure form where you upload your database. When we have it, we spin up a new server
|
||||
for you on our own infrastructure and hand you the credentials. Your existing system keeps running
|
||||
the whole time, because we are not touching it: we work on the database you sent us and the new
|
||||
server we built.
|
||||
</p>
|
||||
<p>
|
||||
That last point is the whole reason to do it this way. On our service you are not migrating your
|
||||
live database in the evening after the shop closes. You are looking at a second system, in a new
|
||||
version, with your data in it, and you can compare the two before you decide anything.
|
||||
</p>
|
||||
<p>
|
||||
Our migration service documents support for databases on Odoo 17, 18 and 19, main releases only —
|
||||
patch releases such as 18.1 or 17.2 are not supported anywhere in our service. If your database is
|
||||
older than 17, we can still help you get it to a supported release, but only after reviewing it to
|
||||
check compatibility. New instances on our servers can be created on Odoo 19 or Odoo 20, so if you
|
||||
are moving to 20 specifically, say so in the ticket: the version you are going to matters more than
|
||||
the version you are on.
|
||||
</p>
|
||||
<p>
|
||||
On the AI side, here is a case we have actually published. Copying invoices from one Odoo instance
|
||||
to another by hand is slow and easy to get wrong, so we did it with a workflow instead: records
|
||||
written from an Odoo 19 system into a new Odoo 20 system, driven by an automation workflow and an
|
||||
MCP server pointed at the new system. Three rules made it safe — the invoice number and date never
|
||||
change, the contact is looked up rather than guessed, the product is looked up rather than guessed —
|
||||
and one hard constraint: if a contact or a product is missing, the run fails loudly rather than
|
||||
creating a near-duplicate. Before releasing it on the rest, we checked one invoice end to end:
|
||||
number, date, contact, product lines.
|
||||
</p>
|
||||
<p>
|
||||
One thing we will not blur, because it is the difference between us and a salesman. The MCP server
|
||||
we ship inside our own management console does hosting operations. It restarts a server, uploads a
|
||||
module, adds or checks a domain, manages backups and reads a log file — that is the published list,
|
||||
and it is a real convenience if you use an AI assistant. It is not a data-migration engine and we do
|
||||
not describe it as one. The import work above was done with an automation workflow and a third-party
|
||||
MCP; the AI was doing the tedious part and being checked by a human, exactly as it should be.
|
||||
</p>
|
||||
<p>
|
||||
And the honest limit, in the words of the project that knows this best. The OpenUpgrade
|
||||
documentation names the export-and-import alternative and prices it plainly: you recover only some
|
||||
of your data, and in particular you do not get the history and the links between records — the
|
||||
invoices for each customer, for example. That is the risk of any route that moves documents into a
|
||||
fresh system, and it is why, if you take that route with us, you ask us one question before you
|
||||
approve anything: which records will be in the new database, and which will not. We would rather you
|
||||
ask it than assume it.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Self-hosting cost -->
|
||||
<section class="section-light">
|
||||
@@ -809,9 +843,9 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
<h2 class="section-title">What doing it yourself really costs</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
A rented server is cheap. That is the smallest number in this decision. A modest virtual server
|
||||
costs about the price of a restaurant meal a year, and Odoo Community itself is free — you will not
|
||||
find a per-user licence anywhere in this route, because Community does not have one.
|
||||
A rented server is cheap. That is the smallest number in this decision. <a href="blog/posts/community-vs-enterprise-cost.html">Odoo Community itself is
|
||||
free</a> — you will not find a per-user licence anywhere in this route, because Community does not have
|
||||
one.
|
||||
</p>
|
||||
<p>
|
||||
What is not in that number is the person. An upgrade on your own server means someone installs the
|
||||
@@ -840,7 +874,7 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
<h2 class="section-title">Questions about upgrading</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary>Is an upgrade the same as an update?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Is an upgrade the same as an update?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
No. An update gives you the newest revision of the software you already run. An upgrade moves
|
||||
@@ -851,7 +885,7 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Can we upgrade straight from Odoo 14 to Odoo 20?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Can we upgrade straight from Odoo 14 to Odoo 20?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
No. It is one major version at a time: 14 → 15 → 16 → 17 → 18 → 19 → 20. Skipping a version is
|
||||
@@ -862,21 +896,22 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>What happens to my history — the invoices, the payments, the attachments?</summary>
|
||||
<summary class="plausible-event-name=FAQ">What happens to my history — the invoices, the payments, the attachments?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
That is the right question to ask, and the answer depends on which route you take. A version
|
||||
migration carries the database across and keeps the history and the links between records; that
|
||||
is the point of it. A route that moves documents into a fresh system does not, and the
|
||||
OpenUpgrade documentation says so plainly: export and import recovers only some of your data,
|
||||
and you lose the history and the links — the invoices for each customer, for example. If your
|
||||
upgrade runs on our service, ask us to list exactly which records will be in the new database
|
||||
before you approve anything.
|
||||
That is the right question to ask, and the honest answer is that it depends on the route. The
|
||||
OpenUpgrade route — a version migration run on your own server — carries the database across and
|
||||
keeps the history and the links between records. The OpenUpgrade documentation warns that the
|
||||
other route, moving documents into a fresh system, recovers only some of your data and loses the
|
||||
history and the links between records — the invoices for each customer, for example. Our service
|
||||
builds you a new database and moves your data into it, so ours is the route to ask about: before
|
||||
you approve anything, ask us to list exactly which records will be in the new database, and
|
||||
which will not. We would rather you ask it than assume it.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Will my custom modules still work?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Will my custom modules still work?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Not by themselves. A module written for your business has to have its code brought up to the
|
||||
@@ -889,7 +924,7 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>What does it cost, and how long does it take?</summary>
|
||||
<summary class="plausible-event-name=FAQ">What does it cost, and how long does it take?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
We publish no price and no duration for the upgrade service, and we are not going to invent one
|
||||
@@ -901,7 +936,7 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Do I need a developer?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Do I need a developer?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
To run the commands in the technical section, yes — or someone comfortable in a terminal with
|
||||
@@ -911,7 +946,7 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Can I look at the upgraded system before going live?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Can I look at the upgraded system before going live?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Yes, and you should. Whoever does the work migrates a copy first — that is the first rule of the
|
||||
@@ -923,7 +958,7 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>We are hosted somewhere else. Can you still upgrade us?</summary>
|
||||
<summary class="plausible-event-name=FAQ">We are hosted somewhere else. Can you still upgrade us?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>
|
||||
Yes, that is exactly what our migration service is for. You open a support ticket, we send you a
|
||||
@@ -952,6 +987,7 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
@@ -960,6 +996,7 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="legal.html">Legal</a></li>
|
||||
</ul>
|
||||
@@ -983,7 +1020,7 @@ sudo -u postgres pg_restore -d <DB_NEW> /path/backup/<DB>.dump
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:hello@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="oc-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
||||
<link rel="preload" as="image" href="/images/hero/bootcamp-hero-mobile-900.webp" media="(max-width: 640px)" fetchpriority="high" />
|
||||
<link rel="preload" as="image" href="/images/hero/bootcamp-hero-desktop-1920.webp" media="(min-width: 641px)" fetchpriority="high" />
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- ODOO ERP Automation Bootcamp landing page (page-scoped; additive) ---- */
|
||||
.bc-sr-only {
|
||||
@@ -192,6 +193,14 @@
|
||||
form[action$="/shop/post_basket"] .btn {
|
||||
line-height: inherit;
|
||||
}
|
||||
/* At 0 seats /static/bootcamp-availability.js disables these Buy buttons; make the
|
||||
disabled state read as disabled — quiet dimming in the page's own CI, never an
|
||||
alert banner. */
|
||||
form[action$="/shop/post_basket"] .btn:disabled,
|
||||
form[action$="/shop/post_basket"] .btn[aria-disabled="true"] {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Grids — auto-fit so no breakpoint is needed */
|
||||
.bc-list {
|
||||
@@ -223,7 +232,7 @@
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-rest);
|
||||
padding: 1.4rem 1.4rem 1.4rem 3.4rem;
|
||||
transition: box-shadow 0.25s, transform 0.25s;
|
||||
transition: transform 0.25s; /* box-shadow kept, not transitioned (non-composited) */
|
||||
}
|
||||
.bc-lessons li:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
@@ -313,7 +322,7 @@
|
||||
.bc-schedule dt {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.92rem;
|
||||
color: var(--brass-deep);
|
||||
color: #876c1e; /* 4.68:1 on --ivory (was --brass-deep 4.49:1) */
|
||||
}
|
||||
.bc-schedule dd {
|
||||
margin: 0;
|
||||
@@ -452,6 +461,109 @@
|
||||
.btn-brass:focus-visible {
|
||||
outline-color: #fff;
|
||||
}
|
||||
/* Waiting list — for someone who cannot attend the January cohort.
|
||||
Deliberately quieter than the Buy button: outline button, smaller type, no brass fill. */
|
||||
.bc-waitlist {
|
||||
/* Component-scoped error colour: the site has no shared token for it. */
|
||||
--wl-error: #b02a37;
|
||||
max-width: 720px;
|
||||
margin: 2.5rem auto 0;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: var(--ivory);
|
||||
text-align: left;
|
||||
}
|
||||
.bc-wl-title {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 1.1rem;
|
||||
color: var(--ink);
|
||||
}
|
||||
.bc-wl-lead {
|
||||
margin: 0 0 1.1rem;
|
||||
font-size: 0.88rem;
|
||||
line-height: 1.6;
|
||||
color: rgba(23, 28, 38, 0.78); /* the page's own .bc-note value, on the same cream */
|
||||
}
|
||||
.bc-wl-form input,
|
||||
.bc-wl-form textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 0.6rem;
|
||||
padding: 0.6rem 0.75rem;
|
||||
font-family: Inter, sans-serif;
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink);
|
||||
background: #fff;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.bc-wl-form textarea {
|
||||
min-height: 3.4rem;
|
||||
resize: vertical;
|
||||
}
|
||||
.bc-wl-btn {
|
||||
padding: 0.6rem 1.5rem;
|
||||
font-size: 0.8rem;
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
border-color: rgba(23, 28, 38, 0.35);
|
||||
}
|
||||
.bc-wl-btn:hover {
|
||||
border-color: var(--brass);
|
||||
background: rgba(201, 162, 39, 0.12);
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.bc-wl-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
.bc-wl-success {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: var(--success);
|
||||
}
|
||||
.bc-wl-error {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--wl-error);
|
||||
}
|
||||
|
||||
/* --- 2026-11-02 PageSpeed pass (page-scoped, additive) ---------------------
|
||||
1. The footer <h4>s became <h3>s so the heading order descends after the last
|
||||
section h2 (a11y "heading-order"); these rules keep their look identical to
|
||||
the shared .footer h4 in /style.css.
|
||||
2. A link inside an on-dark note is the lighter brass (7.15:1 on midnight,
|
||||
A11y "color-contrast") and underlined, so it is distinguishable without
|
||||
colour (A11y "link-in-text-block"). */
|
||||
.footer h3 {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
color: #fff;
|
||||
margin-bottom: 0.8rem;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
.bc-note.on-dark a {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
}
|
||||
/* the footer copyright line at .35 alpha was 3.2:1 on midnight */
|
||||
.footer .fcopy {
|
||||
color: rgba(255, 255, 255, 0.5); /* 5.17:1 */
|
||||
}
|
||||
/* no-JS footer fallback (rendered only when JavaScript is off) */
|
||||
.footer .bc-noscript {
|
||||
margin-top: 0.6rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.footer .bc-noscript a {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
@@ -482,8 +594,9 @@
|
||||
"@type": "CourseInstance",
|
||||
"courseMode": "online",
|
||||
"courseWorkload": "PT1H",
|
||||
"startDate": "2026-01-22",
|
||||
"endDate": "2026-03-26",
|
||||
"maximumAttendeeCapacity": 6,
|
||||
"startDate": "2027-01-21",
|
||||
"endDate": "2027-03-25",
|
||||
"instructor": {
|
||||
"@type": "Person",
|
||||
"name": "Oliver Arnold",
|
||||
@@ -500,7 +613,7 @@
|
||||
},
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "465.00",
|
||||
"price": "595.00",
|
||||
"priceCurrency": "USD",
|
||||
"category": "Paid",
|
||||
"url": "https://odoo4projects.com/odoo-erp-automation-bootcamp/"
|
||||
@@ -554,6 +667,12 @@
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
@@ -569,9 +688,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero bc-hero">
|
||||
<div class="container">
|
||||
<p class="hero-kicker">Q1 2026 · 10 LIVE SESSIONS · OLIVER ARNOLD</p>
|
||||
<p class="hero-kicker">Q1 2027 · 10 LIVE SESSIONS · OLIVER ARNOLD</p>
|
||||
<h1>ODOO ERP Automation Bootcamp</h1>
|
||||
<p class="hero-sub">
|
||||
No programming. No server to install. If you can run your business on a spreadsheet, you can do
|
||||
@@ -580,19 +700,26 @@
|
||||
<div class="hero-stats">
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> 10 live sessions, one hour each</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Thursdays 18:00–19:00 Central Time</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Starts Thursday 22 January 2026</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Starts Thursday 21 January 2027</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> One year of Odoo Community Edition included</span>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<input type="hidden" name="basket" value='[{"product_id":12,"qty":1}]' />
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":17,"qty":1,"info":"Q1 2027, English"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Buy for 465.00 USD</button>
|
||||
<button type="submit" class="btn btn-brass btn-lg">Buy for 595.00 USD</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Live remaining-seat count, immediately below the hero. One seat element only on
|
||||
the page; /static/bootcamp-availability.js fills it from the availability webhook
|
||||
and leaves it empty+hidden if that fetch fails. -->
|
||||
<div class="container">
|
||||
<p class="bc-note bc-seats" data-bc-seats hidden></p>
|
||||
</div>
|
||||
|
||||
<!-- From zero to a running ERP -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
@@ -607,10 +734,10 @@
|
||||
</p>
|
||||
<p class="bc-subline">Three months. Ten hours of teaching. One system that runs your company.</p>
|
||||
<div class="bc-action">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<input type="hidden" name="basket" value='[{"product_id":12,"qty":1}]' />
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":17,"qty":1,"info":"Q1 2027, English"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Buy for 465.00 USD</button>
|
||||
<button type="submit" class="btn btn-brass btn-lg">Buy for 595.00 USD</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -716,6 +843,9 @@
|
||||
free plan. The free plan is not part of this price and is not included in the programme.
|
||||
Everything else listed above is.
|
||||
</p>
|
||||
<p class="bc-note on-dark">
|
||||
<strong>Adding capability later:</strong> our guide to <a href="/blog/posts/howto-custom-module.html">installing custom Odoo modules from Git</a> shows both routes — Quick Git for a zip you bought, Git for a developer.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -730,22 +860,24 @@
|
||||
<dt>Sessions</dt>
|
||||
<dd>10, every Thursday at 18:00–19:00 Central Time</dd>
|
||||
<dt>Term</dt>
|
||||
<dd>Q1 2026</dd>
|
||||
<dd>Q1 2027</dd>
|
||||
<dt>First session</dt>
|
||||
<dd>Thursday 22 January 2026</dd>
|
||||
<dd>Thursday 21 January 2027</dd>
|
||||
<dt>Last session</dt>
|
||||
<dd>Thursday 26 March 2026</dd>
|
||||
<dd>Thursday 25 March 2027</dd>
|
||||
<dt>Dates</dt>
|
||||
<dd>22 Jan · 29 Jan · 5 Feb · 12 Feb · 19 Feb · 26 Feb · 5 Mar · 12 Mar · 19 Mar · 26 Mar 2026</dd>
|
||||
<dd>21 Jan · 28 Jan · 4 Feb · 11 Feb · 18 Feb · 25 Feb · 4 Mar · 11 Mar · 18 Mar · 25 Mar 2027</dd>
|
||||
<dt>Length</dt>
|
||||
<dd>1 hour per session, 10 hours total</dd>
|
||||
<dt>Where</dt>
|
||||
<dd>Live and online</dd>
|
||||
<dt>Class size</dt>
|
||||
<dd>Limited to 6 participants</dd>
|
||||
<dt>Instructor</dt>
|
||||
<dd>Oliver - The OC Guy - Arnold, Technical Lead at ODOO4projects</dd>
|
||||
</dl>
|
||||
<p class="bc-note">
|
||||
Central Time is UTC−6 until 8 March and UTC−5 afterwards — calendar invites carry
|
||||
Central Time is UTC−6 until 14 March and UTC−5 afterwards — calendar invites carry
|
||||
the correct local time.
|
||||
</p>
|
||||
</div>
|
||||
@@ -774,20 +906,42 @@
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Price and booking</h2>
|
||||
<p class="bc-price">The programme costs USD 465.00 for all ten sessions.</p>
|
||||
<p class="bc-price">The programme costs USD 595.00 for all ten sessions.</p>
|
||||
<p class="bc-note"><strong>Limited to 6 participants</strong> — the cohort is capped, so the instructor can work through your own setup.</p>
|
||||
<p class="bc-note">A seat can be <strong>transferred at any time</strong>, and <strong>cancelled up to two weeks before</strong> the first session on 21 January 2027.</p>
|
||||
<p class="bc-lead">
|
||||
Covers the full programme: ten live sessions, one year of hosted Odoo Community Edition, the
|
||||
alumni community and the expert review.
|
||||
</p>
|
||||
<div class="bc-action">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank">
|
||||
<input type="hidden" name="basket" value='[{"product_id":12,"qty":1}]' />
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":17,"qty":1,"info":"Q1 2027, English"}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg">Buy for 465.00 USD</button>
|
||||
<button type="submit" class="btn btn-brass btn-lg">Buy for 595.00 USD</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Waiting list: for a visitor who cannot attend the January cohort.
|
||||
Secondary to the Buy button above. Same CRM webhook and same payload shape as the
|
||||
site's footer contact form (area:'message'); the copy lives here, in the page's
|
||||
language, and /static/bootcamp-waitlist.js carries no strings. -->
|
||||
<div class="bc-waitlist">
|
||||
<h3 class="bc-wl-title">Another timezone or language?</h3>
|
||||
<p class="bc-wl-lead">The January cohort runs Thursdays 18:00–19:00 Central Time, in English. If you need a different time or another language, join the waiting list and we will write to you when a cohort that fits opens.</p>
|
||||
<form id="bcWaitlistForm" class="bc-wl-form" action="https://n8n.odoo4projects.com/webhook/ODOO4projects/crm" method="post" enctype="text/plain">
|
||||
<label class="bc-sr-only" for="bcWaitlistEmail">Your email address</label>
|
||||
<input type="email" id="bcWaitlistEmail" name="email" placeholder="Your email address" required />
|
||||
<label class="bc-sr-only" for="bcWaitlistComment">Which timezone or language you need</label>
|
||||
<textarea id="bcWaitlistComment" name="comment" rows="2" placeholder="Which timezone or language do you need?" required></textarea>
|
||||
<button type="submit" class="btn bc-wl-btn" data-sending="Adding you…">Join the waiting list</button>
|
||||
</form>
|
||||
<p class="bc-wl-success" id="bcWaitlistSuccess" role="status" style="display:none">You are on the waiting list. We will write to you as soon as a cohort in your timezone or language is announced.</p>
|
||||
<p class="bc-wl-error" id="bcWaitlistError" role="alert" style="display:none">Something went wrong. Please try again.</p>
|
||||
</div>
|
||||
<ul class="bc-related">
|
||||
<li><a href="/support.html#contact">Questions before you book? Talk to us first</a></li>
|
||||
<li><a href="/workshops/">All our live courses, side by side</a></li>
|
||||
<li><a href="/odoo-n8n-masterclass/">The two-hour masterclass on calling n8n from Odoo</a></li>
|
||||
<li><a href="/odoo-hosting-2027.html">What hosting looks like after your year with us</a></li>
|
||||
<li><a href="/support.html">What our support does and does not cover</a></li>
|
||||
<li><a href="/blog/posts/community-vs-enterprise-cost.html">What Community costs compared with Enterprise</a></li>
|
||||
@@ -801,31 +955,31 @@
|
||||
<h2 class="section-title">Questions people ask first</h2>
|
||||
<div class="bc-faq-grid">
|
||||
<details class="bc-faq">
|
||||
<summary>Do I need technical skills?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Do I need technical skills?</summary>
|
||||
<div class="bc-a">
|
||||
<p>No. The sessions assume no ERP knowledge and no coding, and you build on your own data rather than following along on an empty demo.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>What if I miss a session?</summary>
|
||||
<summary class="plausible-event-name=FAQ">What if I miss a session?</summary>
|
||||
<div class="bc-a">
|
||||
<p>The sessions are live and each one builds on the last, so attend if you can. If you miss one, the alumni chat and the open workshop in the final session are where you catch up.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>Is hosting included after the course?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Is hosting included after the course?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Yes, for one year, included in the programme. After that year your system moves to one of our normal hosting plans, at the price published on our site.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>What do I need installed?</summary>
|
||||
<summary class="plausible-event-name=FAQ">What do I need installed?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Nothing to install and nothing to run yourself. A computer and a browser are enough — we provide the live system. n8n, used in lesson 9, is a free account you sign up for on n8n's own free plan.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary>Is this a course about Odoo?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Is this a course about Odoo?</summary>
|
||||
<div class="bc-a">
|
||||
<p>It is a course about your business running. Odoo is the engine under the system you build; the ten lessons are about your stock, your invoices, your customers and the hours this gives back.</p>
|
||||
</div>
|
||||
@@ -833,6 +987,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
@@ -840,16 +995,17 @@
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Useful Links</h4>
|
||||
<h3>Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Legal</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Partners</h4>
|
||||
<h3>Partners</h3>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
@@ -857,17 +1013,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>About us</h4>
|
||||
<h3>About us</h3>
|
||||
<p>We build smart, scalable business solutions by combining the <strong>stability</strong> of Odoo ERP with the <strong>power</strong> of AI Agents and N8N automations.</p>
|
||||
<p>From streamlined sales to global rollouts, our <strong>lean, eco-friendly</strong> approach helps businesses cut costs, boost efficiency, and grow without limits.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Follow us on</h4>
|
||||
<h3>Follow us on</h3>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:hello@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<form class="footer-contact-form" id="footerContactForm" action="https://n8n.odoo4projects.com/webhook/ODOO4projects/crm" method="post" enctype="text/plain" data-ok="Thanks! We'll get back to you shortly." data-err="Something went wrong. Please try again.">
|
||||
<label class="bc-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
@@ -877,12 +1033,15 @@
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
<noscript><p class="bc-noscript">JavaScript is off. Email us directly at <a href="mailto:support@odoo4projects.com">support@odoo4projects.com</a>.</p></noscript>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script defer src="/static/buy.js"></script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/buy.js?v=31314de600"></script>
|
||||
<script defer src="/static/bootcamp-availability.js?v=94dfd8cd7c"></script>
|
||||
<script defer src="/static/bootcamp-waitlist.js?v=6c2e2fbd33"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -31,8 +31,7 @@
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="style.css" /></noscript>
|
||||
<link rel="stylesheet" href="style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- Odoo Hosting 2027 landing page (page-scoped; additive) ---- */
|
||||
.cmp-sr-only {
|
||||
@@ -479,7 +478,7 @@
|
||||
{
|
||||
"@type": "Product",
|
||||
"name": "Managed Odoo Community hosting",
|
||||
"description": "Managed Odoo Community hosting: the server, backups, SSL certificate and version upgrades are run for you on one yearly price, with no per-user licence on Odoo Community.",
|
||||
"description": "Managed Odoo Community hosting: the server, backups and SSL certificate are run for you and your Odoo is kept current within its version, on one yearly price with no per-user licence on Odoo Community. Moving to a new major version is a migration and is quoted separately.",
|
||||
"brand": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"offers": [
|
||||
{
|
||||
@@ -560,7 +559,7 @@
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
@@ -576,14 +575,15 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero cmp-hero">
|
||||
<div class="container">
|
||||
<p class="hero-kicker">Managed Odoo Community Hosting</p>
|
||||
<h1>Odoo Hosting 2027: Managed Odoo Community, <span>Live in About Five Minutes</span></h1>
|
||||
<p class="hero-sub">
|
||||
A managed Odoo Community instance: your stock, orders, invoices and customers in one system. We
|
||||
run the server, the backups, the certificate and the upgrades. You put your own data in and get on
|
||||
with the business.
|
||||
run the server, the backups, the certificate and the updates within your Odoo version. You put
|
||||
your own data in and get on with the business.
|
||||
</p>
|
||||
<div class="hero-stats">
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> About 5 minutes to a live instance</span>
|
||||
@@ -606,8 +606,9 @@
|
||||
<p class="cmp-lead">
|
||||
You should not have to become the IT department to find out what is in your stock. A business
|
||||
system is something you subscribe to, not a project you build. The server, the patches, the
|
||||
backups, the certificate, the version upgrade: those are our job, permanently, and not an evening
|
||||
you hand back to the company.
|
||||
backups, the certificate, the updates within your Odoo version: those are our job, permanently,
|
||||
and not an evening you hand back to the company. Moving the database to a new major version is a
|
||||
migration we quote for separately.
|
||||
</p>
|
||||
<p class="cmp-lead">
|
||||
So we put your stock, your orders, your invoices and who owes you money in one place, and we keep
|
||||
@@ -704,7 +705,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Version upgrades</th>
|
||||
<td class="is-us">A support ticket. We migrate versions 17, 18 and 19.</td>
|
||||
<td class="is-us">Updates and in-version upgrades are included. A move to a new major version is a migration, quoted separately.</td>
|
||||
<td>You do it, after taking a full backup.</td>
|
||||
<td>Push to the branch; if a module update fails, Odoo reverts the server and rolls the database back.</td>
|
||||
<td>Automatic and mandatory on Odoo's schedule.</td>
|
||||
@@ -754,6 +755,15 @@
|
||||
panel. It is optional. The business works exactly the same without it.
|
||||
</p>
|
||||
</div>
|
||||
<div class="cmp-note">
|
||||
<h3>Do you need staging?</h3>
|
||||
<p>
|
||||
A staging environment is a second copy of your system you are allowed to break. It is the right
|
||||
tool when you change Odoo's code, and overkill when you install a finished module on a backup.
|
||||
We wrote out <a href="/odoo-staging-environment/">do you need a staging environment?</a>, and the
|
||||
simpler route we recommend first.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -916,39 +926,39 @@
|
||||
<h2 class="section-title">Questions the table raises</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary>What does "five minutes" actually mean?</summary>
|
||||
<summary class="plausible-event-name=FAQ">What does "five minutes" actually mean?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Five minutes is the time to a running instance, not to a finished system. Putting your own customers, products and stock in is the first week's work, and it is the same week on any of the routes above.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Do you support Odoo Online?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Do you support Odoo Online?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No. Odoo Online runs Odoo's standard apps only and is incompatible with custom modules or modules from the Odoo Apps Store, so you cannot add an app that is not on Odoo's list. Upgrades are automatic and mandatory on Odoo's schedule. If Odoo's standard apps cover everything you will ever need, Odoo Online is the cheaper and simpler answer and we are not the right choice.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Can I add my own apps or OCA modules?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Can I add my own apps or OCA modules?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Odoo's own apps are all there on every plan. Custom and OCA modules install from On the Rise up, by Git or one click. Side Hustle has no module installation.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Do I need an AI assistant to use ODOO4projects?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Do I need an AI assistant to use ODOO4projects?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No. We ship our MCP server directly in the apps, so an AI assistant such as Claude Code or Hermes can restart the server, upload a module, add a domain or read the log for you, and you never open a hosting panel. It is optional: the business works exactly the same without it.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Can we move to Odoo Enterprise later?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Can we move to Odoo Enterprise later?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Yes. Bring your own Odoo Enterprise licence and keep the same instance. No migration.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary>Is there a per-user licence?</summary>
|
||||
<summary class="plausible-event-name=FAQ">Is there a per-user licence?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No. Odoo Community has no per-user licence; our plans are one flat yearly price. Odoo Enterprise, if you bring it, is licensed per user by Odoo S.A.</p>
|
||||
<p>No. <a href="blog/posts/community-vs-enterprise-cost.html">Odoo Community has no per-user licence</a>; our plans are one flat yearly price. Odoo Enterprise, if you bring it, is licensed per user by Odoo S.A.</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
@@ -976,6 +986,7 @@
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
@@ -984,6 +995,7 @@
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="legal.html">Legal</a></li>
|
||||
</ul>
|
||||
@@ -1007,7 +1019,7 @@
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:hello@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="cmp-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
|
||||
@@ -0,0 +1,620 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Odoo Hosting Offers: What a Year Actually Costs</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Odoo hosting offers explained: one flat yearly price, no per-user licence, no setup fee, a 30-day free trial, and what each plan costs."
|
||||
/>
|
||||
<link rel="canonical" href="https://odoo4projects.com/odoo-hosting-offers/" />
|
||||
<meta property="og:title" content="Odoo Hosting Offers: What a Year Actually Costs" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Odoo hosting offers explained: one flat yearly price, no per-user licence, no setup fee, a 30-day free trial, and what each plan costs."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/odoo-hosting-offers/" />
|
||||
<meta property="og:image" content="https://odoo4projects.com/images/black-friday/bf2026-hosting-og.png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta
|
||||
property="og:image:alt"
|
||||
content="Black Friday 2026 poster: 'Black Friday — 2–30 November' and 'Save $100 on Odoo hosting', with a secret deal on the Bootcamp."
|
||||
/>
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:image" content="https://odoo4projects.com/images/black-friday/bf2026-hosting-og.png" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- Odoo Hosting Offers (evergreen hub) page (page-scoped; additive) ---- */
|
||||
.of-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Top bar (page-scoped: the site has no global header) */
|
||||
.of-topbar {
|
||||
background: var(--midnight-2);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.85rem 0;
|
||||
}
|
||||
.of-topbar .container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.of-brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
}
|
||||
.of-brand span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.of-topbar-links {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
font-size: 0.82rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
.of-topbar-links a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.of-topbar-links a:hover {
|
||||
color: var(--brass);
|
||||
}
|
||||
/* Language selector — slides into the top-bar row, right of the links, behind a hairline brass
|
||||
divider. CI §1/§2: brass marks the active language; lang.js owns the markup. */
|
||||
.of-topbar .lang-switch-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.45);
|
||||
}
|
||||
.of-topbar .lang-switch {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.of-topbar .lang-switch a:hover,
|
||||
.of-topbar .lang-switch a:focus-visible {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.of-topbar .lang-switch a[aria-current="true"] {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* Hero */
|
||||
.of-hero {
|
||||
min-height: 0;
|
||||
padding: 3.5rem 0 3rem;
|
||||
}
|
||||
.of-hero .hero-sub {
|
||||
max-width: 640px;
|
||||
}
|
||||
|
||||
/* Date-scoped Black Friday block (removed after 30 Nov 2026 — see BF-BLOCK markers) */
|
||||
.bf-hub {
|
||||
max-width: 780px;
|
||||
margin: 0 auto;
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line-brass);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-rest);
|
||||
padding: 1.75rem 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
.bf-hub h2 {
|
||||
margin-bottom: 0.85rem;
|
||||
}
|
||||
.bf-hub .bf-hub-line {
|
||||
font-size: 1.02rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
.bf-hub .bf-hub-link {
|
||||
margin: 0;
|
||||
}
|
||||
.bf-hub .bf-hub-link a {
|
||||
display: inline-block;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: var(--midnight);
|
||||
background: var(--brass);
|
||||
border-radius: var(--radius-pill);
|
||||
padding: 0.8rem 1.75rem;
|
||||
text-decoration: none;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.bf-hub .bf-hub-link a:hover {
|
||||
background: var(--brass-bright);
|
||||
color: var(--midnight);
|
||||
}
|
||||
.bf-hub .bf-hub-link a:focus-visible {
|
||||
outline: 3px solid var(--midnight);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Prose bands */
|
||||
.of-lead {
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.75;
|
||||
max-width: 760px;
|
||||
margin: 0 auto 1.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
.section-dark .of-lead {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.of-lead:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.of-lead strong {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Plans */
|
||||
.offers-plans {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
max-width: 620px;
|
||||
margin: 0 auto 1.25rem;
|
||||
}
|
||||
.offers-plans li {
|
||||
font-size: 1rem;
|
||||
color: var(--ink);
|
||||
line-height: 1.6;
|
||||
padding: 0.85rem 0;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.offers-plans li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.offers-plans strong {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-weight: 400;
|
||||
font-size: 1.1rem;
|
||||
color: var(--midnight);
|
||||
}
|
||||
.offers-note {
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
max-width: 620px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Pricing list */
|
||||
.of-price-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.of-price-list li {
|
||||
position: relative;
|
||||
padding-left: 1.4rem;
|
||||
margin-bottom: 0.7rem;
|
||||
font-size: 0.95rem;
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
line-height: 1.65;
|
||||
}
|
||||
.of-price-list li::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0.25rem;
|
||||
top: 0.6rem;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--brass);
|
||||
}
|
||||
.of-price-list strong {
|
||||
color: #fff;
|
||||
}
|
||||
.of-regions {
|
||||
font-size: 0.95rem;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
line-height: 1.7;
|
||||
max-width: 760px;
|
||||
margin: 1.5rem auto 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* FAQ (native details/summary — no JS) */
|
||||
.cmp-faq-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cmp-faq {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.4rem 1.25rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
transition: box-shadow 0.25s;
|
||||
}
|
||||
.cmp-faq[open] {
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
.cmp-faq:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
.cmp-faq summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.85rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.98rem;
|
||||
color: var(--midnight);
|
||||
}
|
||||
.cmp-faq summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.cmp-faq summary::after {
|
||||
content: "+";
|
||||
font-family: Inter, sans-serif;
|
||||
color: var(--brass);
|
||||
font-size: 1.15rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
.cmp-faq[open] summary::after {
|
||||
content: "\2212";
|
||||
}
|
||||
.cmp-faq summary:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.cmp-faq .faq-a,
|
||||
.cmp-faq .cmp-a {
|
||||
font-size: 0.87rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.cmp-faq .faq-a p:last-child,
|
||||
.cmp-faq .cmp-a p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.cmp-faq-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Related links */
|
||||
.of-links {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
max-width: 900px;
|
||||
margin: 2.5rem auto 0;
|
||||
}
|
||||
.of-links a {
|
||||
font-size: 0.88rem;
|
||||
color: var(--brass-deep);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
.of-links a:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.btn:focus-visible,
|
||||
.of-topbar-links a:focus-visible {
|
||||
outline: 3px solid var(--brass-bright);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Organization",
|
||||
"@id": "https://odoo4projects.com/#organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/",
|
||||
"foundingDate": "2020",
|
||||
"sameAs": ["https://www.linkedin.com/company/odoo4projects/"],
|
||||
"contactPoint": {
|
||||
"@type": "ContactPoint",
|
||||
"contactType": "customer support",
|
||||
"url": "https://odoo4projects.com/support.html#contact"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "WebPage",
|
||||
"@id": "https://odoo4projects.com/odoo-hosting-offers/",
|
||||
"url": "https://odoo4projects.com/odoo-hosting-offers/",
|
||||
"name": "Odoo Hosting Offers: What a Year Actually Costs",
|
||||
"description": "Odoo hosting offers explained: one flat yearly price, no per-user licence, no setup fee, a 30-day free trial, and what each plan costs.",
|
||||
"isPartOf": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"about": [
|
||||
{ "@type": "Thing", "name": "Odoo hosting offers" },
|
||||
{ "@type": "Thing", "name": "managed Odoo Community hosting" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://odoo4projects.com/" },
|
||||
{ "@type": "ListItem", "position": 2, "name": "Odoo hosting offers", "item": "https://odoo4projects.com/odoo-hosting-offers/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "Product",
|
||||
"name": "On the Rise — managed Odoo Community hosting",
|
||||
"description": "Managed Odoo Community hosting on the On the Rise plan: the server, backups and SSL certificate are run for you and your Odoo is kept current within its version, on one yearly price with no per-user licence and no setup fee. Moving to a new major version is a migration and is quoted separately.",
|
||||
"brand": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"offers": [
|
||||
{
|
||||
"@type": "Offer",
|
||||
"name": "On the Rise",
|
||||
"price": "395.00",
|
||||
"priceCurrency": "USD",
|
||||
"url": "https://odoo4projects.com/odoo-hosting-offers/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "FAQPage",
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Is there a per-user licence?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No. Odoo Community has no per-user licence, and our plans are one flat yearly price. There is nothing to pay for each person who logs in."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Is there a setup fee?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No setup fee. You pay one price for the year and nothing to get started."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What does the 30-day free trial include?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "A live system for 30 days, with no card needed. It does not include backups or your own web address; those start with a paid plan."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Do you have a discount code for Odoo?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Not for Odoo itself. We do not sell Odoo licences, so there is no licence coupon here. When we run a deal, like our yearly Black Friday offer on hosting, it is stated on our own pages."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Where is my system hosted?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "In one of six regions: Amsterdam, Boston, Manchester, Mumbai, São Paulo or Sydney. You choose the closest when you start."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="of-topbar">
|
||||
<div class="container">
|
||||
<a class="of-brand" href="/">ODOO4<span>projects</span></a>
|
||||
<nav class="of-topbar-links" aria-label="Page links">
|
||||
<a href="/index.html#pricing">Plans & pricing</a>
|
||||
<a href="/support.html">Support</a>
|
||||
</nav>
|
||||
<div data-lang-switcher class="lang-switch-slot"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero of-hero">
|
||||
<div class="container">
|
||||
<h1>Odoo hosting offers, and what a year costs</h1>
|
||||
<p class="hero-sub">One yearly price for your whole business. No per-user licence. No setup fee.</p>
|
||||
<div class="hero-actions">
|
||||
<a href="/index.html#trialCard" class="btn btn-brass btn-lg">Start the 30-day free trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Date-scoped Black Friday block -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<!-- BF-BLOCK-START: live 2–30 November 2026 only. Remove this block after 30 Nov 2026. -->
|
||||
<div class="bf-hub">
|
||||
<h2>Black Friday and Cyber Monday 2026</h2>
|
||||
<p class="bf-hub-line">This November we take $100 off your first year of hosting. The window is 2–30 November 2026, and it ends on Cyber Monday.</p>
|
||||
<!-- 2026-11-01, dated for removal: the offer and the code are revealed on /odoo-black-friday/ only. Remove this link with the BF block after 30 November 2026. -->
|
||||
<!-- Buy = CLICK PROXY (offer-CTA click), NOT a sale. The real purchase event is fired on the
|
||||
checkout host (20.odoo4projects.com) by odoo-dev. See wiki/concepts/conversion-tracking-contract. -->
|
||||
<p class="bf-hub-link"><a class="plausible-event-name=Buy" href="/odoo-black-friday/">See the Black Friday offer</a></p>
|
||||
</div>
|
||||
<!-- BF-BLOCK-END -->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What a hosting offer from us actually is -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">What a hosting offer from us actually is</h2>
|
||||
<p class="of-lead">A hosting offer from us is one flat price for a year. That price runs your whole business system, and we run everything under it: the server, the backups, your certificate, and the updates that keep your Odoo current within its version. Moving to a new major version is a migration, and we quote that separately.</p>
|
||||
<p class="of-lead">What is not on the bill: a charge for each person who logs in, and a fee to set you up. Odoo Community has no per-user licence, so there is nothing per seat to pay, and there is no setup fee.</p>
|
||||
<p class="of-lead">Start with a 30-day free trial and no card. If it fits, the year starts when you pay, not when you sign up.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Our plans and what each costs -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Our plans and what each costs</h2>
|
||||
<p class="of-lead">Three plans, each one flat price for a year. Pick by how much room you need, not by how many people will use it.</p>
|
||||
<ul class="offers-plans">
|
||||
<li><strong>Side Hustle</strong> — $214 a year.</li>
|
||||
<li><strong>On the Rise</strong> — $395 a year.</li>
|
||||
<li><strong>Powerhouse</strong> — $595 a year.</li>
|
||||
</ul>
|
||||
<p class="offers-note">On the Rise and up install modules, so you can add capability as your business asks for it. Side Hustle is built for a single web address.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- How our pricing works -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">How our pricing works</h2>
|
||||
<ul class="of-price-list">
|
||||
<li><strong>One yearly price.</strong> Billed yearly, not monthly.</li>
|
||||
<li><strong>No per-user licence.</strong> Community has none, so we do not charge one.</li>
|
||||
<li><strong>No setup fee.</strong> Nothing to pay to start.</li>
|
||||
<li><strong>Renews at list.</strong> Your second year costs what the first year's list price was. There is no quiet increase.</li>
|
||||
<li><strong>30-day free trial.</strong> No card, no commitment.</li>
|
||||
</ul>
|
||||
<p class="of-regions">Hosted in six regions: Amsterdam, Boston, Manchester, Mumbai, São Paulo and Sydney. Pick the one nearest your team.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section class="section-light" id="faq">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Hosting questions</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Is there a per-user licence?</summary>
|
||||
<div class="faq-a"><p>No. Odoo Community has no per-user licence, and our plans are one flat yearly price. There is nothing to pay for each person who logs in.</p></div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Is there a setup fee?</summary>
|
||||
<div class="faq-a"><p>No setup fee. You pay one price for the year and nothing to get started.</p></div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">What does the 30-day free trial include?</summary>
|
||||
<div class="faq-a"><p>A live system for 30 days, with no card needed. It does not include backups or your own web address; those start with a paid plan.</p></div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Do you have a discount code for Odoo?</summary>
|
||||
<div class="faq-a"><p>Not for Odoo itself. We do not sell Odoo licences, so there is no licence coupon here. When we run a deal, like our yearly Black Friday offer on hosting, it is stated on our own pages.</p></div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Where is my system hosted?</summary>
|
||||
<div class="faq-a"><p>In one of six regions: Amsterdam, Boston, Manchester, Mumbai, São Paulo or Sydney. You choose the closest when you start.</p></div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<nav class="of-links" aria-label="Related pages">
|
||||
<a href="/odoo-hosting-2027.html">Odoo hosting in 2027, compared</a>
|
||||
<a href="/blog/posts/community-vs-enterprise-cost.html">What Community costs compared with Enterprise</a>
|
||||
<a href="/index.html#trialCard">Start the 30-day free trial</a>
|
||||
</nav>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Useful Links</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Legal</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Partners</h4>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
<a href="https://OD8N.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OD8N</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>About us</h4>
|
||||
<p>We build smart, scalable business solutions by combining the <strong>stability</strong> of Odoo ERP with the <strong>power</strong> of AI Agents and N8N automations.</p>
|
||||
<p>From streamlined sales to global rollouts, our <strong>lean, eco-friendly</strong> approach helps businesses cut costs, boost efficiency, and grow without limits.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Follow us on</h4>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="of-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
<label class="of-sr-only" for="footerContactText">Your message</label>
|
||||
<textarea id="footerContactText" name="message" placeholder="Your message..." required></textarea>
|
||||
<button type="submit" class="footer-send-btn" aria-label="Send message"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M2 21l21-9L2 3v7l15 2-15 2z" /></svg></button>
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,837 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>ODOO x N8N Masterclass: Call n8n from Odoo, Live in 2 Hours</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Two live hours with Oliver Arnold: call n8n webhooks from Odoo automated actions and build a working automation yourself. Free trial systems, $120."
|
||||
/>
|
||||
<link rel="canonical" href="https://odoo4projects.com/odoo-n8n-masterclass/" />
|
||||
<meta property="og:title" content="ODOO x N8N Masterclass: Call n8n from Odoo, Live in 2 Hours" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Two live hours with Oliver Arnold: call n8n webhooks from Odoo automated actions and build a working automation yourself. Free trial systems, $120."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/odoo-n8n-masterclass/" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- ODOO x N8N Masterclass landing page (page-scoped; additive).
|
||||
The block below is the bootcamp page's page-scoped CSS, reused so the two
|
||||
course pages share one visual language. Only the hero photo comment is
|
||||
rewritten; every value is the bootcamp's. ---- */
|
||||
.bc-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Top bar (page-scoped: the site has no global header) */
|
||||
.bc-topbar {
|
||||
background: var(--midnight-2);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.85rem 0;
|
||||
}
|
||||
.bc-topbar .container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.bc-brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
}
|
||||
.bc-brand span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.bc-topbar-links {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
.bc-topbar-links a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.bc-topbar-links a:hover {
|
||||
color: var(--brass);
|
||||
}
|
||||
/* Language selector — slides into the top-bar row, right of the links, behind a hairline brass divider.
|
||||
CI §1/§2: brass marks the active language; lang.js owns the markup. */
|
||||
.bc-topbar-links {
|
||||
margin-left: auto;
|
||||
}
|
||||
.bc-topbar .lang-switch-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.45);
|
||||
}
|
||||
.bc-topbar .lang-switch {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.bc-topbar .lang-switch a:hover,
|
||||
.bc-topbar .lang-switch a:focus-visible {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.bc-topbar .lang-switch a[aria-current="true"] {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* Hero — same treatment as the bootcamp page: our own London night aerial
|
||||
(CI §5) behind the header copy, with the identical two-zone scrim
|
||||
(.78 0%-88%, ramp 88%-94%, .25 94%-100%) so every text block in the copy
|
||||
zone keeps its contrast floor. Numbers for the scrim: see the bootcamp
|
||||
page's comment and handoffs/2026-10-24-webmaster-to-olchi-bootcamp-page-published.md. */
|
||||
.bc-hero {
|
||||
min-height: 0;
|
||||
padding: 3.5rem 0 3rem;
|
||||
background-image: linear-gradient(90deg,
|
||||
rgba(13, 27, 46, 0.78) 0%,
|
||||
rgba(13, 27, 46, 0.78) 88%,
|
||||
rgba(13, 27, 46, 0.25) 94%,
|
||||
rgba(13, 27, 46, 0.25) 100%),
|
||||
url("/images/hero/bootcamp-hero-desktop-1920.webp");
|
||||
background-size: cover;
|
||||
background-position: 50% 25%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
/* The global .hero::after is a second, 50%-opacity midnight wash for the homepage's
|
||||
flat hero; with the photo + gradient scrim above the copy it only dulls the shot,
|
||||
so it is switched off on this page. One page-scoped rule, no global CSS touched. */
|
||||
.bc-hero::after {
|
||||
content: none;
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.bc-hero {
|
||||
background-image: linear-gradient(90deg,
|
||||
rgba(13, 27, 46, 0.78) 0%,
|
||||
rgba(13, 27, 46, 0.78) 88%,
|
||||
rgba(13, 27, 46, 0.25) 94%,
|
||||
rgba(13, 27, 46, 0.25) 100%),
|
||||
url("/images/hero/bootcamp-hero-mobile-900.webp");
|
||||
background-position: 50% 50%;
|
||||
}
|
||||
}
|
||||
/* wrapped hero-stat labels keep their tick on the first line */
|
||||
.bc-hero .hero-stat {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.bc-hero .hero-stat i {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.bc-lead {
|
||||
font-size: 1.05rem;
|
||||
color: rgba(23, 28, 38, 0.78);
|
||||
max-width: 720px;
|
||||
margin: 0 auto 1rem;
|
||||
line-height: 1.75;
|
||||
}
|
||||
.section-dark .bc-lead,
|
||||
.bc-lead.on-dark {
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
.bc-subline {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
color: var(--midnight);
|
||||
text-align: center;
|
||||
max-width: 720px;
|
||||
margin: 1.75rem auto 1.25rem;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.bc-action {
|
||||
text-align: center;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
/* The CTAs are native basket <form>s with a <button>. A <button> takes
|
||||
`line-height: normal` from the UA font shorthand while an <a> inherits the
|
||||
body line-height, which would make the button 5.6px shorter. Match the
|
||||
anchors' height: one declaration, no new look. */
|
||||
form[action$="/shop/post_basket"] .btn {
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/* Grids — auto-fit so no breakpoint is needed */
|
||||
.bc-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1rem;
|
||||
max-width: 1040px;
|
||||
}
|
||||
|
||||
/* Learning tiles (light canvas) */
|
||||
.bc-lessons {
|
||||
list-style: none;
|
||||
counter-reset: bc-lesson;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1rem;
|
||||
max-width: 1040px;
|
||||
}
|
||||
.bc-lessons li {
|
||||
counter-increment: bc-lesson;
|
||||
position: relative;
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-rest);
|
||||
padding: 1.4rem 1.4rem 1.4rem 3.4rem;
|
||||
transition: box-shadow 0.25s, transform 0.25s;
|
||||
}
|
||||
.bc-lessons li:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
.bc-lessons li::before {
|
||||
content: counter(bc-lesson);
|
||||
position: absolute;
|
||||
left: 1.15rem;
|
||||
top: 1.3rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.5rem;
|
||||
color: var(--brass-deep);
|
||||
line-height: 1;
|
||||
}
|
||||
.bc-lessons h3 {
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
color: var(--midnight);
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
.bc-lessons p {
|
||||
font-size: 0.86rem;
|
||||
color: rgba(23, 28, 38, 0.78);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Cards on midnight */
|
||||
.bc-cards {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1rem;
|
||||
max-width: 1040px;
|
||||
}
|
||||
.bc-cards li {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid var(--line-brass);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.35rem 1.4rem;
|
||||
}
|
||||
.bc-cards h3 {
|
||||
font-size: 1rem;
|
||||
color: #fff;
|
||||
margin-bottom: 0.45rem;
|
||||
}
|
||||
.bc-cards p {
|
||||
font-size: 0.86rem;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
line-height: 1.65;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.bc-note {
|
||||
max-width: 720px;
|
||||
margin: 1.5rem auto 0;
|
||||
font-size: 0.86rem;
|
||||
color: rgba(23, 28, 38, 0.78);
|
||||
line-height: 1.65;
|
||||
}
|
||||
.bc-note.on-dark {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
.bc-note strong {
|
||||
color: var(--midnight);
|
||||
}
|
||||
.bc-note.on-dark strong {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Definition list (prerequisites) */
|
||||
.bc-schedule {
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(9rem, auto) 1fr;
|
||||
gap: 0.55rem 1.25rem;
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-rest);
|
||||
padding: 1.5rem 1.75rem;
|
||||
}
|
||||
.bc-schedule dt {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.92rem;
|
||||
color: var(--brass-deep);
|
||||
}
|
||||
.bc-schedule dd {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
/* Price line */
|
||||
.bc-price {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.3rem;
|
||||
color: var(--midnight);
|
||||
text-align: center;
|
||||
margin: 0 auto 1rem;
|
||||
}
|
||||
|
||||
/* Related links */
|
||||
.bc-related {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 2rem auto 0;
|
||||
max-width: 720px;
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.bc-related li {
|
||||
position: relative;
|
||||
padding-left: 1.4rem;
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
.bc-related li::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0.25rem;
|
||||
top: 0.55rem;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--brass);
|
||||
}
|
||||
.bc-related a {
|
||||
color: var(--midnight);
|
||||
text-decoration: underline;
|
||||
text-decoration-color: var(--brass);
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
.bc-related a:hover {
|
||||
text-decoration-color: var(--brass-deep);
|
||||
text-decoration-thickness: 2px;
|
||||
}
|
||||
|
||||
/* FAQ (native details/summary — no JS) */
|
||||
.bc-faq-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
align-items: start;
|
||||
}
|
||||
.bc-faq {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.4rem 1.25rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
transition: box-shadow 0.25s;
|
||||
}
|
||||
.bc-faq[open],
|
||||
.bc-faq:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
.bc-faq summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.85rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.98rem;
|
||||
color: var(--midnight);
|
||||
}
|
||||
.bc-faq summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.bc-faq summary::after {
|
||||
content: "+";
|
||||
font-family: Inter, sans-serif;
|
||||
color: var(--brass);
|
||||
font-size: 1.15rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.bc-faq[open] summary::after {
|
||||
content: "\2212";
|
||||
}
|
||||
.bc-faq summary:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.bc-faq .bc-a {
|
||||
font-size: 0.87rem;
|
||||
color: rgba(23, 28, 38, 0.78);
|
||||
line-height: 1.7;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.bc-faq .bc-a p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.bc-faq-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.bc-schedule {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.15rem 0;
|
||||
padding: 1.25rem 1.35rem;
|
||||
}
|
||||
.bc-schedule dd {
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus states */
|
||||
.btn:focus-visible,
|
||||
.bc-topbar-links a:focus-visible,
|
||||
.bc-related a:focus-visible {
|
||||
outline: 3px solid var(--brass-bright);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.btn-brass:focus-visible {
|
||||
outline-color: #fff;
|
||||
}
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Course",
|
||||
"name": "ODOO × N8N Masterclass",
|
||||
"description": "A two-hour live masterclass on connecting Odoo to n8n: calling n8n webhooks from Odoo automated actions, how the n8n integration for Odoo works, and website workarounds for extending your automation. Hands-on in free trial systems.",
|
||||
"url": "https://odoo4projects.com/odoo-n8n-masterclass/",
|
||||
"provider": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects",
|
||||
"url": "https://odoo4projects.com/"
|
||||
},
|
||||
"instructor": {
|
||||
"@type": "Person",
|
||||
"name": "Oliver Arnold",
|
||||
"jobTitle": "Technical Lead",
|
||||
"worksFor": {
|
||||
"@type": "Organization",
|
||||
"name": "ODOO4projects"
|
||||
}
|
||||
},
|
||||
"inLanguage": "en",
|
||||
"hasCourseInstance": {
|
||||
"@type": "CourseInstance",
|
||||
"courseMode": "online",
|
||||
"courseWorkload": "PT2H",
|
||||
"startDate": "2027-02-04",
|
||||
"instructor": {
|
||||
"@type": "Person",
|
||||
"name": "Oliver Arnold"
|
||||
}
|
||||
},
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "120.00",
|
||||
"priceCurrency": "USD",
|
||||
"category": "Paid",
|
||||
"url": "https://20.odoo4projects.com/shop/post_basket"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "FAQPage",
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Do I need to know n8n already?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No. You can arrive having never opened it. The session starts at the webhook and builds up from there, inside n8n's own free plan."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What do I need to know before I join?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Two things. Basic Odoo, meaning you know what workflows and automated actions are and where they live in the interface. And basic programming, enough to know what an API is and how one gets called."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What do I need installed?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Nothing. A computer and a browser. We provide the free Odoo trial system, so you are working in a live setup rather than a video. You use n8n on n8n's own free plan."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Do I get a certificate?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Yes. You receive a certificate at the end of the masterclass."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What language is it in?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "English."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Is this for me if I do not write code?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Yes, as long as you can read code rather than write it. You need to understand what an API call is, not to build an application. If code is entirely foreign to you, the bootcamp covers automating your business without any of it."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="bc-topbar">
|
||||
<div class="container">
|
||||
<a class="bc-brand" href="/">ODOO4<span>projects</span></a>
|
||||
<nav class="bc-topbar-links" aria-label="Page links">
|
||||
<a href="/index.html#pricing">Plans & pricing</a>
|
||||
<a href="/workshops/">Workshops</a>
|
||||
<a href="/support.html">Support</a>
|
||||
</nav>
|
||||
<div data-lang-switcher class="lang-switch-slot"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero bc-hero">
|
||||
<div class="container">
|
||||
<p class="hero-kicker">2 HOURS · LIVE · OLIVER ARNOLD · ENGLISH</p>
|
||||
<p class="hero-kicker">NEXT SESSION · THURSDAYS IN FEBRUARY 2027 · 17:00 CENTRAL TIME</p>
|
||||
<h1>ODOO × N8N Masterclass</h1>
|
||||
<p class="hero-sub">
|
||||
Two live hours with Oliver Arnold, working inside real Odoo and n8n systems: make your ERP start
|
||||
its own jobs instead of waiting for someone to click.
|
||||
</p>
|
||||
<div class="hero-stats">
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> 2 hours live, with a Q&A at the end</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> You build and test a live automation yourself</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> A free Odoo trial system; n8n on n8n's own free plan</span>
|
||||
<span class="hero-stat"><i aria-hidden="true">✓</i> Certificate when you are done</span>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":44,"qty":1}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg plausible-event-name=Buy">Buy for 120.00 USD</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What the two hours give you -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">What the two hours give you</h2>
|
||||
<p class="bc-lead">
|
||||
Your Odoo system already knows the moment a quote is confirmed, a stock level drops, or an
|
||||
invoice gets paid. Today most of that knowledge sits still until a person notices it and does the
|
||||
next thing by hand.
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
In two hours you learn how to hand that next thing to n8n. One Odoo automated action fires on a
|
||||
business event, calls an n8n webhook, and n8n carries the work forward while you are somewhere
|
||||
else. You build it in the session and you keep the pattern afterwards.
|
||||
</p>
|
||||
<p class="bc-subline">Two hours. One working automation. Your system doing its own work.</p>
|
||||
<div class="bc-action">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":44,"qty":1}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg plausible-event-name=Buy">Buy for 120.00 USD</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Who this is for -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Who this is for</h2>
|
||||
<p class="bc-lead">
|
||||
You already run Odoo and you can name the manual steps that pile up every week. The quote that
|
||||
needs a message sent, the payment that needs a note added, the report someone rebuilds by hand on
|
||||
Friday. You know your way around workflows and automated actions in the interface, and you are
|
||||
comfortable enough with code to read a payload.
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
This is not a first course in Odoo, and it is not an owner's introduction to ERP. If you have
|
||||
never opened Odoo, or an API is still a vague word to you, start with the
|
||||
<a href="/odoo-erp-automation-bootcamp/">ODOO ERP Automation Bootcamp</a> instead. This
|
||||
masterclass assumes you are already past that line.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What you will learn -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">What you will learn</h2>
|
||||
<ol class="bc-lessons">
|
||||
<li>
|
||||
<h3>Calling n8n webhooks from Odoo automated actions.</h3>
|
||||
<p>The core of the session. You set an automated action to fire on a business event and call an n8n webhook, carrying the record's data with it, and you watch the workflow pick it up on the other side. This is the piece most people have never wired up themselves.</p>
|
||||
</li>
|
||||
<li>
|
||||
<h3>How the n8n integration for Odoo works, with tips and tricks from real use cases.</h3>
|
||||
<p>What is actually happening underneath when the two systems talk, the parts that trip people up, and the shortcuts that come from running this on live systems rather than in a demo.</p>
|
||||
</li>
|
||||
<li>
|
||||
<h3>Smart website workarounds for extending your Odoo automation.</h3>
|
||||
<p>Where Odoo's own automation stops, and the website-side workarounds that get you further without writing a custom module.</p>
|
||||
</li>
|
||||
</ol>
|
||||
<p class="bc-lead">For a worked example end to end, our post on <a href="/blog/posts/odoo-19-to-20-invoice-migration-with-n8n-and-mcp.html">migrating invoices between Odoo versions</a> shows the same idea with an n8n workflow and an MCP tool.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- The hands-on part -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">The hands-on part</h2>
|
||||
<p class="bc-lead">
|
||||
You spend most of the two hours inside the systems. We give you a free Odoo trial environment,
|
||||
and you work through the exercises step by step inside n8n's own free plan: build the automated
|
||||
action, wire the webhook, run the workflow, then break it and fix it with Oliver alongside you.
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
You finish having tested a live automation on your own screen, and you keep access to the pattern
|
||||
you built.
|
||||
</p>
|
||||
<p class="bc-note on-dark">
|
||||
<strong>On n8n, in plain words:</strong> the n8n workspace is n8n's own free plan, which you sign
|
||||
up for yourself. It is not part of the $120 and not included.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What you need first -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">What you need first</h2>
|
||||
<dl class="bc-schedule">
|
||||
<dt>Basic Odoo</dt>
|
||||
<dd>You know what workflows and automated actions are and where to find them.</dd>
|
||||
<dt>Basic programming</dt>
|
||||
<dd>You know what an API is and how one gets called. You do not need to be a developer.</dd>
|
||||
<dt>n8n experience</dt>
|
||||
<dd>None needed. You can arrive having never opened n8n.</dd>
|
||||
</dl>
|
||||
<p class="bc-note">
|
||||
If the first two do not describe you yet, the
|
||||
<a href="/odoo-erp-automation-bootcamp/">bootcamp</a> is the right first step.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Your instructor -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Your instructor</h2>
|
||||
<p class="bc-lead">
|
||||
<strong>Oliver Arnold, Technical Lead at ODOO4projects.</strong>
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
Oliver has spent more than 25 years building software that has to keep working, and he is the lead
|
||||
architect of the platform our hosting runs on. He teaches the way he works: the real system on the
|
||||
screen, the real error in front of you, and the two of you fixing it together.
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
He is the only instructor on this masterclass. Every session is him.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Price and booking -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Price and booking</h2>
|
||||
<p class="bc-price">The masterclass costs USD 120.00.</p>
|
||||
<p class="bc-lead">
|
||||
Covers two live hours with Oliver, the Q&A, the step-by-step exercises, the free Odoo trial
|
||||
system, and your certificate when you finish.
|
||||
</p>
|
||||
<p class="bc-subline">Next session: Thursdays in February 2027, 17:00 Central Time</p>
|
||||
<p class="bc-note">
|
||||
The four Thursdays are 4, 11, 18 and 25 February 2027. Central Time is UTC−6 in February
|
||||
— calendar invites carry the correct local time.
|
||||
</p>
|
||||
<div class="bc-action">
|
||||
<form method="post" action="https://20.odoo4projects.com/shop/post_basket" target="_blank" class="plausible-event-name=Buy">
|
||||
<input type="hidden" name="basket" value='[{"product_id":44,"qty":1}]' />
|
||||
<input type="hidden" name="clear" value="1" />
|
||||
<button type="submit" class="btn btn-brass btn-lg plausible-event-name=Buy">Buy for 120.00 USD</button>
|
||||
</form>
|
||||
</div>
|
||||
<ul class="bc-related">
|
||||
<li><a href="/support.html#contact">Questions before you book? Talk to us first</a></li>
|
||||
<li><a href="/workshops/">All our live courses, side by side</a></li>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">The ten-week bootcamp, if you are starting from zero</a></li>
|
||||
<li><a href="/support.html">What our support does and does not cover</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Questions people ask first</h2>
|
||||
<div class="bc-faq-grid">
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">Do I need to know n8n already?</summary>
|
||||
<div class="bc-a">
|
||||
<p>No. You can arrive having never opened it. The session starts at the webhook and builds up from there, inside n8n's own free plan.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">What do I need to know before I join?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Two things. Basic Odoo, meaning you know what workflows and automated actions are and where they live in the interface. And basic programming, enough to know what an API is and how one gets called.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">What do I need installed?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Nothing. A computer and a browser. We provide the free Odoo trial system, so you are working in a live setup rather than a video. You use n8n on n8n's own free plan.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">Do I get a certificate?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Yes. You receive a certificate at the end of the masterclass.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">What language is it in?</summary>
|
||||
<div class="bc-a">
|
||||
<p>English.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">Is this for me if I do not write code?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Yes, as long as you can read code rather than write it. You need to understand what an API call is, not to build an application. If code is entirely foreign to you, the <a href="/odoo-erp-automation-bootcamp/">bootcamp</a> covers automating your business without any of it.</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Useful Links</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Legal</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Partners</h4>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
<a href="https://OD8N.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OD8N</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>About us</h4>
|
||||
<p>We build smart, scalable business solutions by combining the <strong>stability</strong> of Odoo ERP with the <strong>power</strong> of AI Agents and N8N automations.</p>
|
||||
<p>From streamlined sales to global rollouts, our <strong>lean, eco-friendly</strong> approach helps businesses cut costs, boost efficiency, and grow without limits.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Follow us on</h4>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="bc-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
<label class="bc-sr-only" for="footerContactText">Your message</label>
|
||||
<textarea id="footerContactText" name="message" placeholder="Your message..." required></textarea>
|
||||
<button type="submit" class="footer-send-btn" aria-label="Send message"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M2 21l21-9L2 3v7l15 2-15 2z" /></svg></button>
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script defer src="/static/buy.js?v=31314de600"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,827 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Odoo Staging Environment: Do You Actually Need One?</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Most small businesses don't need an Odoo staging environment. How staging works, what it costs, and the back-up-install-test route we offer instead."
|
||||
/>
|
||||
<link rel="canonical" href="https://odoo4projects.com/odoo-staging-environment/" />
|
||||
<meta property="og:title" content="Odoo Staging Environment: Do You Actually Need One?" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="What an Odoo staging environment is, how odoo.sh's staging works, and the simpler route most small businesses should use instead."
|
||||
/>
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/odoo-staging-environment/" />
|
||||
<meta property="og:image" content="https://odoo4projects.com/images/hero/amsterdam.webp" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:image" content="https://odoo4projects.com/images/hero/amsterdam.webp" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- "Odoo staging environment" guide page (page-scoped; additive).
|
||||
Reuses the top bar, band rhythm, hero and FAQ treatment already shipped on
|
||||
what-can-i-use-odoo-for/, plus the final-CTA block from odoo-hosting-2027.html.
|
||||
Three additions this page needs and no other: .oc-lede (the opening prose in
|
||||
the hero), the light-band re-pointing of the shared .oc-steps colours, and the
|
||||
in-prose bullet list inside a dark band. ---- */
|
||||
.oc-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Top bar (page-scoped: the site has no global header) */
|
||||
.cmp-topbar {
|
||||
background: var(--midnight-2);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.85rem 0;
|
||||
}
|
||||
.cmp-topbar .container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.cmp-brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
}
|
||||
.cmp-brand span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar-links {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
font-size: 0.82rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
.cmp-topbar-links a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar-links a:hover {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar .lang-switch-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.45);
|
||||
}
|
||||
.cmp-topbar .lang-switch {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar .lang-switch a:hover,
|
||||
.cmp-topbar .lang-switch a:focus-visible {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.cmp-topbar .lang-switch a[aria-current="true"] {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* Hero */
|
||||
.oc-hero {
|
||||
min-height: 0;
|
||||
padding: 3.5rem 0 3rem;
|
||||
}
|
||||
.oc-hero .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.oc-hero .hero-sub {
|
||||
max-width: 760px;
|
||||
}
|
||||
.oc-hero-img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
opacity: 0.25;
|
||||
filter: brightness(1.15) saturate(1.1);
|
||||
}
|
||||
/* The opening prose in the hero: the reader's question is answered before the first H2. */
|
||||
.oc-lede {
|
||||
max-width: 780px;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
line-height: 1.7;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.oc-lede p {
|
||||
margin-bottom: 0.9rem;
|
||||
}
|
||||
.oc-lede p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oc-lede a {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
|
||||
/* Prose column */
|
||||
.oc-body {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.75;
|
||||
}
|
||||
.section-dark .oc-body {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.oc-body p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oc-body strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-dark .oc-body strong {
|
||||
color: #fff;
|
||||
}
|
||||
.section-dark .oc-body a {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
/* In-prose bullet list (the odoo.sh facts): the shared list has no styling of its own. */
|
||||
.oc-body ul {
|
||||
padding-left: 1.2rem;
|
||||
margin: 0 0 1.2rem;
|
||||
}
|
||||
.oc-body li {
|
||||
margin-bottom: 0.55rem;
|
||||
}
|
||||
.oc-body li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.section-dark .oc-body li::marker {
|
||||
color: var(--brass);
|
||||
}
|
||||
|
||||
/* Numbered path (back up, install, test) */
|
||||
.oc-steps {
|
||||
max-width: 820px;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
counter-reset: oc-step;
|
||||
}
|
||||
.oc-steps li {
|
||||
position: relative;
|
||||
counter-increment: oc-step;
|
||||
padding: 0 0 1.4rem 3.2rem;
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
line-height: 1.7;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.25);
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.oc-steps li::before {
|
||||
content: counter(oc-step);
|
||||
position: absolute;
|
||||
left: -1.05rem;
|
||||
top: -0.15rem;
|
||||
width: 2.1rem;
|
||||
height: 2.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1rem;
|
||||
color: var(--midnight);
|
||||
background: var(--brass);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.oc-steps li strong {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.oc-steps li em {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
.oc-steps li:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
/* The shared .oc-steps colours are tuned for a dark band; this page runs the path
|
||||
on the light band, so the text re-points to ink (the brass counter still reads). */
|
||||
.section-light .oc-steps li {
|
||||
color: var(--ink-soft);
|
||||
border-left-color: rgba(138, 111, 31, 0.3);
|
||||
}
|
||||
.section-light .oc-steps li strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-light .oc-steps li em {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-light .oc-steps li a {
|
||||
color: var(--brass-deep);
|
||||
}
|
||||
|
||||
/* FAQ */
|
||||
.cmp-faq-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cmp-faq {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.4rem 1.25rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
transition: box-shadow 0.25s;
|
||||
}
|
||||
.cmp-faq[open],
|
||||
.cmp-faq:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
.cmp-faq summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.85rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.98rem;
|
||||
color: var(--midnight);
|
||||
}
|
||||
.cmp-faq summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.cmp-faq summary::after {
|
||||
content: "+";
|
||||
font-family: Inter, sans-serif;
|
||||
color: var(--brass);
|
||||
font-size: 1.15rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
.cmp-faq[open] summary::after {
|
||||
content: "\2212";
|
||||
}
|
||||
.cmp-faq summary:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.cmp-faq .cmp-a {
|
||||
font-size: 0.87rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.cmp-faq .cmp-a p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Final CTA (the same block odoo-hosting-2027.html uses) */
|
||||
.cmp-cta {
|
||||
text-align: center;
|
||||
}
|
||||
.cmp-cta .cmp-lead {
|
||||
font-size: 1.1rem;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
max-width: 720px;
|
||||
line-height: 1.75;
|
||||
margin: 0 auto 1.5rem;
|
||||
}
|
||||
.cmp-cta-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
/* Focus states on every CTA */
|
||||
.btn:focus-visible,
|
||||
.cmp-topbar-links a:focus-visible {
|
||||
outline: 3px solid var(--brass-bright);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.btn-brass:focus-visible {
|
||||
outline-color: #fff;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.cmp-faq-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.oc-hero {
|
||||
padding: 3rem 0 2.5rem;
|
||||
}
|
||||
.oc-steps li {
|
||||
padding-left: 2.6rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "WebPage",
|
||||
"@id": "https://odoo4projects.com/odoo-staging-environment/#webpage",
|
||||
"url": "https://odoo4projects.com/odoo-staging-environment/",
|
||||
"name": "Odoo Staging Environment: Do You Actually Need One?",
|
||||
"description": "Most small businesses don't need an Odoo staging environment. How staging works, what it costs, and the back-up-install-test route we offer instead.",
|
||||
"inLanguage": "en-US",
|
||||
"isPartOf": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"breadcrumb": { "@id": "https://odoo4projects.com/odoo-staging-environment/#breadcrumb" },
|
||||
"mainEntity": { "@id": "https://odoo4projects.com/odoo-staging-environment/#article" }
|
||||
},
|
||||
{
|
||||
"@type": "Article",
|
||||
"@id": "https://odoo4projects.com/odoo-staging-environment/#article",
|
||||
"headline": "Odoo Staging Environment: Do You Actually Need One?",
|
||||
"description": "Most small businesses don't need an Odoo staging environment. How staging works, what it costs, and the back-up-install-test route we offer instead.",
|
||||
"articleSection": [
|
||||
"What is an Odoo staging environment?",
|
||||
"How odoo.sh works with staging",
|
||||
"Who staging is really for",
|
||||
"Do you need one? For most small businesses, no.",
|
||||
"The simpler way: back up, install, test",
|
||||
"When it does get complicated, we set up staging for you",
|
||||
"Frequently asked questions"
|
||||
],
|
||||
"inLanguage": "en-US",
|
||||
"datePublished": "2026-11-01",
|
||||
"dateModified": "2026-11-01",
|
||||
"author": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"publisher": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"mainEntityOfPage": { "@id": "https://odoo4projects.com/odoo-staging-environment/#webpage" }
|
||||
},
|
||||
{
|
||||
"@type": "FAQPage",
|
||||
"@id": "https://odoo4projects.com/odoo-staging-environment/#faq",
|
||||
"isPartOf": { "@id": "https://odoo4projects.com/odoo-staging-environment/#webpage" },
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Do I need a staging environment for my Odoo?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Most small businesses do not. You need one if you change Odoo's code, writing or editing modules or migrating a whole system, and you want to test the change on real data before it goes live. If you add finished modules to a running business system, a backup and a careful test does the job that staging would."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What is an Odoo staging environment?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "A copy of your live Odoo, with the same apps and a recent copy of your data, running separately so a mistake in it cannot reach the system your business uses. You try a change in the copy first and move it to the live system only once it works."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "How much does an Odoo.sh staging environment cost?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "odoo.sh's own pricing page lists base hosting from $57.80 a month and Staging environment as a metered line at $14.40 per environment per month, and states the hosting price does not include the Enterprise licence. odoo.sh is reached through Odoo's Custom plan."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Can I test a new module without a staging environment?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Yes. Take a backup first, install the module into your live Odoo, and try it on your real data. Modules install from the On the Rise plan upwards, in one click. If it misbehaves, the backup you took is what puts the system back."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What happens if a new module breaks my Odoo?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "If you took a backup first, tell us through support and we restore it, and your system goes back to the moment of your backup. That is why the backup comes first: it is the safety net that makes a staging environment unnecessary for a single change."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Can you set up a staging environment for me?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Yes. When a change is bigger than one module, a version upgrade, several modules at once, a migration, tell us and we set up the staging environment for you. You do not need a hosting account elsewhere or to learn how staging branches work."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "BreadcrumbList",
|
||||
"@id": "https://odoo4projects.com/odoo-staging-environment/#breadcrumb",
|
||||
"itemListElement": [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"name": "Home",
|
||||
"item": "https://odoo4projects.com/"
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "Odoo Staging Environment",
|
||||
"item": "https://odoo4projects.com/odoo-staging-environment/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="cmp-topbar">
|
||||
<div class="container">
|
||||
<a class="cmp-brand" href="/index.html">ODOO4<span>projects</span></a>
|
||||
<nav class="cmp-topbar-links" aria-label="Page links">
|
||||
<a href="/index.html#pricing">Plans & pricing</a>
|
||||
<a href="/support.html">Support</a>
|
||||
</nav>
|
||||
<div data-lang-switcher class="lang-switch-slot"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero: the reader's question, answered before the first H2 -->
|
||||
<main>
|
||||
<section class="hero oc-hero">
|
||||
<div class="hero-bg">
|
||||
<img
|
||||
class="oc-hero-img"
|
||||
src="/images/hero/amsterdam.webp"
|
||||
alt="Amsterdam at night — one of the six regions our servers run in"
|
||||
width="1920"
|
||||
height="768"
|
||||
fetchpriority="high"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="container">
|
||||
<p class="hero-kicker">STAGING, IN PLAIN WORDS</p>
|
||||
<h1>Do You Need an Odoo Staging Environment?</h1>
|
||||
<div class="oc-lede">
|
||||
<p>
|
||||
An Odoo staging environment is a copy of your live Odoo that you are allowed to break. It carries
|
||||
the same apps, the same settings and a copy of your real data, and it runs on its own, so nothing
|
||||
you do inside it reaches the system your invoices, orders and stock depend on. You install a module
|
||||
— an add-on, a feature you switch on — into the copy, put it through its paces, and if it misbehaves
|
||||
you delete the copy and the business never noticed.
|
||||
</p>
|
||||
<p>
|
||||
That is a developer's tool. Staging exists for the person who changes Odoo's code and wants to see
|
||||
the change work on real data before it goes near the live system. If you write or edit Odoo modules
|
||||
for a living, it is the right instrument, and you already know what to do with it.
|
||||
</p>
|
||||
<p>
|
||||
Most people who search for a staging environment are not that person. They run a shop, a workshop or
|
||||
an office, someone told them they need staging before they touch their Odoo, and the honest answer
|
||||
is that they usually do not. The rest of this page covers how staging works, who it is really for,
|
||||
and what to do instead.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What it is -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">The plain definition</p>
|
||||
<h2 class="section-title">What is an Odoo staging environment?</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Staging is a second version of your Odoo that stands beside the one your business actually uses. The
|
||||
version customers and staff touch is called production. Staging is a copy of it, with the same
|
||||
applications and configuration and a recent copy of your data, running separately so that a mistake
|
||||
there cannot reach production.
|
||||
</p>
|
||||
<p>
|
||||
You use it to try something before committing to it. A new module, a changed setting, a small piece
|
||||
of code: you put it into the copy first, see how it behaves with your real products and your real
|
||||
customers, and only then move it across. If it turns out badly, production never saw it.
|
||||
</p>
|
||||
<p>Staging is somewhere to be wrong without paying for it.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- odoo.sh -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Another vendor's product, stated fairly</p>
|
||||
<h2 class="section-title">How odoo.sh works with staging</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
odoo.sh is Odoo's own hosting platform, and it has staging built in. A project on odoo.sh is
|
||||
organised into three stages, named exactly Production, Staging and Development, and you move a
|
||||
branch between them. A staging branch is a neutralized duplicate of the production database: it
|
||||
holds your real data, and neutralization switches off the parts that would reach the outside world.
|
||||
Scheduled actions and outgoing email are stopped (mail is caught rather than sent), and payment
|
||||
providers, shipping connectors and Odoo's own paid services are put into test mode. That way you can
|
||||
test on production's data without emailing a customer or charging a real card.
|
||||
</p>
|
||||
<p>A few facts worth knowing before you plan around it:</p>
|
||||
<ul>
|
||||
<li>
|
||||
Staging databases are not backed up automatically. You either take a manual backup or restore a
|
||||
production backup into the staging branch.
|
||||
</li>
|
||||
<li>A staging database is deleted automatically after one month. To keep using the branch, you rebuild it.</li>
|
||||
<li>
|
||||
When you merge staging back into production, only the source code moves across. Database changes
|
||||
you made while testing are not carried over, so a setting you need permanently has to be committed
|
||||
as code or copied by hand.
|
||||
</li>
|
||||
<li>On a trial project, production and every staging branch drop back to the Development stage after 30 days.</li>
|
||||
</ul>
|
||||
<p>
|
||||
The price, from odoo.sh's own pricing page: base hosting starts at $57.80 a month, and Staging
|
||||
environment is a metered line at $14.40 per environment per month. Dedicated hosting is $480.00 a
|
||||
month, workers are $57.60 each per month, and storage is $0.20 per GB per month. That page states
|
||||
the hosting price does not include the Enterprise licence. You reach odoo.sh through Odoo's Custom
|
||||
plan, US$49.00 per user per month billed yearly, or US$61.00 monthly.
|
||||
</p>
|
||||
<p>That is an accurate picture of a good product. For a team that ships Odoo code, it is a sensible way to work.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Who it is for -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Who the tool is built for</p>
|
||||
<h2 class="section-title">Who staging is really for</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Staging is for people who change Odoo's code. A developer adding a module, an agency doing a
|
||||
migration, a technical person on staff who has to know a change works before the warehouse opens on
|
||||
Monday. Their job creates the risk staging removes: they are editing the machinery, and a mistake in
|
||||
the machinery is expensive and stays invisible until it is live.
|
||||
</p>
|
||||
<p>If you have that person, or you are that person, staging is a normal and sensible expense.</p>
|
||||
<p>
|
||||
For everyone else, the useful question is whether they need staging at all. For most small
|
||||
businesses the answer is no, and the reason is worth spelling out.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Do you need one -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<p class="section-kicker">The honest answer</p>
|
||||
<h2 class="section-title">Do you need one? For most small businesses, no.</h2>
|
||||
<div class="oc-body">
|
||||
<p>Two things are true of a typical small business, and both point the same way.</p>
|
||||
<p>
|
||||
The first is how you get a new capability. You do not write a module; you buy one that is already
|
||||
finished and proven. A stock feature, a report, a payment option: it was built and tested by someone
|
||||
else and is already in use at thousands of businesses. You install it and you use it. There is no
|
||||
code of yours to test, because there is no code of yours.
|
||||
</p>
|
||||
<p>
|
||||
The second is who tests it. If you have anybody technical at all, the usual arrangement is that your
|
||||
developer runs the module on their own machine before it comes near your live system, and hands it
|
||||
over when it already works. That local test does the job staging does, for the change you are
|
||||
actually making.
|
||||
</p>
|
||||
<p>
|
||||
So the risk staging removes, breaking live data with an untested code change, barely exists in your
|
||||
week. You are not running a code pipeline. You are adding a capability to a business system, and the
|
||||
honest tool for that is smaller than staging: a backup, an install, and a way back if it goes wrong.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- The simpler way -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">The path we recommend first</p>
|
||||
<h2 class="section-title">The simpler way: back up, install, test</h2>
|
||||
<div class="oc-body">
|
||||
<p>There is a lighter version of the same safety net, and it is the one we recommend first.</p>
|
||||
<p>
|
||||
Everything a staging environment protects against comes down to one fear: that a change breaks your
|
||||
live system and your data goes with it. You can settle that fear directly, on the system you already
|
||||
have, without a second environment to pay for and keep running.
|
||||
</p>
|
||||
</div>
|
||||
<ol class="oc-steps">
|
||||
<li>
|
||||
<strong>Take a backup.</strong> Backups run on your instance already. Before you install anything,
|
||||
<a href="/blog/posts/speed-run-backup.html">take one by hand</a>, so you hold a known-good copy from
|
||||
the moment before the change. Backups run on paid plans: four rotating slots on On the Rise and
|
||||
Powerhouse, one on Side Hustle. The 30-day trial has none. Slots work first-in, first-out, so a new
|
||||
backup overwrites the oldest: a backup is your latest safety copy, not a permanent one. If you are
|
||||
on Side Hustle, check the backup exists before you install, and finish your test before the next
|
||||
scheduled backup replaces it.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Install the module.</strong> Modules
|
||||
<a href="/blog/posts/how-to-install-odoo-modules-using-git.html">install from the On the Rise plan upwards</a>,
|
||||
from inside <a href="/odoo-hosting-2027.html">your own Odoo</a>, in one click. On Side Hustle, module
|
||||
installation is not included. Contact support and we will take it from there. You install straight
|
||||
into your live system, which is the point: you want to see it work with your real data.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Test it, for real.</strong> Open the module, click through what it does, and run it against
|
||||
your actual products, customers and orders. Ten minutes of real use tells you more than any test
|
||||
environment.
|
||||
</li>
|
||||
<li>
|
||||
<strong>If it does not work, put the backup back.</strong> If the module misbehaves, tell us through
|
||||
<a href="/support.html">support</a> and we restore the backup you took; the request is handled by
|
||||
support like any other. Restoring puts the system back to the state it was in when you took the
|
||||
backup. Anything entered since then (orders, invoices, payments) goes back with it, so test at a
|
||||
quiet moment and keep the gap short. On a one-slot plan the backup is only as fresh as the next
|
||||
scheduled run, so finish the test before that replaces it.
|
||||
</li>
|
||||
</ol>
|
||||
<div class="oc-body" style="margin-top: 2.25rem">
|
||||
<p>
|
||||
The whole sequence is a backup, a click, a look, and, only if you need it, a restore. For a single
|
||||
module that is less work than setting up and maintaining a staging environment, and it happens on
|
||||
the system your staff already use.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- The escalation -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<p class="section-kicker">When the change is bigger</p>
|
||||
<h2 class="section-title">When it does get complicated, we set up staging for you</h2>
|
||||
<div class="oc-body">
|
||||
<p>Sometimes the change is bigger than a single module.</p>
|
||||
<p>
|
||||
A <a href="/odoo-community-upgrade.html">version upgrade</a> that moves your whole system to a new
|
||||
Odoo. Several modules arriving at once. A migration where the data itself is being reshaped. A change
|
||||
nobody in the business wants to be the one who risks on the live system. These are the moments where
|
||||
a plain backup and restore is not enough, because you need to see a whole rebuilt system working
|
||||
beside the real one before you commit.
|
||||
</p>
|
||||
<p>
|
||||
That is a staging environment, and it is exactly the job it was built for. If you reach that moment,
|
||||
tell us. We set up the staging environment for you: the copy, the test data, the place to try the
|
||||
change. You do not need to learn how the branches work, or hold a hosting account somewhere else to
|
||||
get one.
|
||||
</p>
|
||||
<p>
|
||||
We scope it with you and price it before we start, and we only suggest it when the change is
|
||||
genuinely bigger than a module, not for one app you could install on a backup.
|
||||
</p>
|
||||
<p>
|
||||
That is the honest split. You install finished modules on a backup; we build you a staging
|
||||
environment the day a small business genuinely needs one.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section class="section-light" id="faq">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Straight answers</p>
|
||||
<h2 class="section-title">Frequently asked questions</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Do I need a staging environment for my Odoo?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Most small businesses do not. You need one if you change Odoo's code, writing or editing modules or migrating a whole system, and you want to test the change on real data before it goes live. If you add finished modules to a running business system, a backup and a careful test does the job that staging would.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">What is an Odoo staging environment?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>A copy of your live Odoo, with the same apps and a recent copy of your data, running separately so a mistake in it cannot reach the system your business uses. You try a change in the copy first and move it to the live system only once it works.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">How much does an Odoo.sh staging environment cost?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>odoo.sh's own pricing page lists base hosting from $57.80 a month and Staging environment as a metered line at $14.40 per environment per month, and states the hosting price does not include the Enterprise licence. odoo.sh is reached through Odoo's Custom plan.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Can I test a new module without a staging environment?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Yes. Take a backup first, install the module into your live Odoo, and try it on your real data. Modules install from the On the Rise plan upwards, in one click. If it misbehaves, the backup you took is what puts the system back.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">What happens if a new module breaks my Odoo?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>If you took a backup first, tell us through support and we restore it, and your system goes back to the moment of your backup. That is why the backup comes first: it is the safety net that makes a staging environment unnecessary for a single change.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Can you set up a staging environment for me?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Yes. When a change is bigger than one module, a version upgrade, several modules at once, a migration, tell us and we set up the staging environment for you. You do not need a hosting account elsewhere or to learn how staging branches work.</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Final CTA -->
|
||||
<section class="section-dark cmp-cta" id="talk">
|
||||
<div class="container">
|
||||
<p class="section-kicker">One change, handled properly</p>
|
||||
<h2 class="section-title">Talk to us about your change.</h2>
|
||||
<p class="cmp-lead">
|
||||
Installing a module: take a backup, click install, and ask us if anything looks wrong. A bigger
|
||||
change: we set up a staging environment for you.
|
||||
</p>
|
||||
<div class="cmp-cta-actions">
|
||||
<a href="/support.html#contact" class="btn btn-brass btn-lg">Contact support</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer (copied from what-can-i-use-odoo-for/; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Useful Links</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Legal</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Partners</h4>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
<a href="https://OD8N.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OD8N</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>About us</h4>
|
||||
<p>We build smart, scalable business solutions by combining the <strong>stability</strong> of Odoo ERP with the <strong>power</strong> of AI Agents and N8N automations.</p>
|
||||
<p>From streamlined sales to global rollouts, our <strong>lean, eco-friendly</strong> approach helps businesses cut costs, boost efficiency, and grow without limits.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Follow us on</h4>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="oc-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
<label class="oc-sr-only" for="footerContactText">Your message</label>
|
||||
<textarea id="footerContactText" name="message" placeholder="Your message..." required></textarea>
|
||||
<button type="submit" class="footer-send-btn" aria-label="Send message"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M2 21l21-9L2 3v7l15 2-15 2z" /></svg></button>
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -92,6 +92,12 @@
|
||||
.chat-card{height:82vh}
|
||||
}
|
||||
</style>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
|
||||
@@ -202,8 +202,15 @@
|
||||
user-select: all;
|
||||
}
|
||||
</style>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="page-subtitle">
|
||||
You <b>immediately</b> unlock all new features and higher limits.<br />
|
||||
Any extra time is <b>added</b> to your existing subscription.
|
||||
@@ -242,7 +249,7 @@
|
||||
<div class="plan-tagline">
|
||||
"ODOO Standard .. that is all my business needs"
|
||||
</div>
|
||||
<button class="plan-btn" id="btn-sidehustle">
|
||||
<button class="plan-btn plausible-event-name=Buy" id="btn-sidehustle">
|
||||
Upgrade Now
|
||||
</button>
|
||||
<ul class="plan-features">
|
||||
@@ -262,7 +269,7 @@
|
||||
<div class="plan-tagline">
|
||||
"I need some modules and professional reports"
|
||||
</div>
|
||||
<button class="plan-btn" id="btn-ontherise">Upgrade Now</button>
|
||||
<button class="plan-btn plausible-event-name=Buy" id="btn-ontherise">Upgrade Now</button>
|
||||
<ul class="plan-features">
|
||||
<li>ODOO CE hosting</li>
|
||||
<li>Space for 4 Backups</li>
|
||||
@@ -280,7 +287,7 @@
|
||||
<div class="plan-tagline">
|
||||
"ODOO Enterprise is a must have!"
|
||||
</div>
|
||||
<button class="plan-btn" id="btn-powerhouse">
|
||||
<button class="plan-btn plausible-event-name=Buy" id="btn-powerhouse">
|
||||
Upgrade Now
|
||||
</button>
|
||||
<ul class="plan-features">
|
||||
@@ -486,5 +493,6 @@
|
||||
|
||||
loadContract();
|
||||
</script>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -27,8 +27,8 @@
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" media="print" onload="this.media='all'" />
|
||||
<noscript><link rel="stylesheet" href="/style.css?v=061517baef" /></noscript>
|
||||
<style>
|
||||
/* ---- Partner briefing for Andrew (page-scoped; additive) ---- */
|
||||
.andrew-sr-only {
|
||||
@@ -454,6 +454,12 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
@@ -655,6 +661,7 @@
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Legal</a></li>
|
||||
</ul>
|
||||
@@ -678,7 +685,7 @@
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:hello@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="bc-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
@@ -693,6 +700,6 @@
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -25,7 +25,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<link rel="stylesheet" href="style.css?v=061517baef" />
|
||||
<style>
|
||||
.legal-hero {
|
||||
padding: 4rem 0 2.5rem;
|
||||
@@ -103,8 +103,15 @@
|
||||
.legal-card { padding: 1.25rem; }
|
||||
}
|
||||
</style>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="index.html">← Back to Home</a>
|
||||
@@ -115,7 +122,7 @@
|
||||
<div class="container">
|
||||
<h1>Privacy Policy</h1>
|
||||
<p style="margin-top: 0.5rem; color: rgba(33, 37, 41, 0.6); font-size: 0.85rem;">
|
||||
Last updated 2026-10-21
|
||||
Last updated 2026-11-02
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -129,7 +136,7 @@
|
||||
30 N Gould St, STE R, Sheridan<br />
|
||||
WY 82801, USA
|
||||
</p>
|
||||
<p>Contact: <span class="contact-email">support@ODOO4projects.com</span></p>
|
||||
<p>Contact: <span class="contact-email">support@odoo4projects.com</span></p>
|
||||
</div>
|
||||
|
||||
<div class="legal-card">
|
||||
@@ -167,6 +174,14 @@
|
||||
<p>Our pages load Stripe (payments), Google Fonts, Font Awesome, GSAP, and our own agent widget from our server. Like any website, these requests can see the IP address your browser connects from.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-card">
|
||||
<h2>Advertising cookies</h2>
|
||||
<p>On our Black Friday page we would like to measure our advertising with Google Ads. This is optional, and it is off until you turn it on.</p>
|
||||
<p>If you accept, the Google Ads tag loads and sets advertising cookies (named <strong>_gcl_au</strong> and <strong>_gcl_aw</strong>). They let Google tell us which ad or search led to a visit, so we spend our budget on the ads that work. They do not change what you pay, and we do not sell your data.</p>
|
||||
<p>If you decline, the tag does not load and those cookies are not set. The page works the same either way. You can change your choice at any time with the “Cookie settings” link in the footer of the Black Friday page, or by clearing cookies in your browser.</p>
|
||||
<p>Our privacy-friendly analytics are separate: they set no cookies and collect no personal data.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-card">
|
||||
<h2>Email</h2>
|
||||
<p>We email you about your account, your invoices and your service. Marketing email carries an unsubscribe link, and unsubscribing does not stop service email about an active account.</p>
|
||||
@@ -179,7 +194,7 @@
|
||||
|
||||
<div class="legal-card">
|
||||
<h2>Your requests</h2>
|
||||
<p>Ask us for a copy of your data, a correction, or deletion at <span class="contact-email">support@ODOO4projects.com</span>. If your account is active, deletion ends the service. We keep invoice records for as long as accounting rules require them.</p>
|
||||
<p>Ask us for a copy of your data, a correction, or deletion at <span class="contact-email">support@odoo4projects.com</span>. If your account is active, deletion ends the service. We keep invoice records for as long as accounting rules require them.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-card">
|
||||
@@ -189,6 +204,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -623,6 +623,7 @@ var si = 0,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(UTM.inject({ email: email, location: location }))
|
||||
}).then(function() {
|
||||
if (window.plausible) window.plausible('Trial');
|
||||
trialForm.style.display = 'none';
|
||||
document.getElementById('trialSuccess').classList.add('visible');
|
||||
}).catch(function() {
|
||||
@@ -651,9 +652,14 @@ var si = 0,
|
||||
'<div class="blog-empty">Could not load blog posts.</div>';
|
||||
});
|
||||
|
||||
var blogSearchTracked = false;
|
||||
document
|
||||
.getElementById("blogSearch")
|
||||
.addEventListener("input", function () {
|
||||
if (!blogSearchTracked) {
|
||||
blogSearchTracked = true;
|
||||
if (window.plausible) window.plausible('search posts');
|
||||
}
|
||||
blogState.searchTerm = this.value;
|
||||
blogState.currentPage = 1;
|
||||
renderBlog();
|
||||
@@ -737,6 +743,7 @@ var si = 0,
|
||||
}).catch(function () { /* ignore */ });
|
||||
|
||||
/* Show success message — we'll email the report */
|
||||
if (window.plausible) window.plausible('Project Plan');
|
||||
form.style.display = 'none';
|
||||
success.style.display = 'block';
|
||||
});
|
||||
@@ -898,6 +905,7 @@ var si = 0,
|
||||
}))
|
||||
}).then(function(r) {
|
||||
if (!r.ok) throw new Error('bad status ' + r.status);
|
||||
if (window.plausible) window.plausible('Custom Quote');
|
||||
customQuoteForm.style.display = 'none';
|
||||
document.getElementById('customQuoteSuccess').style.display = 'block';
|
||||
submitBtn.textContent = 'Submit Request';
|
||||
|
||||
@@ -25,17 +25,53 @@
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/odoo-erp-automation-bootcamp/</loc>
|
||||
<lastmod>2026-10-26</lastmod>
|
||||
<loc>https://odoo4projects.com/odoo-hosting-offers/</loc>
|
||||
<lastmod>2026-10-30</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/odooityourself.html</loc>
|
||||
<lastmod>2026-10-26</lastmod>
|
||||
<loc>https://odoo4projects.com/odoo-black-friday/</loc>
|
||||
<lastmod>2026-10-30</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/odoo-erp-automation-bootcamp/</loc>
|
||||
<lastmod>2026-10-30</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/odoo-n8n-masterclass/</loc>
|
||||
<lastmod>2026-10-28</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/workshops/</loc>
|
||||
<lastmod>2026-10-28</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/what-can-i-use-odoo-for/</loc>
|
||||
<lastmod>2026-10-28</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/odoo-staging-environment/</loc>
|
||||
<lastmod>2026-11-01</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/odoo-community-developers/</loc>
|
||||
<lastmod>2026-11-03</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/support.html</loc>
|
||||
<lastmod>2026-10-27</lastmod>
|
||||
@@ -48,6 +84,42 @@
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.4</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/blog/posts/your-agent-can-run-your-odoo-hosting.html</loc>
|
||||
<lastmod>2026-11-05</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/blog/posts/freelancer-directory-soft-launch.html</loc>
|
||||
<lastmod>2026-11-04</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/blog/posts/odoo-20-is-live-on-our-servers-here-is-what-changed.html</loc>
|
||||
<lastmod>2026-11-03</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/blog/posts/from-a-spreadsheet-to-a-running-erp.html</loc>
|
||||
<lastmod>2026-11-02</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/blog/posts/oca-paraguay-internationalization-hackathon.html</loc>
|
||||
<lastmod>2026-10-29</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/blog/posts/how-to-install-odoo-modules-using-git.html</loc>
|
||||
<lastmod>2026-10-28</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/blog/posts/odoo-community-is-going-online-on-odoo4projects.html</loc>
|
||||
<lastmod>2026-10-27</lastmod>
|
||||
@@ -188,13 +260,25 @@
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/de/odoo-erp-automation-bootcamp/</loc>
|
||||
<lastmod>2026-10-26</lastmod>
|
||||
<lastmod>2026-10-30</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/es/odoo-erp-automation-bootcamp/</loc>
|
||||
<lastmod>2026-10-26</lastmod>
|
||||
<lastmod>2026-10-30</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/de/odoo-community-upgrade.html</loc>
|
||||
<lastmod>2026-10-27</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://odoo4projects.com/es/odoo-community-upgrade.html</loc>
|
||||
<lastmod>2026-10-27</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/* ads-consent.js — Google Ads tag, gated behind a consent banner. Page-side only.
|
||||
*
|
||||
* Page: /odoo-black-friday/. Companion to /static/black-friday.js (which is untouched).
|
||||
* The tag ID and the conversion label are read from the banner element's data-* attributes
|
||||
* (#adsConsent[data-ads-id][data-ads-send-to]), so this file stays generic and reusable and
|
||||
* the page holds the one copy of the config. Without those attributes the script stays inert.
|
||||
*
|
||||
* WHY A GATE: the Google Ads tag is NOT cookieless — it sets the advertising cookies
|
||||
* _gcl_au / _gcl_aw. So nothing loads and no request fires until the visitor accepts.
|
||||
* The default is DENY. Declining genuinely prevents the tag from loading.
|
||||
*
|
||||
* WHAT THE CONVERSIONS ARE: both are CLICK PROXIES, not sales.
|
||||
* - a buy form on this page (POST /shop/post_basket) -> data-ads-send-to
|
||||
* - the free-trial form (#trialForm, the n8n webhook) -> data-ads-trial-send-to
|
||||
* The real purchase is measured on the checkout host (20.odoo4projects.com) by odoo-dev.
|
||||
* See wiki/concepts/conversion-tracking-contract. Never label either a sale.
|
||||
*
|
||||
* SAFETY: a conversion tag must never swallow an action. On submit we fire the event and run the
|
||||
* action from the event callback, with a hard timeout that runs it anyway. For a buy form the
|
||||
* action is form.submit(); for the trial form the page hands us its send function via
|
||||
* window.o4pAds.trialConversion. With JavaScript off the native POST forms submit untouched
|
||||
* (no banner, no conversion, no error) and the trial form does its native thing.
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var STORE_KEY = "o4p_ads_consent"; // "granted" | "denied"
|
||||
var SUBMIT_FALLBACK_MS = 700; // hard cap: submit even if the tag never answers
|
||||
var cfg = null; // { id, sendTo, trialSendTo } — from the banner, never hard-coded
|
||||
|
||||
/* ---- the visitor's stored choice ---- */
|
||||
function readChoice() {
|
||||
try {
|
||||
return window.localStorage.getItem(STORE_KEY);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function saveChoice(value) {
|
||||
try {
|
||||
window.localStorage.setItem(STORE_KEY, value);
|
||||
} catch (e) {
|
||||
/* private mode / storage disabled: treat as no choice, banner stays up */
|
||||
}
|
||||
}
|
||||
function isGranted() {
|
||||
return readChoice() === "granted";
|
||||
}
|
||||
|
||||
/* ---- cookie removal (only used to revoke a prior grant) ---- */
|
||||
function clearCookie(name) {
|
||||
var host = window.location.hostname;
|
||||
var bare = host.replace(/^www\./, "");
|
||||
var paths = ["/", "/odoo-black-friday/"];
|
||||
var domains = ["", "; domain=" + host, "; domain=." + bare];
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
for (var j = 0; j < domains.length; j++) {
|
||||
document.cookie =
|
||||
name + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=" + paths[i] + domains[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
function clearAdsCookies() {
|
||||
clearCookie("_gcl_au");
|
||||
clearCookie("_gcl_aw");
|
||||
}
|
||||
|
||||
/* ---- the tag: loaded ONLY on consent ---- */
|
||||
function loadGtag() {
|
||||
if (!cfg || window.__o4pAdsLoaded) return;
|
||||
window.__o4pAdsLoaded = true;
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.gtag =
|
||||
window.gtag ||
|
||||
function () {
|
||||
window.dataLayer.push(arguments);
|
||||
};
|
||||
window.gtag("js", new Date());
|
||||
window.gtag("config", cfg.id);
|
||||
var s = document.createElement("script");
|
||||
s.async = true;
|
||||
s.src = "https://www.googletagmanager.com/gtag/js?id=" + cfg.id;
|
||||
document.head.appendChild(s);
|
||||
}
|
||||
|
||||
/* ---- fire one conversion, then run the action from the callback or the hard timeout ---- */
|
||||
function fireConversion(sendTo, action) {
|
||||
var done = false;
|
||||
function run() {
|
||||
if (done) return;
|
||||
done = true;
|
||||
action(); // the action always runs: at most SUBMIT_FALLBACK_MS after the event
|
||||
}
|
||||
try {
|
||||
window.gtag("event", "conversion", {
|
||||
send_to: sendTo,
|
||||
event_callback: run,
|
||||
});
|
||||
} catch (err) {
|
||||
run();
|
||||
}
|
||||
window.setTimeout(run, SUBMIT_FALLBACK_MS);
|
||||
}
|
||||
|
||||
/* ---- the conversion proxy, fired on a buy-form submit ---- */
|
||||
/* NOTE: the buy path below is deliberately left byte-identical to what shipped and was
|
||||
* verified on 2026-11-02 — its label, its one mark and its 700 ms fallback are unchanged. */
|
||||
function onSubmit(e) {
|
||||
var form = e.target;
|
||||
if (!form || form.tagName !== "FORM") return;
|
||||
var action = form.getAttribute("action") || "";
|
||||
if (action.indexOf("/shop/post_basket") === -1) return;
|
||||
|
||||
// Not configured, no consent, or no tag: do nothing, let the native POST go through.
|
||||
if (!cfg || !isGranted() || typeof window.gtag !== "function") return;
|
||||
|
||||
e.preventDefault();
|
||||
var submitted = false;
|
||||
function submitNow() {
|
||||
if (submitted) return;
|
||||
submitted = true;
|
||||
form.submit(); // bypasses the submit event: no loop, no re-fire
|
||||
}
|
||||
try {
|
||||
window.gtag("event", "conversion", {
|
||||
send_to: cfg.sendTo,
|
||||
event_callback: submitNow,
|
||||
});
|
||||
} catch (err) {
|
||||
submitNow();
|
||||
}
|
||||
// Hard fallback: a blocked / slow / failed tag must never stop the purchase.
|
||||
window.setTimeout(submitNow, SUBMIT_FALLBACK_MS);
|
||||
}
|
||||
|
||||
/* ---- the banner ---- */
|
||||
function bannerEl() {
|
||||
return document.getElementById("adsConsent");
|
||||
}
|
||||
function showBanner() {
|
||||
var el = bannerEl();
|
||||
if (el) el.hidden = false;
|
||||
}
|
||||
function hideBanner() {
|
||||
var el = bannerEl();
|
||||
if (el) el.hidden = true;
|
||||
}
|
||||
function accept() {
|
||||
saveChoice("granted");
|
||||
loadGtag();
|
||||
hideBanner();
|
||||
}
|
||||
function decline() {
|
||||
saveChoice("denied");
|
||||
clearAdsCookies();
|
||||
hideBanner();
|
||||
}
|
||||
|
||||
function init() {
|
||||
document.addEventListener("submit", onSubmit, false);
|
||||
|
||||
var banner = bannerEl();
|
||||
if (!banner) return;
|
||||
|
||||
// Config lives in the page. Missing config -> stay inert (no tag, no conversion).
|
||||
var id = banner.getAttribute("data-ads-id");
|
||||
var sendTo = banner.getAttribute("data-ads-send-to");
|
||||
if (!id || !sendTo) return;
|
||||
cfg = {
|
||||
id: id,
|
||||
sendTo: sendTo,
|
||||
trialSendTo: banner.getAttribute("data-ads-trial-send-to"),
|
||||
bookSendTo: banner.getAttribute("data-ads-book-send-to"),
|
||||
};
|
||||
|
||||
var choice = readChoice();
|
||||
if (choice === "granted") {
|
||||
loadGtag(); // returning visitor who already accepted: load straight away
|
||||
} else if (choice !== "denied") {
|
||||
showBanner(); // first visit (or no stored choice): default deny, ask
|
||||
}
|
||||
|
||||
var acceptBtn = document.getElementById("adsConsentAccept");
|
||||
if (acceptBtn) acceptBtn.addEventListener("click", accept);
|
||||
var declineBtn = document.getElementById("adsConsentDecline");
|
||||
if (declineBtn) declineBtn.addEventListener("click", decline);
|
||||
|
||||
// A real way to change the choice later.
|
||||
var opener = document.getElementById("adsConsentOpen");
|
||||
if (opener) {
|
||||
opener.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
showBanner();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- the trial conversion: the page hands us its real submit function ---- *
|
||||
* Called by /static/black-friday.js when #trialForm is submitted. With consent we fire the Ads
|
||||
* conversion and run the page's submit from the callback; a blocked/slow tag is covered by the
|
||||
* hard timeout, so the trial always completes. Without consent (or without the tag) we run the
|
||||
* submit immediately and fire nothing — the trial is never gated on the tag.
|
||||
*/
|
||||
window.o4pAds = window.o4pAds || {};
|
||||
window.o4pAds.trialConversion = function (action) {
|
||||
if (typeof action !== "function") return;
|
||||
if (!cfg || !cfg.trialSendTo || !isGranted() || typeof window.gtag !== "function") {
|
||||
action();
|
||||
return;
|
||||
}
|
||||
fireConversion(cfg.trialSendTo, action);
|
||||
};
|
||||
|
||||
/* ---- the booking conversion: fired on a click of the booking link ---- *
|
||||
* The booking happens on Google's domain, off-site, so a click is all we can observe. The
|
||||
* caller does NOT preventDefault: the link opens in a new tab on its own, so even a blocked,
|
||||
* slow or absent tag can never stop the booking page from opening — this only ADDS the event.
|
||||
* Without consent (or the label) it fires nothing and simply runs the (optional) action.
|
||||
*/
|
||||
window.o4pAds.bookConversion = function (action) {
|
||||
if (typeof action !== "function") action = function () {};
|
||||
if (!cfg || !cfg.bookSendTo || !isGranted() || typeof window.gtag !== "function") {
|
||||
action();
|
||||
return;
|
||||
}
|
||||
fireConversion(cfg.bookSendTo, action);
|
||||
};
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,521 @@
|
||||
/* Page-local script for /odoo-black-friday/.
|
||||
The homepage behaviours this landing page needs, copied from the site's /script.js:
|
||||
the hero slide-in image driven by the server-location selector, the Buy Now buttons,
|
||||
the free-trial card, the Custom Quote modal and the footer contact form.
|
||||
The blog, OCA-modules and project-plan blocks of /script.js are removed here because this
|
||||
page does not carry those sections (and those blocks throw on a page without their markup).
|
||||
Image paths are root-relative: this page lives in a subdirectory (/odoo-black-friday/).
|
||||
ES5, no build step, no new dependency beyond the gsap the homepage already loads. */
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
/* ---- UTM tracking helpers (verbatim from /script.js) ---- */
|
||||
(function () {
|
||||
function getCookie(name) {
|
||||
var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
||||
return match ? decodeURIComponent(match[2]) : null;
|
||||
}
|
||||
function setCookie(name, value, days) {
|
||||
var expires = '';
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = '; expires=' + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/; SameSite=Lax';
|
||||
}
|
||||
function parseUTM() {
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
var utm = {};
|
||||
var keys = ['source', 'medium', 'campaign'];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var val = urlParams.get('utm_' + keys[i]);
|
||||
if (val) {
|
||||
utm[keys[i]] = val;
|
||||
setCookie('utm_' + keys[i], val, 90);
|
||||
}
|
||||
}
|
||||
return utm;
|
||||
}
|
||||
function getStoredUTM() {
|
||||
var utm = {};
|
||||
var keys = ['source', 'medium', 'campaign'];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var val = getCookie('utm_' + keys[i]);
|
||||
if (val) utm[keys[i]] = val;
|
||||
}
|
||||
return utm;
|
||||
}
|
||||
function injectUTM(data) {
|
||||
var stored = getStoredUTM();
|
||||
if (Object.keys(stored).length > 0) {
|
||||
data.utm_source = stored.source || null;
|
||||
data.utm_medium = stored.medium || null;
|
||||
data.utm_campaign = stored.campaign || null;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
function appendToForm(form) {
|
||||
var stored = getStoredUTM();
|
||||
var keys = ['source', 'medium', 'campaign'];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (stored[keys[i]]) {
|
||||
var input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'utm_' + keys[i];
|
||||
input.value = stored[keys[i]];
|
||||
form.appendChild(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
function toQuery() {
|
||||
var stored = getStoredUTM();
|
||||
var parts = [];
|
||||
var keys = ['source', 'medium', 'campaign'];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (stored[keys[i]]) {
|
||||
parts.push('utm_' + keys[i] + '=' + encodeURIComponent(stored[keys[i]]));
|
||||
}
|
||||
}
|
||||
return parts.join('&');
|
||||
}
|
||||
window.UTM = { parse: parseUTM, getStored: getStoredUTM, inject: injectUTM, appendToForm: appendToForm, toQuery: toQuery };
|
||||
window.UTM.parse();
|
||||
})();
|
||||
|
||||
/* ---- Hero slide-in image + server-location selector (homepage behaviour) ---- */
|
||||
(function () {
|
||||
var SERVERS = [
|
||||
{ host: 'api.meppel.odoo4projects.com', city: 'Amsterdam' },
|
||||
{ host: 'api.boston.odoo4projects.com', city: 'Boston' },
|
||||
{ host: 'api.manchester.odoo4projects.com', city: 'Manchester' },
|
||||
{ host: 'api.mumbai.odoo4projects.com', city: 'Mumbai' },
|
||||
{ host: 'api.saopaulo.odoo4projects.com', city: 'S\u00e3o Paulo' },
|
||||
{ host: 'api.sydney.odoo4projects.com', city: 'Sydney' }
|
||||
];
|
||||
/* Root-relative on purpose: this page is served from /odoo-black-friday/. */
|
||||
var heroImages = {
|
||||
'api.meppel.odoo4projects.com': '/images/hero/amsterdam.webp',
|
||||
'api.boston.odoo4projects.com': '/images/hero/boston.webp',
|
||||
'api.manchester.odoo4projects.com': '/images/hero/london.webp',
|
||||
'api.mumbai.odoo4projects.com': '/images/hero/mumbai.webp',
|
||||
'api.saopaulo.odoo4projects.com': '/images/hero/brazil.webp',
|
||||
'api.sydney.odoo4projects.com': '/images/hero/sydney.webp'
|
||||
};
|
||||
|
||||
function pingServer(host) {
|
||||
return new Promise(function (resolve) {
|
||||
var start = performance.now();
|
||||
var img = new Image();
|
||||
var timedOut = false;
|
||||
var timer = setTimeout(function () {
|
||||
timedOut = true; img.src = '';
|
||||
resolve({ host: host, time: -1 });
|
||||
}, 2000);
|
||||
img.onload = function () {
|
||||
var elapsed = performance.now() - start;
|
||||
if (!timedOut) { clearTimeout(timer); resolve({ host: host, time: elapsed }); }
|
||||
};
|
||||
img.onerror = function () {
|
||||
var elapsed = performance.now() - start;
|
||||
if (!timedOut) { clearTimeout(timer); resolve({ host: host, time: elapsed }); }
|
||||
};
|
||||
img.src = 'https://' + host + '/favicon.ico?_=' + Date.now() + '_' + Math.random().toString(36).slice(2, 6);
|
||||
});
|
||||
}
|
||||
|
||||
function animateHero(city, image, showLabel) {
|
||||
var hero = document.querySelector('.hero');
|
||||
if (!hero || !window.gsap) return;
|
||||
var bg = hero.querySelector('.hero-bg');
|
||||
if (!bg) {
|
||||
bg = document.createElement('div');
|
||||
bg.className = 'hero-bg';
|
||||
hero.insertBefore(bg, hero.firstChild);
|
||||
}
|
||||
var hasExisting = bg.children.length > 0;
|
||||
var newEl = document.createElement('div');
|
||||
newEl.className = 'hero-bg-slide';
|
||||
newEl.style.backgroundImage = "url('" + image + "')";
|
||||
bg.appendChild(newEl);
|
||||
|
||||
var tl = gsap.timeline();
|
||||
gsap.set(newEl, { x: '100%' });
|
||||
|
||||
var label = null;
|
||||
if (showLabel !== false && city) {
|
||||
var oldLabel = hero.querySelector('.hero-city-label');
|
||||
if (oldLabel) oldLabel.remove();
|
||||
label = document.createElement('div');
|
||||
label.className = 'hero-city-label';
|
||||
label.innerHTML = 'Our <strong>' + city + '</strong> server fits your location';
|
||||
hero.appendChild(label);
|
||||
gsap.set(label, { x: '150%' });
|
||||
}
|
||||
|
||||
if (hasExisting) {
|
||||
var oldEl = bg.children[0];
|
||||
gsap.set(oldEl, { x: '0%' });
|
||||
tl.to(oldEl, { x: '100%', duration: 3, ease: 'power2.out' }, 0)
|
||||
.to(newEl, { x: '0%', duration: 3, ease: 'power2.out' }, 0);
|
||||
if (label) {
|
||||
tl.to(label, { x: '0%', duration: 2.5, ease: 'power2.out' }, 0.3);
|
||||
}
|
||||
tl.call(function () { oldEl.remove(); });
|
||||
} else {
|
||||
tl.to(newEl, { x: '0%', duration: 3, ease: 'power2.out' }, 0);
|
||||
if (label) {
|
||||
tl.to(label, { x: '0%', duration: 2.5, ease: 'power2.out' }, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Location selector: click a server card to slide its city into the hero. */
|
||||
var serverCards = document.querySelectorAll('.server-card');
|
||||
serverCards.forEach(function (card, idx) {
|
||||
card.addEventListener('click', function () {
|
||||
var s = SERVERS[idx];
|
||||
if (!s || !heroImages[s.host]) return;
|
||||
serverCards.forEach(function (c) { c.classList.remove('server-best'); });
|
||||
card.classList.add('server-best');
|
||||
animateHero(null, heroImages[s.host], false);
|
||||
});
|
||||
});
|
||||
|
||||
/* Populate the trial + pricing location selects. */
|
||||
var trialLoc = document.getElementById('trialLocation');
|
||||
var pricingLoc = document.getElementById('pricingServerLocation');
|
||||
[trialLoc, pricingLoc].forEach(function (el) {
|
||||
if (el) {
|
||||
SERVERS.forEach(function (s) {
|
||||
var opt = document.createElement('option');
|
||||
var cityVal = s.host.replace('api.', '').replace('.odoo4projects.com', '');
|
||||
opt.value = cityVal;
|
||||
opt.textContent = s.city;
|
||||
el.appendChild(opt);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/* Ping all servers, highlight the fastest, slide its image in. */
|
||||
var results = [];
|
||||
var pending = SERVERS.length;
|
||||
SERVERS.forEach(function (s) {
|
||||
pingServer(s.host).then(function (r) {
|
||||
results.push(r);
|
||||
pending--;
|
||||
if (pending !== 0) return;
|
||||
var valid = results.filter(function (x) { return x.time >= 0; });
|
||||
if (valid.length === 0) return;
|
||||
valid.sort(function (a, b) { return a.time - b.time; });
|
||||
var best = valid[0];
|
||||
var bestServer = SERVERS.filter(function (x) { return x.host === best.host; })[0];
|
||||
if (bestServer) {
|
||||
[trialLoc, pricingLoc].forEach(function (el) {
|
||||
if (el) {
|
||||
var cityVal = bestServer.host.replace('api.', '').replace('.odoo4projects.com', '');
|
||||
for (var i = 0; i < el.options.length; i++) {
|
||||
if (el.options[i].value === cityVal) { el.selectedIndex = i; break; }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (bestServer && heroImages[best.host]) {
|
||||
var cards = document.querySelectorAll('.server-card');
|
||||
for (var i = 0; i < SERVERS.length && i < cards.length; i++) {
|
||||
if (SERVERS[i].host === best.host) { cards[i].classList.add('server-best'); break; }
|
||||
}
|
||||
var img = new Image();
|
||||
img.onload = function () { animateHero(bestServer.city, heroImages[best.host]); };
|
||||
img.src = heroImages[best.host];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* Free-trial card. */
|
||||
var trialForm = document.getElementById('trialForm');
|
||||
if (trialForm) {
|
||||
trialForm.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var email = document.getElementById('trialEmail').value.trim();
|
||||
var location = trialLoc ? trialLoc.value : '';
|
||||
if (!email) return;
|
||||
var btn = trialForm.querySelector('.btn-brass');
|
||||
|
||||
function sendTrial() {
|
||||
btn.textContent = 'Sending...';
|
||||
btn.disabled = true;
|
||||
fetch('https://n8n.odoo4projects.com/webhook/ODOO4projects/trial', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(UTM.inject({ email: email, location: location }))
|
||||
}).then(function () {
|
||||
if (window.plausible) window.plausible('Trial');
|
||||
trialForm.style.display = 'none';
|
||||
document.getElementById('trialSuccess').classList.add('visible');
|
||||
}).catch(function () {
|
||||
btn.textContent = 'Send';
|
||||
btn.disabled = false;
|
||||
var errorMsg = document.createElement('div');
|
||||
errorMsg.className = 'trial-error visible';
|
||||
errorMsg.textContent = 'Something went wrong. Please try again.';
|
||||
trialForm.appendChild(errorMsg);
|
||||
setTimeout(function () { errorMsg.classList.remove('visible'); }, 3000);
|
||||
});
|
||||
}
|
||||
|
||||
/* When the consent gate is present it fires the Google Ads trial conversion and runs
|
||||
sendTrial from the tag's callback, with a hard timeout that runs it anyway — so a
|
||||
blocked or slow tag can never swallow the trial. Without the gate, send directly. */
|
||||
if (window.o4pAds && typeof window.o4pAds.trialConversion === 'function') {
|
||||
window.o4pAds.trialConversion(sendTrial);
|
||||
} else {
|
||||
sendTrial();
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
/* ---- Buy Now — POST the basket straight to the shop, open checkout in a new tab ---- */
|
||||
window.buyNow = function (productId) {
|
||||
var locSelect = document.getElementById('pricingServerLocation');
|
||||
var location = locSelect ? locSelect.value : '';
|
||||
var verSelect = document.getElementById('pricingOdooVersion');
|
||||
var version = verSelect ? verSelect.value : '';
|
||||
var form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = 'https://20.odoo4projects.com/shop/post_basket';
|
||||
form.target = '_blank';
|
||||
form.style.display = 'none';
|
||||
var basket = document.createElement('input');
|
||||
basket.type = 'hidden';
|
||||
basket.name = 'basket';
|
||||
var item = { product_id: productId, qty: 1 };
|
||||
var info = location ? location.replace('.odoo4projects.com', '') : '';
|
||||
if (version) { info += (info ? '|' : '') + version; }
|
||||
if (info) { item.info = info; }
|
||||
basket.value = JSON.stringify([item]);
|
||||
form.appendChild(basket);
|
||||
var clear = document.createElement('input');
|
||||
clear.type = 'hidden';
|
||||
clear.name = 'clear';
|
||||
clear.value = '1';
|
||||
form.appendChild(clear);
|
||||
UTM.appendToForm(form);
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
document.body.removeChild(form);
|
||||
};
|
||||
|
||||
/* ---- Carry the chosen Server Location + Odoo version into the native buy forms ----
|
||||
* The Black Friday buy buttons are plain form POSTs to /shop/post_basket, so they work with
|
||||
* JavaScript off. buyNow() builds `info` for the JS buttons; this does exactly the same for
|
||||
* the native forms, on submit, from the one global selector pair (#pricingServerLocation +
|
||||
* #pricingOdooVersion). Additive only: with JavaScript off the basket posts exactly as before
|
||||
* (no info) and the selector is empty anyway because its options are built here. The POST is
|
||||
* untouched — only the form's own hidden `basket` input is rewritten. */
|
||||
(function () {
|
||||
var forms = document.querySelectorAll('form[action*="/shop/post_basket"]');
|
||||
forms.forEach(function (form) {
|
||||
form.addEventListener('submit', function () {
|
||||
var basket = form.querySelector('input[name="basket"]');
|
||||
if (!basket) return;
|
||||
var locSelect = document.getElementById('pricingServerLocation');
|
||||
var verSelect = document.getElementById('pricingOdooVersion');
|
||||
var location = locSelect ? locSelect.value : '';
|
||||
var version = verSelect ? verSelect.value : '';
|
||||
var info = location ? location.replace('.odoo4projects.com', '') : '';
|
||||
if (version) { info += (info ? '|' : '') + version; }
|
||||
if (!info) return;
|
||||
try {
|
||||
var items = JSON.parse(basket.value);
|
||||
if (!Array.isArray(items)) return;
|
||||
items.forEach(function (it) { if (it) { it.info = info; } });
|
||||
basket.value = JSON.stringify(items);
|
||||
} catch (e) { /* leave the basket untouched rather than break the purchase */ }
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
/* ---- Buy buttons + Custom Quote modal ---- */
|
||||
(function () {
|
||||
document.querySelectorAll('.btn-buy').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var id = this.getAttribute('data-id');
|
||||
if (id) buyNow(parseInt(id, 10));
|
||||
});
|
||||
});
|
||||
|
||||
function openCustomQuoteModal() {
|
||||
document.getElementById('customQuotePanel').style.display = 'block';
|
||||
document.getElementById('customQuoteModal').style.display = 'flex';
|
||||
}
|
||||
function closeCustomQuoteModal() {
|
||||
document.getElementById('customQuoteModal').style.display = 'none';
|
||||
document.getElementById('customQuoteForm').reset();
|
||||
document.getElementById('customQuoteSuccess').style.display = 'none';
|
||||
}
|
||||
window.openCustomQuoteModal = openCustomQuoteModal;
|
||||
window.closeCustomQuoteModal = closeCustomQuoteModal;
|
||||
|
||||
document.querySelectorAll('.btn-empire').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () { openCustomQuoteModal(); });
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') {
|
||||
var modal = document.getElementById('customQuoteModal');
|
||||
if (modal && modal.style.display === 'flex') { closeCustomQuoteModal(); }
|
||||
}
|
||||
});
|
||||
|
||||
var customQuoteForm = document.getElementById('customQuoteForm');
|
||||
if (customQuoteForm) {
|
||||
customQuoteForm.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var name = document.getElementById('cqName').value.trim();
|
||||
var email = document.getElementById('cqEmail').value.trim();
|
||||
var requirements = document.getElementById('cqRequirements').value.trim();
|
||||
if (!name || !email || !requirements) return;
|
||||
var submitBtn = customQuoteForm.querySelector('.btn-lg');
|
||||
submitBtn.textContent = 'Sending...';
|
||||
submitBtn.disabled = true;
|
||||
fetch('https://n8n.odoo4projects.com/webhook/ODOO4projects/crm', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(UTM.inject({ name: name, email: email, requirements: requirements, area: 'quote' }))
|
||||
}).then(function (r) {
|
||||
if (!r.ok) throw new Error('bad status ' + r.status);
|
||||
if (window.plausible) window.plausible('Custom Quote');
|
||||
customQuoteForm.style.display = 'none';
|
||||
document.getElementById('customQuoteSuccess').style.display = 'block';
|
||||
submitBtn.textContent = 'Submit Request';
|
||||
submitBtn.disabled = false;
|
||||
}).catch(function () {
|
||||
submitBtn.textContent = 'Submit Request';
|
||||
submitBtn.disabled = false;
|
||||
var errorMsg = document.createElement('div');
|
||||
errorMsg.style.marginTop = '1rem';
|
||||
errorMsg.style.color = '#dc3545';
|
||||
errorMsg.textContent = 'Something went wrong. Please try again.';
|
||||
customQuoteForm.appendChild(errorMsg);
|
||||
setTimeout(function () { if (errorMsg.parentNode) errorMsg.parentNode.removeChild(errorMsg); }, 3000);
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
/* ---- Booking link — fire the Google Ads booking conversion on the click, through the same
|
||||
consent gate as the buy and trial conversions. The link is a plain <a target="_blank">, so
|
||||
the click is never preventDefault-ed: the Google appointment page opens regardless, and a
|
||||
blocked, slow or absent tag merely skips the event. Fires nothing without consent. ---- */
|
||||
(function () {
|
||||
var link = document.getElementById('bookingCTA');
|
||||
if (!link) return;
|
||||
link.addEventListener('click', function () {
|
||||
if (window.o4pAds && typeof window.o4pAds.bookConversion === 'function') {
|
||||
window.o4pAds.bookConversion();
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
/* ---- Footer contact form ---- */
|
||||
(function () {
|
||||
var form = document.getElementById('footerContactForm');
|
||||
if (!form) return;
|
||||
var emailInput = document.getElementById('footerContactEmail');
|
||||
var textInput = document.getElementById('footerContactText');
|
||||
var submitBtn = form.querySelector('.footer-send-btn');
|
||||
var status = document.getElementById('footerFormStatus');
|
||||
function showStatus(message, isError) {
|
||||
status.textContent = message;
|
||||
status.classList.toggle('error', !!isError);
|
||||
status.classList.add('visible');
|
||||
}
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var email = emailInput.value.trim();
|
||||
var text = textInput.value.trim();
|
||||
if (!email || !text) return;
|
||||
submitBtn.disabled = true;
|
||||
status.classList.remove('visible');
|
||||
fetch('https://n8n.odoo4projects.com/webhook/ODOO4projects/crm', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(UTM.inject({ email: email, requirements: text, area: 'message' }))
|
||||
}).then(function (r) {
|
||||
if (!r.ok) throw new Error('bad status ' + r.status);
|
||||
form.reset();
|
||||
submitBtn.disabled = false;
|
||||
showStatus("Thanks! We'll get back to you shortly.", false);
|
||||
}).catch(function () {
|
||||
submitBtn.disabled = false;
|
||||
showStatus('Something went wrong. Please try again.', true);
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
/* ---- Scroll-triggered reveal (same grids as the homepage, minus blog / project-plan) ---- */
|
||||
(function () {
|
||||
if (!window.gsap || !('IntersectionObserver' in window)) return;
|
||||
var animated = {};
|
||||
var observer = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (!entry.isIntersecting) return;
|
||||
var grid = entry.target;
|
||||
if (!grid || !grid.children || grid.children.length === 0) return;
|
||||
var key = grid.className || 'anon';
|
||||
if (animated[key]) return;
|
||||
animated[key] = true;
|
||||
gsap.fromTo(grid.children, { y: 30, opacity: 0 }, {
|
||||
y: 0, opacity: 1, duration: 0.7, ease: 'power2.out', stagger: 0.08, overwrite: 'auto'
|
||||
});
|
||||
});
|
||||
}, { threshold: 0.1 });
|
||||
|
||||
var grids = document.querySelectorAll('.features-grid, .faq-grid, .pricing-grid');
|
||||
grids.forEach(function (g) {
|
||||
if (g.children.length > 0) { gsap.set(g.children, { y: 30, opacity: 0 }); }
|
||||
observer.observe(g);
|
||||
});
|
||||
})();
|
||||
|
||||
/* ---- Black Friday time remaining (Fix 10) ----
|
||||
ONE documented constant: the instant the offer ends — 30 November 2026, end of day, in the
|
||||
account's US/Eastern context (EST, UTC-5, after the 1 Nov DST change). The day count is
|
||||
computed client-side from this instant on every page load; it is NEVER hard-coded, so it
|
||||
stays correct as the date changes.
|
||||
|
||||
Fail-safe: the HTML carries the static sentence "Ends Monday 30 November 2026." with an empty
|
||||
span beside it, so with JavaScript off the deadline still reads correctly on its own. Once the
|
||||
end instant has passed the text switches to the past tense — it never keeps claiming time
|
||||
remains. Nothing here animates visibility. */
|
||||
(function () {
|
||||
var BF_END = new Date('2026-11-30T23:59:59-05:00');
|
||||
var DAY = 86400000;
|
||||
var nodes = document.querySelectorAll('[data-bf-days]');
|
||||
if (!nodes.length) return;
|
||||
|
||||
/* Whole calendar days in US/Eastern, so "days left" is a date difference and not a 24-hour
|
||||
window (the offer ends at the end of a day, not 28 x 24h from now). */
|
||||
function easternDayNumber(d) {
|
||||
var parts = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'America/New_York', year: 'numeric', month: '2-digit', day: '2-digit'
|
||||
}).format(d).split('-');
|
||||
return Date.UTC(parseInt(parts[0], 10), parseInt(parts[1], 10) - 1, parseInt(parts[2], 10)) / DAY;
|
||||
}
|
||||
|
||||
var daysLeft = easternDayNumber(BF_END) - easternDayNumber(new Date());
|
||||
var text;
|
||||
if (daysLeft > 1) {
|
||||
text = daysLeft + ' days left';
|
||||
} else if (daysLeft === 1) {
|
||||
text = '1 day left';
|
||||
} else if (daysLeft === 0) {
|
||||
text = 'last day today';
|
||||
} else {
|
||||
text = 'this offer has ended';
|
||||
}
|
||||
nodes.forEach(function (n) { n.textContent = text; });
|
||||
})();
|
||||
})();
|
||||
@@ -0,0 +1,137 @@
|
||||
/* bootcamp-availability.js — live remaining-seat count for the bootcamp cohort.
|
||||
*
|
||||
* Source of truth: the availability webhook (product 17 = Bootcamp Q1-2027).
|
||||
* Progressive enhancement, same spirit as buy.js — it only ever ADDS, and it can
|
||||
* never block the buy:
|
||||
*
|
||||
* fetch OK, seats > 0 -> fill the [data-bc-seats] line with "<n> of 6 seats available"
|
||||
* in the page's own language; Buy stays enabled.
|
||||
* fetch OK, seats == 0 -> say the cohort is full, point at the next one, and disable
|
||||
* the Buy buttons (we must not sell a full cohort).
|
||||
* anything else -> DO NOTHING. Timeout, network error, CORS, non-200 or an
|
||||
* unexpected payload leave the page exactly as it is: the static
|
||||
* cap text shows and the Buy buttons stay enabled. A
|
||||
* conversion-critical element must not fail closed.
|
||||
*
|
||||
* The count is live and authoritative, so it is never written into the HTML as a fixed
|
||||
* string — the [data-bc-seats] element ships empty and hidden.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var ENDPOINT = 'https://n8n.odoo4projects.com/webhook/ODOO4projects/available';
|
||||
var PRODUCT_ID = 17;
|
||||
var CAP = 6; /* the page's own cohort cap ("Limited to 6 participants") */
|
||||
var TIMEOUT_MS = 6000;
|
||||
|
||||
/* The page's own words and language. "seat" = seat / Platz / plaza, as used elsewhere
|
||||
on the same page ("A seat can be transferred" / "Ein Platz ist übertragbar" /
|
||||
"Una plaza se puede transferir"). */
|
||||
var TEXT = {
|
||||
en: {
|
||||
available: function (n) { return n + ' of ' + CAP + ' seats available'; },
|
||||
full: 'This cohort is full.',
|
||||
next: 'Talk to us about the next cohort',
|
||||
href: '/support.html#contact'
|
||||
},
|
||||
de: {
|
||||
available: function (n) { return n + ' von ' + CAP + ' Plätzen frei'; },
|
||||
full: 'Dieser Kurs ist ausgebucht.',
|
||||
next: 'Sprechen Sie mit uns über den nächsten Kurs',
|
||||
href: '/de/support.html#contact'
|
||||
},
|
||||
es: {
|
||||
available: function (n) { return n + ' de ' + CAP + ' plazas disponibles'; },
|
||||
full: 'Este grupo está completo.',
|
||||
next: 'Hable con nosotros sobre el próximo grupo',
|
||||
href: '/es/support.html#contact'
|
||||
}
|
||||
};
|
||||
|
||||
function lang() {
|
||||
var l = (document.documentElement.getAttribute('lang') || 'en').toLowerCase();
|
||||
if (l.indexOf('de') === 0) return 'de';
|
||||
if (l.indexOf('es') === 0) return 'es';
|
||||
return 'en';
|
||||
}
|
||||
|
||||
function renderAvailable(el, n, t) {
|
||||
el.textContent = '';
|
||||
var strong = document.createElement('strong');
|
||||
strong.textContent = t.available(n);
|
||||
el.appendChild(strong);
|
||||
el.hidden = false;
|
||||
}
|
||||
|
||||
function renderFull(el, t) {
|
||||
el.textContent = '';
|
||||
var strong = document.createElement('strong');
|
||||
strong.textContent = t.full;
|
||||
el.appendChild(strong);
|
||||
el.appendChild(document.createTextNode(' '));
|
||||
var a = document.createElement('a');
|
||||
a.href = t.href;
|
||||
a.textContent = t.next;
|
||||
el.appendChild(a);
|
||||
el.hidden = false;
|
||||
disableBuy();
|
||||
}
|
||||
|
||||
function disableBuy() {
|
||||
var buttons = document.querySelectorAll('form[action$="/shop/post_basket"] button[type="submit"]');
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
buttons[i].disabled = true;
|
||||
buttons[i].setAttribute('aria-disabled', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
/* Unwrap [{data:[...]}] or {data:[...]} and read product 17's qty_available.
|
||||
Returns a finite number >= 0, or null if the shape is not what we expect. */
|
||||
function seatsFrom(json) {
|
||||
var obj = json;
|
||||
if (Array.isArray(obj)) obj = obj[0];
|
||||
if (!obj || !Array.isArray(obj.data)) return null;
|
||||
for (var i = 0; i < obj.data.length; i++) {
|
||||
var row = obj.data[i];
|
||||
if (row && Number(row.id) === PRODUCT_ID) {
|
||||
var q = Number(row.qty_available);
|
||||
return (isFinite(q) && q >= 0) ? q : null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function run() {
|
||||
var el = document.querySelector('[data-bc-seats]');
|
||||
if (!el) return;
|
||||
if (!window.fetch || typeof AbortController === 'undefined') return; /* keep fallback */
|
||||
var t = TEXT[lang()];
|
||||
|
||||
var ctrl = new AbortController();
|
||||
var timer = setTimeout(function () { ctrl.abort(); }, TIMEOUT_MS);
|
||||
|
||||
fetch(ENDPOINT, {
|
||||
signal: ctrl.signal,
|
||||
headers: { 'Accept': 'application/json' },
|
||||
cache: 'no-store'
|
||||
})
|
||||
.then(function (r) {
|
||||
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||
return r.json();
|
||||
})
|
||||
.then(function (json) {
|
||||
var n = seatsFrom(json);
|
||||
if (n === null) return; /* unexpected payload -> keep fallback */
|
||||
if (n === 0) renderFull(el, t);
|
||||
else renderAvailable(el, n, t);
|
||||
})
|
||||
.catch(function () { /* keep fallback; Buy stays enabled */ })
|
||||
.then(function () { clearTimeout(timer); });
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', run);
|
||||
} else {
|
||||
run();
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,186 @@
|
||||
/* bootcamp-waitlist.js — page-local waiting-list form for the three bootcamp pages.
|
||||
*
|
||||
* The user's rule: "You want another timezone / language? Join the waiting list."
|
||||
* The form posts to the same n8n CRM webhook the site's other forms use, with the
|
||||
* site's own footer-message payload shape — area:'message', no `name` (that belongs to
|
||||
* the `area:'quote'` shape of the Custom Quote modal).
|
||||
*
|
||||
* This page does not load /script.js, so the UTM helpers are copied verbatim from it
|
||||
* (same as /static/black-friday.js does). If script.js's helpers change, change these.
|
||||
*
|
||||
* All copy — labels, placeholders, the "sending" label, success and error text — lives in
|
||||
* the page markup, in the page's own language. This file carries no strings.
|
||||
*
|
||||
* A 200 from the webhook means the workflow accepted the request, not that a CRM record
|
||||
* exists (the workflow answers before it runs) — same as the site's other forms.
|
||||
*/
|
||||
var ENDPOINT = 'https://n8n.odoo4projects.com/webhook/ODOO4projects/crm';
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/* ---- UTM tracking helpers (verbatim from /script.js) ---- */
|
||||
function getCookie(name) {
|
||||
var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
||||
return match ? decodeURIComponent(match[2]) : null;
|
||||
}
|
||||
|
||||
function setCookie(name, value, days) {
|
||||
var expires = '';
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = '; expires=' + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/; SameSite=Lax';
|
||||
}
|
||||
|
||||
function parseUTM() {
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
var utm = {};
|
||||
var keys = ['source', 'medium', 'campaign'];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var val = urlParams.get('utm_' + keys[i]);
|
||||
if (val) {
|
||||
utm[keys[i]] = val;
|
||||
setCookie('utm_' + keys[i], val, 90);
|
||||
}
|
||||
}
|
||||
return utm;
|
||||
}
|
||||
|
||||
function getStoredUTM() {
|
||||
var utm = {};
|
||||
var keys = ['source', 'medium', 'campaign'];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var val = getCookie('utm_' + keys[i]);
|
||||
if (val) utm[keys[i]] = val;
|
||||
}
|
||||
return utm;
|
||||
}
|
||||
|
||||
function injectUTM(data) {
|
||||
var stored = getStoredUTM();
|
||||
if (Object.keys(stored).length > 0) {
|
||||
data.utm_source = stored.source || null;
|
||||
data.utm_medium = stored.medium || null;
|
||||
data.utm_campaign = stored.campaign || null;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
window.UTM = { parse: parseUTM, getStored: getStoredUTM, inject: injectUTM };
|
||||
window.UTM.parse();
|
||||
|
||||
/* ---- Waiting list ---- */
|
||||
function run() {
|
||||
var form = document.getElementById('bcWaitlistForm');
|
||||
if (!form) return;
|
||||
var emailInput = document.getElementById('bcWaitlistEmail');
|
||||
var commentInput = document.getElementById('bcWaitlistComment');
|
||||
var submitBtn = form.querySelector('button[type="submit"]');
|
||||
var success = document.getElementById('bcWaitlistSuccess');
|
||||
var error = document.getElementById('bcWaitlistError');
|
||||
var label = submitBtn ? submitBtn.textContent : '';
|
||||
|
||||
/* Both fields are required, exactly as the footer form requires both. */
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var email = emailInput.value.trim();
|
||||
var comment = commentInput.value.trim();
|
||||
if (!email || !comment) return;
|
||||
|
||||
error.style.display = 'none';
|
||||
submitBtn.textContent = submitBtn.getAttribute('data-sending') || label;
|
||||
submitBtn.disabled = true;
|
||||
|
||||
fetch(ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(UTM.inject({
|
||||
email: email,
|
||||
requirements: comment,
|
||||
area: 'message'
|
||||
}))
|
||||
}).then(function (r) {
|
||||
if (!r.ok) throw new Error('bad status ' + r.status);
|
||||
if (window.plausible) window.plausible('Bootcamp Waitlist');
|
||||
form.style.display = 'none';
|
||||
success.style.display = 'block';
|
||||
}).catch(function () {
|
||||
submitBtn.textContent = label;
|
||||
submitBtn.disabled = false;
|
||||
error.style.display = 'block';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', run);
|
||||
} else {
|
||||
run();
|
||||
}
|
||||
})();
|
||||
|
||||
/* ---- Footer contact form ------------------------------------------------------------
|
||||
* These pages do NOT load /script.js, so its footer-form handler does not run here. This
|
||||
* mirrors /script.js's handler one-for-one — same webhook, same payload shape
|
||||
* ({ email, requirements, area:'message' } wrapped in UTM.inject), same success/failure
|
||||
* behaviour — but reads its two strings from the form's own data-ok / data-err attributes
|
||||
* so the message is in the page's language. Without it a submit would navigate the visitor
|
||||
* to the webhook's raw JSON reply.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function runFooter() {
|
||||
var form = document.getElementById('footerContactForm');
|
||||
if (!form) return;
|
||||
var emailInput = document.getElementById('footerContactEmail');
|
||||
var textInput = document.getElementById('footerContactText');
|
||||
var submitBtn = form.querySelector('.footer-send-btn');
|
||||
var status = document.getElementById('footerFormStatus');
|
||||
var okText = form.getAttribute('data-ok') || "Thanks! We'll get back to you shortly.";
|
||||
var errText = form.getAttribute('data-err') || 'Something went wrong. Please try again.';
|
||||
|
||||
function showStatus(message, isError) {
|
||||
status.textContent = message;
|
||||
status.classList.toggle('error', !!isError);
|
||||
status.classList.add('visible');
|
||||
}
|
||||
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var email = emailInput.value.trim();
|
||||
var text = textInput.value.trim();
|
||||
if (!email || !text) return;
|
||||
|
||||
submitBtn.disabled = true;
|
||||
status.classList.remove('visible');
|
||||
|
||||
fetch(ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(window.UTM.inject({
|
||||
email: email,
|
||||
requirements: text,
|
||||
area: 'message'
|
||||
}))
|
||||
}).then(function (r) {
|
||||
if (!r.ok) throw new Error('bad status ' + r.status);
|
||||
form.reset();
|
||||
submitBtn.disabled = false;
|
||||
showStatus(okText, false);
|
||||
}).catch(function () {
|
||||
submitBtn.disabled = false;
|
||||
showStatus(errText, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', runFooter);
|
||||
} else {
|
||||
runFooter();
|
||||
}
|
||||
})();
|
||||
@@ -1,7 +1,7 @@
|
||||
/* buy.js — page-local checkout helper (progressive enhancement).
|
||||
*
|
||||
* The checkout itself is a native <form method="post" target="_blank"> that posts
|
||||
* basket=[{"product_id":12,"qty":1}] + clear=1 to
|
||||
* basket=[{"product_id":17,"qty":1}] + clear=1 to
|
||||
* https://20.odoo4projects.com/shop/post_basket. With JavaScript off it still works.
|
||||
*
|
||||
* This file only adds attribution: on submit it appends the utm_* hidden inputs
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/* The freelancer PHOTO — one endpoint, one constant, one fetch.
|
||||
|
||||
The photo does NOT live in the profile payload any more. It used to ride there as
|
||||
inline base64 under the key `Image`; the webhook no longer sends that key, so the
|
||||
payload is small and the photo is fetched separately, per card, by record id.
|
||||
|
||||
ONE constant holds BOTH halves of the address: the route and the query-parameter
|
||||
name. Changing either is a one-line edit here, and both pages pick it up.
|
||||
|
||||
The parameter name is `id`, CONFIRMED by measurement against the live route:
|
||||
`?id=<n>` answers 200 with the photo for that record, while `/4`, `?profile_id=`,
|
||||
`?image_id=` and a missing id all fail.
|
||||
|
||||
THE ENDPOINT RETURNS JSON, NOT IMAGE BYTES. Measured on the live route:
|
||||
|
||||
GET …/odoo_experts_image?id=10 → 200 application/json
|
||||
body: {"Image":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ…"}
|
||||
|
||||
So a plain `<img src="…?id=N">` receives JSON, cannot decode it and fires `onerror`
|
||||
— the monogram. That is why the card FETCHES the route, reads `Image` and puts the
|
||||
DATA URI on an `<img>` only when it passes the `isImageSrc` allowlist. n8n sometimes
|
||||
answers an array instead of an object, so both shapes are accepted.
|
||||
|
||||
`load(id)` resolves to a usable image source, or `null` on ANY failure — a non-2xx, an
|
||||
empty `{}`, a missing/blank `Image`, a value that fails `isImageSrc`, or a request that
|
||||
does not answer in `timeoutMs`. A `null` answer means "show the monogram": the caller
|
||||
never sees a broken image. The decoded URI is cached by id (and a failure is remembered
|
||||
too), so a re-render can never re-fetch a photo already in memory.
|
||||
|
||||
THE TIMEOUT. A request that neither succeeds nor errors leaves the fallback unable to
|
||||
fire (measured live: an <img> pointed at this route sat `complete=false · naturalWidth=0`
|
||||
for 20 s). Each fetch is therefore bounded by `timeoutMs` (default 8000): an
|
||||
`AbortController` is aborted by a `setTimeout`, the abort rejects the fetch, and the
|
||||
rejection lands in the same catch that returns `null` — the monogram. The timer is
|
||||
cleared on every completion, so a fast answer never pays for the guard. `AbortController`
|
||||
is universal in the browsers this site targets (it already needs `fetch`, `Promise` and
|
||||
`IntersectionObserver`); if it were missing there is nothing to abort with, but the
|
||||
abort is what turns a hang into the fallback, so it is the one capability worth naming.
|
||||
|
||||
The route answers with `Access-Control-Allow-Origin` echoing the caller and
|
||||
`Cache-Control: public, max-age=3600`, so the browser may also serve a repeat from its
|
||||
own HTTP cache. */
|
||||
window.O4PExpertImage = {
|
||||
endpoint: "https://n8n.odoo4projects.com/webhook/ODOO4projects/odoo_experts_image",
|
||||
idParam: "id",
|
||||
// A photo request that hangs is a card with no photo AND no fallback: bound it.
|
||||
timeoutMs: 8000,
|
||||
|
||||
/* The ONLY allowlist for an image source in this codebase — `https://` or a
|
||||
`data:image/` URI. Both forms are what this endpoint has served across its life. */
|
||||
isImageSrc: function (v) {
|
||||
return typeof v === "string" &&
|
||||
(v.indexOf("https://") === 0 || v.indexOf("data:image/") === 0);
|
||||
},
|
||||
|
||||
url: function (id) {
|
||||
return this.endpoint + "?" + this.idParam + "=" + encodeURIComponent(id);
|
||||
},
|
||||
|
||||
// id -> decoded image source (or "" when the record has no usable photo)
|
||||
cache: Object.create(null),
|
||||
// id -> the in-flight Promise, so two observers of one id share ONE request
|
||||
inflight: Object.create(null),
|
||||
|
||||
/* Fetch the photo for `id`. Resolves to an image source, or null when there is none.
|
||||
Never rejects — a caller only has to check for a value. Every request is bounded by
|
||||
`timeoutMs`: on expiry the fetch is ABORTED (not merely abandoned) and the rejection
|
||||
resolves null, so a hung endpoint becomes the monogram instead of an empty box. */
|
||||
load: function (id) {
|
||||
var self = this;
|
||||
var key = String(id);
|
||||
if (key in self.cache) return Promise.resolve(self.cache[key] || null);
|
||||
if (self.inflight[key]) return self.inflight[key];
|
||||
|
||||
var ctrl = (typeof AbortController !== "undefined") ? new AbortController() : null;
|
||||
var timer = ctrl ? setTimeout(function () { ctrl.abort(); }, self.timeoutMs) : 0;
|
||||
|
||||
var req = fetch(self.url(key), {
|
||||
headers: { Accept: "application/json" },
|
||||
signal: ctrl ? ctrl.signal : undefined
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res.ok) throw new Error("HTTP " + res.status);
|
||||
return res.json();
|
||||
})
|
||||
.then(function (body) {
|
||||
// n8n sometimes wraps the record in an array — accept both shapes.
|
||||
var d = Array.isArray(body) ? body[0] : body;
|
||||
var img = d && d.Image;
|
||||
if (!self.isImageSrc(img)) throw new Error("no image");
|
||||
self.cache[key] = img;
|
||||
return img;
|
||||
})
|
||||
.catch(function () {
|
||||
// Every failure — non-2xx, no image, a decode-hostile value, or the timeout's
|
||||
// abort — is the monogram. Remember it, so a shared id under a re-render does not
|
||||
// ask the network twice.
|
||||
self.cache[key] = "";
|
||||
return null;
|
||||
})
|
||||
.then(function (out) {
|
||||
if (timer) clearTimeout(timer);
|
||||
delete self.inflight[key];
|
||||
return out;
|
||||
});
|
||||
|
||||
self.inflight[key] = req;
|
||||
return req;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
/* The ONE source of truth for the "skill profile" rule — the 15-point budget.
|
||||
Two forms render this rule: the directory application form
|
||||
(/odoo-community-developers/) and the private self-service edit form
|
||||
(/freelancer-edit/). Both take the legend, the directive and the wrong-total
|
||||
message from here, so the two cannot word the same rule differently again.
|
||||
Loaded before each page's own script. */
|
||||
(function () {
|
||||
var TOTAL = 15;
|
||||
window.O4PFocus = {
|
||||
TOTAL: TOTAL,
|
||||
MAX: 5,
|
||||
LEGEND: "Skill profile — 15 points to distribute",
|
||||
DIRECTIVE: "Distribute all 15 points across the five areas — they cannot all be 0.",
|
||||
/* The wrong-total message, naming the direction to move. "" when the sum is right. */
|
||||
message: function (sum) {
|
||||
if (sum === TOTAL) return "";
|
||||
if (sum === 0) return "You have 0 of " + TOTAL + " — place all " + TOTAL + " points.";
|
||||
if (sum > TOTAL) return "You have " + sum + " of " + TOTAL + " — remove " + (sum - TOTAL) + ".";
|
||||
return "You have " + sum + " of " + TOTAL + " — add " + (TOTAL - sum) + ".";
|
||||
}
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,22 @@
|
||||
# static/icons — the profile-link icon set
|
||||
|
||||
Four monochrome brand marks shown in the freelancer directory card's links row
|
||||
(`/odoo-community-developers/`): LinkedIn, GitHub, Upwork, Fiverr.
|
||||
|
||||
**Source:** [Simple Icons](https://simpleicons.org) v13 — one uniform set, so the four
|
||||
share one visual language by construction: the same 24 × 24 grid, the same internal
|
||||
padding, the same monochrome mass, single-path art. Nothing here is hand-drawn and
|
||||
nothing is fetched from a third party at runtime.
|
||||
|
||||
**How the page uses them.** The card inlines the same path data (see `LINK_ICONS` in the
|
||||
page's script and in `work/build-directory.py`), so the links row makes **zero requests**
|
||||
and each mark inherits the link's `currentColor`. These files are the self-hosted,
|
||||
drop-in copy of that set — identical geometry — for any host that prefers a file over an
|
||||
inline `<svg>`.
|
||||
|
||||
**Brand rule.** A brand mark is never redrawn and never restyled beyond a single
|
||||
monochrome fill. The one styling the page applies is `fill="currentColor"`.
|
||||
|
||||
The `role`/`aria-label` here are for standalone use; the card strips them and marks the
|
||||
inline SVG `aria-hidden="true" focusable="false"`, putting the accessible name on the
|
||||
link (`aria-label` + `title`, e.g. "GitHub profile").
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Fiverr"><path fill="currentColor" d="M23.004 15.588a.995.995 0 1 0 .002-1.99.995.995 0 0 0-.002 1.99zm-.996-3.705h-.85c-.546 0-.84.41-.84 1.092v2.466h-1.61v-3.558h-.684c-.547 0-.84.41-.84 1.092v2.466h-1.61v-4.874h1.61v.74c.264-.574.626-.74 1.163-.74h1.972v.74c.264-.574.625-.74 1.162-.74h.527v1.316zm-6.786 1.501h-3.359c.088.546.43.858 1.006.858.43 0 .732-.175.83-.487l1.425.4c-.351.848-1.22 1.364-2.255 1.364-1.748 0-2.549-1.355-2.549-2.515 0-1.14.703-2.505 2.45-2.505 1.856 0 2.471 1.384 2.471 2.408 0 .224-.01.37-.02.477zm-1.562-.945c-.04-.42-.342-.81-.889-.81-.508 0-.81.225-.908.81h1.797zM7.508 15.44h1.416l1.767-4.874h-1.62l-.86 2.837-.878-2.837H5.72l1.787 4.874zm-6.6 0H2.51v-3.558h1.524v3.558h1.591v-4.874H2.51v-.302c0-.332.235-.536.606-.536h.918V8.412H2.85c-1.162 0-1.943.712-1.943 1.755v.4H0v1.316h.908v3.558z"/></svg>
|
||||
|
After Width: | Height: | Size: 912 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="GitHub"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
|
||||
|
After Width: | Height: | Size: 842 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="LinkedIn"><path fill="currentColor" d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>
|
||||
|
After Width: | Height: | Size: 630 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Upwork"><path fill="currentColor" d="M18.561 13.158c-1.102 0-2.135-.467-3.074-1.227l.228-1.076.008-.042c.207-1.143.849-3.06 2.839-3.06 1.492 0 2.703 1.212 2.703 2.703-.001 1.489-1.212 2.702-2.704 2.702zm0-8.14c-2.539 0-4.51 1.649-5.31 4.366-1.22-1.834-2.148-4.036-2.687-5.892H7.828v7.112c-.002 1.406-1.141 2.546-2.547 2.548-1.405-.002-2.543-1.143-2.545-2.548V3.492H0v7.112c0 2.914 2.37 5.303 5.281 5.303 2.913 0 5.283-2.389 5.283-5.303v-1.19c.529 1.107 1.182 2.229 1.974 3.221l-1.673 7.873h2.797l1.213-5.71c1.063.679 2.285 1.109 3.686 1.109 3 0 5.439-2.452 5.439-5.45 0-3-2.439-5.439-5.439-5.439z"/></svg>
|
||||
|
After Width: | Height: | Size: 689 B |
@@ -0,0 +1,141 @@
|
||||
/* The ONE source of truth for photo uploads — limits, validation and downscale.
|
||||
Two forms call this: the directory application form (/odoo-community-developers/)
|
||||
and the private self-service edit form (/freelancer-edit/). The limits live here
|
||||
once, so the two cannot drift. Loaded before each page's own script.
|
||||
|
||||
Why this exists beyond page weight: re-encoding to a canvas DROPS EXIF entirely.
|
||||
A phone photo carries GPS coordinates, so an un-stripped portrait publishes the
|
||||
photographer's home location. Re-encoding is also a security step — a file whose
|
||||
declared type was spoofed fails to decode and is refused here.
|
||||
|
||||
NOTE: the <input accept> attribute is a picker HINT, never validation. Only
|
||||
validate() below decides, and it runs on the File object before any read. */
|
||||
(function () {
|
||||
var MAX_INPUT_BYTES = 8 * 1024 * 1024; // 8 MB — refuse before reading a byte
|
||||
var ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp"];
|
||||
var MAX_SIDE = 384; // longest side of the stored image, px
|
||||
var MAX_OUTPUT_BYTES = 80 * 1024; // 80 KB — the encoded JPEG target
|
||||
var QUALITY = 0.82; // starting JPEG quality
|
||||
var QUALITY_STEP = 0.05; // step down until the target is met
|
||||
var QUALITY_FLOOR = 0.4; // never go below this
|
||||
|
||||
function kb(bytes) { return Math.round(bytes / 1024); }
|
||||
function mb(bytes) { return (bytes / (1024 * 1024)).toFixed(1); }
|
||||
|
||||
/* Decide on the File's own metadata — no read happens here. */
|
||||
function validate(file) {
|
||||
if (!file) return { ok: false, reason: "No file was chosen." };
|
||||
if (ALLOWED_TYPES.indexOf(file.type) === -1) {
|
||||
return { ok: false, reason: "That file type is not allowed. Use a JPEG, PNG or WebP image." };
|
||||
}
|
||||
if (file.size > MAX_INPUT_BYTES) {
|
||||
return { ok: false, reason: "That photo is " + mb(file.size) + " MB. The limit is 8 MB — please choose a smaller one." };
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
function readAsDataUrl(file) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () { resolve(reader.result); };
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
function loadImage(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var img = new Image();
|
||||
img.onload = function () { resolve(img); };
|
||||
img.onerror = reject; // a spoofed "image/jpeg" that is not an image lands here
|
||||
img.src = url;
|
||||
});
|
||||
}
|
||||
|
||||
function byteLength(dataUrl) {
|
||||
return atob(dataUrl.slice(dataUrl.indexOf(",") + 1)).length;
|
||||
}
|
||||
|
||||
/* Read → centre-crop square → cap longest side → encode JPEG → step quality down
|
||||
until it fits. Resolves { dataUrl, width, height, bytes, quality }. */
|
||||
function downscale(file) {
|
||||
return readAsDataUrl(file).then(loadImage).then(function (img) {
|
||||
var w = img.naturalWidth, h = img.naturalHeight;
|
||||
var side = Math.min(w, h);
|
||||
var sx = (w - side) / 2, sy = (h - side) / 2;
|
||||
var out = Math.min(MAX_SIDE, side);
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = out;
|
||||
canvas.height = out;
|
||||
canvas.getContext("2d").drawImage(img, sx, sy, side, side, 0, 0, out, out);
|
||||
var quality = QUALITY;
|
||||
var dataUrl = canvas.toDataURL("image/jpeg", quality);
|
||||
var bytes = byteLength(dataUrl);
|
||||
while (bytes > MAX_OUTPUT_BYTES && quality > QUALITY_FLOOR) {
|
||||
quality = Math.max(QUALITY_FLOOR, quality - QUALITY_STEP);
|
||||
dataUrl = canvas.toDataURL("image/jpeg", quality);
|
||||
bytes = byteLength(dataUrl);
|
||||
}
|
||||
return { dataUrl: dataUrl, width: out, height: out, bytes: bytes, quality: quality };
|
||||
});
|
||||
}
|
||||
|
||||
/* The one honest line the person sees. No "optimised for the web" — only what we can show. */
|
||||
function resultLine(res) {
|
||||
return "Resized to " + res.width + " × " + res.height + ", " + kb(res.bytes) + " KB";
|
||||
}
|
||||
|
||||
/* Wire one file input to a preview <img> and a status line. onResult receives the
|
||||
downscaled data URL, or null when there is no (valid) file. Both forms use this,
|
||||
so the outcome shown is identical. */
|
||||
function wire(input, preview, result, onResult) {
|
||||
if (!input) return;
|
||||
function say(text, state) {
|
||||
if (!result) return;
|
||||
result.textContent = text || "";
|
||||
if (state) result.setAttribute("data-state", state);
|
||||
else result.removeAttribute("data-state");
|
||||
}
|
||||
input.addEventListener("change", function () {
|
||||
var file = input.files && input.files[0];
|
||||
if (!file) {
|
||||
if (preview) preview.hidden = true;
|
||||
say("", null);
|
||||
onResult(null);
|
||||
return;
|
||||
}
|
||||
var v = validate(file);
|
||||
if (!v.ok) {
|
||||
if (preview) preview.hidden = true;
|
||||
input.value = ""; // a refused file must never be submitted
|
||||
say(v.reason, "err");
|
||||
onResult(null);
|
||||
return;
|
||||
}
|
||||
say("Processing…", null);
|
||||
downscale(file).then(function (res) {
|
||||
if (preview) { preview.src = res.dataUrl; preview.hidden = false; }
|
||||
say(resultLine(res), "ok");
|
||||
onResult(res.dataUrl, res);
|
||||
}).catch(function () {
|
||||
if (preview) preview.hidden = true;
|
||||
input.value = "";
|
||||
say("That file could not be read as an image. Please choose a JPEG, PNG or WebP.", "err");
|
||||
onResult(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
window.O4PPhoto = {
|
||||
MAX_INPUT_BYTES: MAX_INPUT_BYTES,
|
||||
ALLOWED_TYPES: ALLOWED_TYPES,
|
||||
MAX_SIDE: MAX_SIDE,
|
||||
MAX_OUTPUT_BYTES: MAX_OUTPUT_BYTES,
|
||||
QUALITY: QUALITY,
|
||||
validate: validate,
|
||||
downscale: downscale,
|
||||
resultLine: resultLine,
|
||||
kb: kb,
|
||||
wire: wire
|
||||
};
|
||||
})();
|
||||
@@ -6,6 +6,19 @@
|
||||
========================================================= */
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
/* `hidden` must really hide — everywhere, not one element at a time. The UA's own
|
||||
`[hidden] { display: none }` is the weakest possible declaration: any page rule that
|
||||
sets `display` on the same element outranks it. A class rule (`.dir-pager`,
|
||||
`.dev-card`, `.hero-notice`) already beats it, and an id-based state selector such as
|
||||
`.js #directory[data-dir-state="ready"] #dirGrid > .dev-card` (two ids) beat the old
|
||||
per-element patch — so setting `el.hidden = true` set the attribute and the element
|
||||
stayed on screen (measured on /odoo-community-developers/: four cards visible, the
|
||||
count line reading "Showing 1 of 4"). This one rule, with `!important`, beats every
|
||||
class- or id-based `display`, so the attribute hides its element no matter which
|
||||
later rule sets `display`. It is the single mechanism for `[hidden]` site-wide; the
|
||||
per-element `[hidden]` rules are gone so nothing disagrees. */
|
||||
[hidden] { display: none !important; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, 'Segoe UI', sans-serif;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<link rel="stylesheet" href="style.css?v=061517baef" />
|
||||
<style>
|
||||
/* Language selector — the page's top row: the back-link stays left, the selector travels right.
|
||||
Cream canvas, so lang.js's own dark-brass active colour is the correct one (no override). */
|
||||
@@ -268,9 +268,16 @@
|
||||
.contact-form { padding: 1.25rem; }
|
||||
}
|
||||
</style>
|
||||
<script defer src="/static/lang.js"></script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="index.html">← Back to Home</a>
|
||||
@@ -286,6 +293,8 @@
|
||||
For the fastest help, please read our <strong>FAQ</strong> first — our support
|
||||
bot can assist with quick fixes like <strong>git pull</strong> or restarts — or
|
||||
simply send a <strong>ticket</strong> to our support team for further assistance.
|
||||
Urgent topics can be handled by the <strong>AI agent</strong> we offer, and email
|
||||
support answers within <strong>24 hours</strong>.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -321,7 +330,7 @@
|
||||
<!-- First Steps -->
|
||||
<div class="faq-panel active" id="panel-first-steps">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>My Odoo seems empty. What can I do with it?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -338,10 +347,12 @@
|
||||
<li><strong>Event company</strong>: Install Events and Website apps.</li>
|
||||
</ul>
|
||||
<p>No matter your business type, you can pick the apps that match your needs, and gradually build your Odoo system step by step.</p>
|
||||
<p>If you are at the very start — choosing a plan, deploying your instance, mapping your first domain — our guide on <a href="blog/posts/my-first-post.html">getting started with Odoo hosting</a> walks through it step by step.</p>
|
||||
<p>If the question you are asking is bigger than the apps — <em>what can I use Odoo for at all, and is it right for my kind of business?</em> — we have written that answer out properly, business type by business type: <a href="what-can-i-use-odoo-for/">what you can use Odoo for</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>How do I install a new app?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -351,7 +362,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>How do I add my email Server for sending messages from Odoo?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -361,7 +372,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>How do I change my login name or password?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -375,7 +386,7 @@
|
||||
<!-- Advanced Users -->
|
||||
<div class="faq-panel" id="panel-advanced">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Do I get SSH access to my service?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -384,7 +395,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>How do I configure my Backup frequency?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -393,7 +404,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>How long are Backups stored?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -402,7 +413,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>How do I route my domain to my Odoo?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -412,7 +423,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>How can I install Odoo Enterprise?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -425,16 +436,17 @@
|
||||
<!-- Trouble Shooting -->
|
||||
<div class="faq-panel" id="panel-trouble">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>After a git check in, my server does not come up again or shows an error 500</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
<div class="faq-answer">
|
||||
<p>If you've pushed a new module to the server and it prevents the service from starting, first revert your changes in Git and push the corrected version back to the server. Then open the support chat — you'll need your UUID (sent in the confirmation email). After you tell our chatbot to git pull and restart the server, you'll receive a confirmation email; once confirmed, we'll bring your Odoo instance back online.</p>
|
||||
<p>Before you check in a change like this, read <a href="/odoo-staging-environment/">test it safely first</a>: a staging environment is what stops a bad check-in taking your server down, and most small businesses do not need one.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Why does my domain show an "Unknown Certificate" or "Bad Gateway"?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -447,7 +459,7 @@
|
||||
<!-- Commercial -->
|
||||
<div class="faq-panel" id="panel-commercial">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Is the Odoo Enterprise License included?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -456,7 +468,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>How can I upgrade my service?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -469,7 +481,7 @@
|
||||
<!-- Bring your Database -->
|
||||
<div class="faq-panel" id="panel-migrate">
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>How can I migrate my Odoo database from another service provider?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -479,7 +491,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<button class="faq-question">
|
||||
<button class="faq-question plausible-event-name=FAQ">
|
||||
<span>Can I update my Odoo database from an older version, e.g., 14 → 19?</span>
|
||||
<span class="faq-icon"><i class="fas fa-chevron-down"></i></span>
|
||||
</button>
|
||||
@@ -577,6 +589,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -25,7 +25,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<link rel="stylesheet" href="style.css?v=061517baef" />
|
||||
<style>
|
||||
.legal-hero {
|
||||
padding: 4rem 0 2.5rem;
|
||||
@@ -103,8 +103,15 @@
|
||||
.legal-card { padding: 1.25rem; }
|
||||
}
|
||||
</style>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="blog-header">
|
||||
<a href="index.html">← Back to Home</a>
|
||||
@@ -124,7 +131,7 @@
|
||||
<div class="container">
|
||||
<div class="legal-card">
|
||||
<h2>Who we are</h2>
|
||||
<p>ODOO4projects LLC, 30 N Gould St, STE R, Sheridan, WY 82801, USA. Contact: <span class="contact-email">support@ODOO4projects.com</span></p>
|
||||
<p>ODOO4projects LLC, 30 N Gould St, STE R, Sheridan, WY 82801, USA. Contact: <span class="contact-email">support@odoo4projects.com</span></p>
|
||||
<p>These terms cover the hosting service we sell on this website.</p>
|
||||
</div>
|
||||
|
||||
@@ -147,17 +154,17 @@
|
||||
|
||||
<div class="legal-card">
|
||||
<h2>Price and payment</h2>
|
||||
<p>Plans are billed yearly, in advance, in US dollars, plus tax where it applies. Payment is taken by card through Stripe. The current prices are the ones on the pricing page.</p>
|
||||
<p>Plans are billed yearly, in advance, in US dollars, tax included — the price you see is the price you pay. Payment is taken by card through Stripe. The current prices are the ones on the pricing page.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-card">
|
||||
<h2>Cancelling</h2>
|
||||
<p>You can cancel at any time. Cancelling stops the next renewal. It does not refund the period you have already paid for. We make no refund promise beyond what is written here.</p>
|
||||
<p>You can cancel at any time. Cancelling stops the next renewal, and we refund the time you have not used — the part of the period you have paid for that is still ahead of you, pro rata against the period you paid for.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-card">
|
||||
<h2>Version upgrades and migrations</h2>
|
||||
<p>Ask our support team for a version upgrade. We migrate databases on the main Odoo releases 17, 18 and 19. We do not support patch releases such as 18.1.</p>
|
||||
<p>Updates and upgrades within your current Odoo version are included in your plan. Moving a database to a new major Odoo version is a migration: it is a separate service and is quoted separately, so ask our support team for a quote. Our migration service covers databases on the main Odoo releases 17, 18 and 19. New instances can run Odoo 20, the current release. We do not support patch releases such as 18.1.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-card">
|
||||
@@ -187,6 +194,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script defer src="/static/agent-odoo4projects/agent.js"></script>
|
||||
</main>
|
||||
<script defer src="/static/agent-odoo4projects/agent.js?v=c3bb0cee2b"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,957 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>What Can I Use Odoo For? What Odoo Does, and What It Costs</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Odoo runs stock, invoicing, CRM, website and projects in one place. What you can use Odoo for, what is free, and how to get it running in about five minutes."
|
||||
/>
|
||||
<link rel="canonical" href="https://odoo4projects.com/what-can-i-use-odoo-for/" />
|
||||
<meta property="og:title" content="What Can I Use Odoo For? What Odoo Does, and What It Costs" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Stock, invoicing, CRM, projects and a website in one system. What Odoo is used for, what it costs, and the shortest route to running it."
|
||||
/>
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/what-can-i-use-odoo-for/" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- "What Can I Use Odoo For?" guide page (page-scoped; additive).
|
||||
The block below is odoo-community-upgrade.html's page-scoped CSS, reused so
|
||||
this guide shares the site's top bar, band rhythm and FAQ treatment, plus the
|
||||
comparison-table block already in use on odoo-hosting-2027.html. One addition
|
||||
only: .wd-wrap, the prose column for the app table's surrounding copy. ---- */
|
||||
.oc-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Top bar (page-scoped: the site has no global header) */
|
||||
.cmp-topbar {
|
||||
background: var(--midnight-2);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.85rem 0;
|
||||
}
|
||||
.cmp-topbar .container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.cmp-brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
}
|
||||
.cmp-brand span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar-links {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
font-size: 0.82rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
.cmp-topbar-links a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar-links a:hover {
|
||||
color: var(--brass);
|
||||
}
|
||||
.cmp-topbar .lang-switch-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.45);
|
||||
}
|
||||
.cmp-topbar .lang-switch {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.cmp-topbar .lang-switch a:hover,
|
||||
.cmp-topbar .lang-switch a:focus-visible {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.cmp-topbar .lang-switch a[aria-current="true"] {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* Hero */
|
||||
.oc-hero {
|
||||
min-height: 0;
|
||||
padding: 3.5rem 0 3rem;
|
||||
}
|
||||
.oc-hero .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.oc-hero h1 span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.oc-hero .hero-sub {
|
||||
max-width: 760px;
|
||||
}
|
||||
.oc-hero-img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
opacity: 0.25;
|
||||
filter: brightness(1.15) saturate(1.1);
|
||||
}
|
||||
|
||||
/* Prose column */
|
||||
.oc-body {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.75;
|
||||
}
|
||||
.section-dark .oc-body {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.oc-body p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oc-body strong {
|
||||
color: var(--ink);
|
||||
}
|
||||
.section-dark .oc-body strong {
|
||||
color: #fff;
|
||||
}
|
||||
.section-dark .oc-body a {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
/* The one addition: the app table's lead-in and closing line keep the same
|
||||
column width as .oc-body, so the table and the prose line up. */
|
||||
.wd-wrap {
|
||||
max-width: 820px;
|
||||
margin: 0 auto;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.75;
|
||||
}
|
||||
.section-dark .wd-wrap {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
.wd-wrap p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Sub-sections (the business types) */
|
||||
.oc-sub {
|
||||
margin-top: 2.25rem;
|
||||
}
|
||||
.oc-sub h3 {
|
||||
color: var(--ink);
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
.oc-sub > p {
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.75;
|
||||
}
|
||||
.section-dark .oc-sub h3 {
|
||||
color: var(--cream);
|
||||
}
|
||||
.section-dark .oc-sub > p {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
|
||||
/* Numbered how-to-start list */
|
||||
.oc-steps {
|
||||
max-width: 820px;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
counter-reset: oc-step;
|
||||
}
|
||||
.oc-steps li {
|
||||
position: relative;
|
||||
counter-increment: oc-step;
|
||||
padding: 0 0 1.4rem 3.2rem;
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
line-height: 1.7;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.25);
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.oc-steps li::before {
|
||||
content: counter(oc-step);
|
||||
position: absolute;
|
||||
left: -1.05rem;
|
||||
top: -0.15rem;
|
||||
width: 2.1rem;
|
||||
height: 2.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1rem;
|
||||
color: var(--midnight);
|
||||
background: var(--brass);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.oc-steps li strong {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.oc-steps li em {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
.oc-steps li:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* App table (the same block odoo-hosting-2027.html uses) */
|
||||
.cmp-table-wrap {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--line-brass);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
margin: 1.5rem 0 1.5rem;
|
||||
}
|
||||
.cmp-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
min-width: 640px;
|
||||
}
|
||||
.cmp-table th,
|
||||
.cmp-table td {
|
||||
padding: 0.7rem 0.9rem;
|
||||
font-size: 0.85rem;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
border-bottom: 1px solid rgba(201, 162, 39, 0.1);
|
||||
}
|
||||
.cmp-table thead th {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.82rem;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--brass);
|
||||
background: rgba(13, 27, 46, 0.55);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
white-space: normal;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.cmp-table tbody th {
|
||||
font-family: Inter, sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 0.82rem;
|
||||
color: #fff;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
.cmp-table td {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.cmp-table tbody tr:hover td,
|
||||
.cmp-table tbody tr:hover th {
|
||||
background: rgba(201, 162, 39, 0.06);
|
||||
}
|
||||
.cmp-table tbody tr:last-child th,
|
||||
.cmp-table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* FAQ */
|
||||
.cmp-faq-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cmp-faq {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.4rem 1.25rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
transition: box-shadow 0.25s;
|
||||
}
|
||||
.cmp-faq[open],
|
||||
.cmp-faq:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
.cmp-faq summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.85rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.98rem;
|
||||
color: var(--midnight);
|
||||
}
|
||||
.cmp-faq summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.cmp-faq summary::after {
|
||||
content: "+";
|
||||
font-family: Inter, sans-serif;
|
||||
color: var(--brass);
|
||||
font-size: 1.15rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
.cmp-faq[open] summary::after {
|
||||
content: "\2212";
|
||||
}
|
||||
.cmp-faq summary:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.cmp-faq .cmp-a {
|
||||
font-size: 0.87rem;
|
||||
color: var(--ink-soft);
|
||||
line-height: 1.7;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.cmp-faq .cmp-a p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Focus states on every CTA */
|
||||
.btn:focus-visible,
|
||||
.cmp-topbar-links a:focus-visible {
|
||||
outline: 3px solid var(--brass-bright);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.cmp-faq-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.oc-hero {
|
||||
padding: 3rem 0 2.5rem;
|
||||
}
|
||||
.oc-steps li {
|
||||
padding-left: 2.6rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "WebPage",
|
||||
"@id": "https://odoo4projects.com/what-can-i-use-odoo-for/#webpage",
|
||||
"url": "https://odoo4projects.com/what-can-i-use-odoo-for/",
|
||||
"name": "What Can I Use Odoo For?",
|
||||
"description": "Odoo runs stock, invoicing, CRM, website and projects in one place. What you can use Odoo for, what is free, and how to get it running in about five minutes.",
|
||||
"inLanguage": "en-US",
|
||||
"isPartOf": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"breadcrumb": { "@id": "https://odoo4projects.com/what-can-i-use-odoo-for/#breadcrumb" },
|
||||
"mainEntity": { "@id": "https://odoo4projects.com/what-can-i-use-odoo-for/#article" }
|
||||
},
|
||||
{
|
||||
"@type": "Article",
|
||||
"@id": "https://odoo4projects.com/what-can-i-use-odoo-for/#article",
|
||||
"headline": "What Can I Use Odoo For? What Odoo Does, and What It Costs",
|
||||
"description": "Odoo runs stock, invoicing, CRM, website and projects in one place. What you can use Odoo for, what is free, and how to get it running in about five minutes.",
|
||||
"articleSection": [
|
||||
"What Odoo actually is",
|
||||
"What you can run on Odoo",
|
||||
"What Odoo is used for, by business type",
|
||||
"What Odoo is not for",
|
||||
"What it costs to use Odoo",
|
||||
"How to start using Odoo",
|
||||
"Frequently asked questions"
|
||||
],
|
||||
"inLanguage": "en-US",
|
||||
"datePublished": "2026-10-28",
|
||||
"dateModified": "2026-10-28",
|
||||
"author": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"publisher": { "@id": "https://odoo4projects.com/#organization" },
|
||||
"mainEntityOfPage": { "@id": "https://odoo4projects.com/what-can-i-use-odoo-for/#webpage" }
|
||||
},
|
||||
{
|
||||
"@type": "FAQPage",
|
||||
"@id": "https://odoo4projects.com/what-can-i-use-odoo-for/#faq",
|
||||
"isPartOf": { "@id": "https://odoo4projects.com/what-can-i-use-odoo-for/#webpage" },
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What is Odoo used for?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Odoo is used to run the parts of a business that produce paperwork and numbers: sales and quotes, customer invoices and supplier bills, stock and purchasing, manufacturing, projects and timesheets, the website and its orders, the till, and the employee records behind payroll. All of it works on one database, so stock, orders and accounts agree with each other instead of being reconciled at month end."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What can Odoo do?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "It holds stock by location, raises a supplier order when a reorder rule trips, turns a quote into a sales order and that order into an invoice, takes payment, reconciles the bank statement, and reports what the month looked like. It does the same job for manufacturing, for services billed by the hour, and for a shop with a till and a website. You install the apps that apply to you."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Can I use Odoo for free?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Yes. Odoo Community is free and open source, and you can install and run it yourself at no licence cost. What is not free is the running of it: a server or VPS, someone's hours on updates and backups, and the certificate. If you want Community without that work, hosting is a paid service, ours starting at $214 a year."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "How is Odoo free if it is also sold per user?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Two different editions. Community is open source and carries no licence and no per-user charge; Enterprise is the licensed edition, sold per user by Odoo S.A. Enterprise exists for the extra apps and official support, not because Community is crippled. Plenty of businesses run Community for years and never buy a licence."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Can I use Odoo for dropshipping?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Yes. Odoo has dropshipping built in as a purchase route: you enable the Dropshipping setting, mark the product so it can be sold and purchased, and set its vendor. A sales order then raises the supplier request for quotation automatically, and the supplier ships to your customer. Two things to know: a dropshipped product never enters your stock, so it does not appear in your stock valuation, and no custom module is needed for any of it."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Is Odoo easy to use?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Daily use is straightforward once someone has set it up: a sale, an invoice and a stock move are each a few clicks and Odoo's own screens are consistent between apps. Setting it up is the part that is not easy, and Odoo's own documentation is written for an administrator rather than for an owner. The practical split is that you learn the business screens in an afternoon and hand the configuration and the server to someone who does it for a living."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Can Odoo be used for project management?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Yes, and for many service businesses it is the reason they moved. The Project app gives you tasks on a board, deadlines, sub-tasks, customer-facing stages, and timesheets against each job, so the hours you spent become the invoice you send. If you already run projects in a separate tool, the question is whether you want the hours and the invoice in the same system."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Do I need a developer to run Odoo?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "No, not to run it. You need a developer if you are installing custom modules or writing your own, and you need somebody technical once, to set the system up properly. After that, ordinary use is a browser login: install apps, enter your products, raise invoices, look at reports. The developer question usually arrives with a custom module, not with day-to-day work."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "How long before it is useful?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "A day for the first app, with the owner's decisions on the chart of accounts and the products. A week of real use before it is genuinely running your month. An instance on our plans is live in about five minutes; the rest of the time goes on your own data and your own decisions."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "BreadcrumbList",
|
||||
"@id": "https://odoo4projects.com/what-can-i-use-odoo-for/#breadcrumb",
|
||||
"itemListElement": [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"name": "Home",
|
||||
"item": "https://odoo4projects.com/"
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "What Can I Use Odoo For?",
|
||||
"item": "https://odoo4projects.com/what-can-i-use-odoo-for/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="cmp-topbar">
|
||||
<div class="container">
|
||||
<a class="cmp-brand" href="/index.html">ODOO4<span>projects</span></a>
|
||||
<nav class="cmp-topbar-links" aria-label="Page links">
|
||||
<a href="/index.html#pricing">Plans & pricing</a>
|
||||
<a href="/support.html">Support</a>
|
||||
</nav>
|
||||
<div data-lang-switcher class="lang-switch-slot"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero: the question, answered in the first hundred words -->
|
||||
<main>
|
||||
<section class="hero oc-hero">
|
||||
<div class="hero-bg">
|
||||
<img
|
||||
class="oc-hero-img"
|
||||
src="/images/hero/boston.webp"
|
||||
alt="Boston at night — one of the six regions our servers run in"
|
||||
width="1920"
|
||||
height="768"
|
||||
fetchpriority="high"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="container">
|
||||
<p class="hero-kicker">USING ODOO</p>
|
||||
<h1>What Can I Use Odoo For?</h1>
|
||||
<p class="hero-sub">
|
||||
Odoo is business software you install a piece at a time. Stock, sales, invoicing, accounting,
|
||||
purchasing, manufacturing, projects, a website, a point of sale and HR are separate apps in one
|
||||
system, sharing one database. A shop uses it for stock and a till. A workshop uses it for quotes,
|
||||
jobs and supplier orders. A distributor uses it for orders, deliveries and invoices. An office uses
|
||||
it for timesheets and billing. Odoo Community is free and open source, so nobody is charged a
|
||||
licence for logging in.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What Odoo is -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">The plain definition</p>
|
||||
<h2 class="section-title">What Odoo actually is</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
Odoo is an ERP system: a set of applications that all read and write the same database. Odoo S.A.
|
||||
publishes two editions. Community is open source and free to run, and it is the edition we host.
|
||||
Enterprise is the licensed edition sold per user, with extra accounting reports, the Studio
|
||||
customisation tool and official support on top.
|
||||
</p>
|
||||
<p>
|
||||
When you install Odoo you get an empty system and an app library. Install Sales and Inventory and you
|
||||
have a shop. Add Purchase and a confirmed sales order can raise the supplier order for you. Add
|
||||
Manufacturing and those supplier orders become components of a work order. A customer, a product and
|
||||
an invoice each exist once, so the number the accountant sees is the number the warehouse sees.
|
||||
</p>
|
||||
<p>
|
||||
That is the whole idea, and it is why the answer to "what can I use Odoo for" is a list of apps rather
|
||||
than a list of features.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Apps -->
|
||||
<section class="section-dark" id="apps">
|
||||
<div class="container">
|
||||
<p class="section-kicker">A list of apps</p>
|
||||
<h2 class="section-title">What you can run on Odoo</h2>
|
||||
<div class="wd-wrap">
|
||||
<p>
|
||||
Each of these installs from the Apps menu inside your own instance, and you install the ones your
|
||||
business needs:
|
||||
</p>
|
||||
</div>
|
||||
<div class="cmp-table-wrap">
|
||||
<table class="cmp-table">
|
||||
<caption class="oc-sr-only">
|
||||
The ten Odoo applications this guide lists, and what each one is used for.
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">App</th>
|
||||
<th scope="col">What you use it for</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Invoicing and Accounting</th>
|
||||
<td>Customer invoices, supplier bills, bank reconciliation, VAT returns, payment reminders</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Sales</th>
|
||||
<td>Quotes, sales orders, price lists, order confirmations</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Inventory</th>
|
||||
<td>Stock on hand, warehouse locations, lot and serial numbers, barcode scanning, reorder rules</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Purchase</th>
|
||||
<td>Requests for quotation, supplier orders, vendor price lists</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">CRM</th>
|
||||
<td>Leads, a pipeline you can look at, and what happened to each one</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Point of Sale</th>
|
||||
<td>A till for a shop or a counter, cash and card, sales landing in the same stock and books</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Manufacturing</th>
|
||||
<td>Bills of materials, work orders, a shop-floor screen for the people making the thing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Projects and Timesheets</th>
|
||||
<td>Tasks on a board, hours logged against a job, invoices raised from those hours</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Website and eCommerce</th>
|
||||
<td>Pages, a product catalogue, orders from the web arriving as sales orders</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Employees and Time Off</th>
|
||||
<td>Who works here, holiday requests, the record behind the payroll</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="wd-wrap">
|
||||
<p>
|
||||
Ten entries is not the ceiling. Odoo's app library is much larger, and Odoo Community has no per-user
|
||||
licence, so adding an app for one person costs nothing extra to try.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- By business type -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Your kind of business</p>
|
||||
<h2 class="section-title">What Odoo is used for, by business type</h2>
|
||||
<div class="wd-wrap">
|
||||
<div class="oc-sub">
|
||||
<h3>Manufacturing</h3>
|
||||
<p>
|
||||
This is the case Odoo was built around. You write down what goes into a product (a bill of
|
||||
materials), and Odoo works out what the factory needs: components in stock, what has to be bought,
|
||||
which work order is next, and what each unit actually cost to make. When a customer orders twelve
|
||||
units, the stock reservation and the production order happen in the same movement.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oc-sub">
|
||||
<h3>Retail and trade</h3>
|
||||
<p>
|
||||
A counter till, stock by location, and purchasing that reacts to the shelf instead of to a feeling.
|
||||
When the last of a line sells, the reorder rule raises the supplier order. Shops selling online run
|
||||
the same catalogue through the website app, so a web order and a counter sale come out of the same
|
||||
stock figure.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oc-sub">
|
||||
<h3>Services and agencies</h3>
|
||||
<p>
|
||||
Quotes become projects, projects collect timesheets, and timesheets become invoices. The person who
|
||||
did the work is the person whose hours are on the invoice, which is the part most small firms
|
||||
rebuild by hand every month.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oc-sub">
|
||||
<h3>Construction and trades</h3>
|
||||
<p>
|
||||
A job is a project. Materials are purchased against that job, so you can see what a build has cost
|
||||
so far instead of guessing until the final invoice. Progress billing and purchase orders sit on the
|
||||
same project record.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oc-sub">
|
||||
<h3>Nonprofits and membership organisations</h3>
|
||||
<p>
|
||||
Contacts, events, invoicing and the website come from one place, and the accounts run on the same
|
||||
data your membership list does. Small teams like this usually have no one to spare for double
|
||||
entry, which is exactly where a single system earns its keep.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oc-sub">
|
||||
<h3>Accounting practices</h3>
|
||||
<p>
|
||||
Several clients' books are kept apart inside one Odoo database, each with its own journals and
|
||||
reports, and the reconciliation work is one screen per bank account. Practices that host Odoo for
|
||||
clients end up selling their clients' access to the same instance rather than maintaining a
|
||||
different tool per client.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oc-sub">
|
||||
<h3>Small business, starting out</h3>
|
||||
<p>
|
||||
Start with Invoicing and one other app. Most owners pick Inventory or Sales, get the real products
|
||||
and the real customers in, and add the next app the week it starts to hurt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What it is not for -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Where it stops</p>
|
||||
<h2 class="section-title">What Odoo is not for</h2>
|
||||
<div class="oc-body">
|
||||
<p>
|
||||
<strong>Odoo Online will not take custom code.</strong> Odoo's own hosted offering runs standard apps
|
||||
on databases without custom modules; that is how their own standard plan is described. If you know
|
||||
you need a custom module or a bespoke integration, that route is closed to you and Community or
|
||||
odoo.sh is where custom code lives. This is the one boundary that changes the answer to "can I use
|
||||
Odoo for this" from yes to no.
|
||||
</p>
|
||||
<p>
|
||||
<strong>It will not do your trade's specialist work.</strong> Odoo will not keep a dentist's clinical
|
||||
notes or produce a machinist's CAD drawings. It runs the business around that work: appointments,
|
||||
quotes, invoices, stock, purchasing, hours.
|
||||
</p>
|
||||
<p>
|
||||
<strong>It does not configure itself.</strong> A fresh Odoo arrives empty. Your chart of accounts,
|
||||
your tax rules, your warehouse layout and your price lists are decisions somebody has to make, and
|
||||
the first week on Odoo is mostly those decisions.
|
||||
</p>
|
||||
<p>
|
||||
<strong>It is not free of maintenance.</strong> Somebody has to run the server, take the backups,
|
||||
renew the certificate and move you to the next major version. If that somebody is you, you have
|
||||
bought a second job alongside the first one.
|
||||
</p>
|
||||
<p>
|
||||
<strong>And if your whole requirement is four invoices a month from a phone, it is more system than
|
||||
you need.</strong> That is a real answer, and we would rather give it here than after you have paid
|
||||
for a year.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What it costs -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Two costs, not one</p>
|
||||
<h2 class="section-title">What it costs to use Odoo</h2>
|
||||
<div class="oc-body">
|
||||
<p>There are two costs, and people usually only count one of them.</p>
|
||||
<p>
|
||||
<strong>The software.</strong> Odoo Community is free and open source: no licence, no charge per
|
||||
user. Odoo Enterprise is licensed per user by Odoo S.A., at prices Odoo sets and changes, so we do
|
||||
not print a figure for it here. If you bring your own Enterprise licence, you keep it and we host it
|
||||
on the same instance, with no migration.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Running it.</strong> Odoo's own cloud is a per-user subscription with hosting included, and
|
||||
it is the route that will not take custom modules. Running it yourself means a server or VPS bill
|
||||
plus your own hours on updates and backups. A managed service is a flat yearly price and the hours
|
||||
are somebody else's. What separates those routes is whose hours go into the updates and backups, and
|
||||
we have written the full comparison out on the
|
||||
<a href="/odoo-hosting-2027.html">Odoo hosting comparison page</a>.
|
||||
</p>
|
||||
<p>
|
||||
<strong>What we charge, since we publish it.</strong> Our managed Community plans start at
|
||||
<strong>$214 a year</strong> for Side Hustle, then <strong>$395</strong> for On the Rise and
|
||||
<strong>$595</strong> for Powerhouse, with Empire quoted per setup. There is no per-user licence on
|
||||
any of them and no setup fee, the instance is live in about five minutes, and the trial runs 30 days
|
||||
without a credit card. The
|
||||
<a href="/index.html#pricing">plans and prices are on the pricing page</a>.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Dropshipping changes none of this.</strong> It is a setting inside the Purchase app, not a
|
||||
paid add-on, so your licence position is the same as any other seller's. See the
|
||||
<a href="#can-i-use-odoo-for-dropshipping">dropshipping answer in the FAQ</a>.
|
||||
</p>
|
||||
<p>
|
||||
<strong>If you would rather learn it by doing it,</strong> the
|
||||
<a href="/odoo-erp-automation-bootcamp/">ODOO ERP Automation Bootcamp</a> is a ten-session live
|
||||
course at USD 595.00 with a year of hosted Odoo Community included, and the two-hour
|
||||
<a href="/odoo-n8n-masterclass/">ODOO x N8N Masterclass</a> is USD 120.00.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- How to start -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Five moves</p>
|
||||
<h2 class="section-title">How to start using Odoo</h2>
|
||||
<ol class="oc-steps">
|
||||
<li>
|
||||
<strong>Write down the five things that hurt, in your words.</strong> Not "we need inventory
|
||||
management" — <em>"we sold twelve pallets and the paperwork says nine."</em> The pain is the
|
||||
requirement.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Name what you are buying.</strong> Hours back per week, money that stopped leaking, one
|
||||
place to look. If you cannot say it in a sentence, you are not ready to buy software yet.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Put your real work in this week.</strong> Your actual customers and products, not a demo.
|
||||
Use it for a week before you decide anything else.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Add the next app when you reach its limit,</strong> not on a project plan. A system you use
|
||||
today beats one you will use properly in six months.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Hand off the boring parts on day one.</strong> Backups, certificates, upgrades, restarts. If
|
||||
you are the one fixing the server at 11pm, you bought a job rather than a system.
|
||||
</li>
|
||||
</ol>
|
||||
<div class="oc-body" style="margin-top: 2.25rem">
|
||||
<p>
|
||||
An ODOO4projects instance is live in about five minutes, on servers in one of six regions, with
|
||||
backups already running and support reachable in your own words when you get stuck. If something
|
||||
breaks once your data is in it, the
|
||||
<a href="/odoo-community-upgrade.html">upgrade and migration route is here</a>, and the place to
|
||||
ask is <a href="/support.html">support</a>.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Start with your own data:</strong>
|
||||
<a href="/index.html#pricing">see the plans</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section class="section-light" id="faq">
|
||||
<div class="container">
|
||||
<p class="section-kicker">Straight answers</p>
|
||||
<h2 class="section-title">Frequently asked questions</h2>
|
||||
<div class="cmp-faq-grid">
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">What is Odoo used for?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Odoo is used to run the parts of a business that produce paperwork and numbers: sales and quotes, customer invoices and supplier bills, stock and purchasing, manufacturing, projects and timesheets, the website and its orders, the till, and the employee records behind payroll. All of it works on one database, so stock, orders and accounts agree with each other instead of being reconciled at month end.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">What can Odoo do?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>It holds stock by location, raises a supplier order when a reorder rule trips, turns a quote into a sales order and that order into an invoice, takes payment, reconciles the bank statement, and reports what the month looked like. It does the same job for manufacturing, for services billed by the hour, and for a shop with a till and a website. You install the apps that apply to you.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Can I use Odoo for free?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Yes. Odoo Community is free and open source, and you can install and run it yourself at no licence cost. What is not free is the running of it: a server or VPS, someone's hours on updates and backups, and the certificate. If you want Community without that work, hosting is a paid service, ours starting at $214 a year.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">How is Odoo free if it is also sold per user?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Two different editions. Community is open source and carries no licence and no per-user charge; Enterprise is the licensed edition, sold per user by Odoo S.A. Enterprise exists for the extra apps and official support, not because Community is crippled. Plenty of businesses run Community for years and never buy a licence.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq" id="can-i-use-odoo-for-dropshipping">
|
||||
<summary class="plausible-event-name=FAQ">Can I use Odoo for dropshipping?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Yes. Odoo has dropshipping built in as a purchase route: you enable the Dropshipping setting, mark the product so it can be sold and purchased, and set its vendor. A sales order then raises the supplier request for quotation automatically, and the supplier ships to your customer. Two things to know: a dropshipped product never enters your stock, so it does not appear in your stock valuation, and no custom module is needed for any of it.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Is Odoo easy to use?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Daily use is straightforward once someone has set it up: a sale, an invoice and a stock move are each a few clicks and Odoo's own screens are consistent between apps. Setting it up is the part that is not easy, and Odoo's own documentation is written for an administrator rather than for an owner. The practical split is that you learn the business screens in an afternoon and hand the configuration and the server to someone who does it for a living.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Can Odoo be used for project management?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>Yes, and for many service businesses it is the reason they moved. The Project app gives you tasks on a board, deadlines, sub-tasks, customer-facing stages, and timesheets against each job, so the hours you spent become the invoice you send. If you already run projects in a separate tool, the question is whether you want the hours and the invoice in the same system.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">Do I need a developer to run Odoo?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>No, not to run it. You need a developer if you are installing custom modules or writing your own, and you need somebody technical once, to set the system up properly. After that, ordinary use is a browser login: install apps, enter your products, raise invoices, look at reports. The developer question usually arrives with a custom module, not with day-to-day work.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="cmp-faq">
|
||||
<summary class="plausible-event-name=FAQ">How long before it is useful?</summary>
|
||||
<div class="cmp-a">
|
||||
<p>A day for the first app, with the owner's decisions on the chart of accounts and the products. A week of real use before it is genuinely running your month. An instance on our plans is live in about five minutes; the rest of the time goes on your own data and your own decisions.</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer (copied from odoo-community-upgrade.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Useful Links</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Legal</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Partners</h4>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
<a href="https://OD8N.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OD8N</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>About us</h4>
|
||||
<p>We build smart, scalable business solutions by combining the <strong>stability</strong> of Odoo ERP with the <strong>power</strong> of AI Agents and N8N automations.</p>
|
||||
<p>From streamlined sales to global rollouts, our <strong>lean, eco-friendly</strong> approach helps businesses cut costs, boost efficiency, and grow without limits.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Follow us on</h4>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="oc-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
<label class="oc-sr-only" for="footerContactText">Your message</label>
|
||||
<textarea id="footerContactText" name="message" placeholder="Your message..." required></textarea>
|
||||
<button type="submit" class="footer-send-btn" aria-label="Send message"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M2 21l21-9L2 3v7l15 2-15 2z" /></svg></button>
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,793 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>ODOO Workshops and Classes: Live Courses from USD 120</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Two live courses with Oliver Arnold: the two-hour ODOO x N8N Masterclass at USD 120.00 and the ten-session ODOO ERP Automation Bootcamp at USD 595.00."
|
||||
/>
|
||||
<link rel="canonical" href="https://odoo4projects.com/workshops/" />
|
||||
<meta property="og:title" content="ODOO Workshops and Classes: Live Courses from USD 120" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Two live courses with Oliver Arnold: the two-hour ODOO x N8N Masterclass at USD 120.00 and the ten-session ODOO ERP Automation Bootcamp at USD 595.00."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://odoo4projects.com/workshops/" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<link rel="icon" href="/images/favicon.ico" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||
media="print"
|
||||
onload="this.media='all'"
|
||||
/>
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
||||
<style>
|
||||
/* ---- Workshops and Classes hub page (page-scoped; additive).
|
||||
The block below is the bootcamp page's page-scoped CSS, reused so the two
|
||||
course pages and this hub share one visual language, plus the comparison
|
||||
table block already in use on odoo-hosting-2027.html. Three additions only,
|
||||
each marked below. ---- */
|
||||
.bc-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Top bar (page-scoped: the site has no global header) */
|
||||
.bc-topbar {
|
||||
background: var(--midnight-2);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
padding: 0.85rem 0;
|
||||
}
|
||||
.bc-topbar .container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.bc-brand {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: 0.04em;
|
||||
color: #fff;
|
||||
}
|
||||
.bc-brand span {
|
||||
color: var(--brass);
|
||||
}
|
||||
.bc-topbar-links {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
.bc-topbar-links a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.bc-topbar-links a:hover {
|
||||
color: var(--brass);
|
||||
}
|
||||
/* Language selector — slides into the top-bar row, right of the links, behind a hairline brass divider.
|
||||
CI §1/§2: brass marks the active language; lang.js owns the markup. */
|
||||
.bc-topbar-links {
|
||||
margin-left: auto;
|
||||
}
|
||||
.bc-topbar .lang-switch-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid rgba(201, 162, 39, 0.45);
|
||||
}
|
||||
.bc-topbar .lang-switch {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.bc-topbar .lang-switch a:hover,
|
||||
.bc-topbar .lang-switch a:focus-visible {
|
||||
color: var(--brass-bright);
|
||||
}
|
||||
.bc-topbar .lang-switch a[aria-current="true"] {
|
||||
color: var(--brass);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* Hero — same treatment as the bootcamp page: our own London night aerial
|
||||
(CI §5) behind the header copy, with the identical two-zone scrim
|
||||
(.78 0%-88%, ramp 88%-94%, .25 94%-100%) so every text block in the copy
|
||||
zone keeps its contrast floor. */
|
||||
.bc-hero {
|
||||
min-height: 0;
|
||||
padding: 3.5rem 0 3rem;
|
||||
background-image: linear-gradient(90deg,
|
||||
rgba(13, 27, 46, 0.78) 0%,
|
||||
rgba(13, 27, 46, 0.78) 88%,
|
||||
rgba(13, 27, 46, 0.25) 94%,
|
||||
rgba(13, 27, 46, 0.25) 100%),
|
||||
url("/images/hero/bootcamp-hero-desktop-1920.webp");
|
||||
background-size: cover;
|
||||
background-position: 50% 25%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
/* The global .hero::after is a second, 50%-opacity midnight wash for the homepage's
|
||||
flat hero; with the photo + gradient scrim above the copy it only dulls the shot,
|
||||
so it is switched off on this page. One page-scoped rule, no global CSS touched. */
|
||||
.bc-hero::after {
|
||||
content: none;
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.bc-hero {
|
||||
background-image: linear-gradient(90deg,
|
||||
rgba(13, 27, 46, 0.78) 0%,
|
||||
rgba(13, 27, 46, 0.78) 88%,
|
||||
rgba(13, 27, 46, 0.25) 94%,
|
||||
rgba(13, 27, 46, 0.25) 100%),
|
||||
url("/images/hero/bootcamp-hero-mobile-900.webp");
|
||||
background-position: 50% 50%;
|
||||
}
|
||||
}
|
||||
/* wrapped hero-stat labels keep their tick on the first line */
|
||||
.bc-hero .hero-stat {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.bc-hero .hero-stat i {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.bc-lead {
|
||||
font-size: 1.05rem;
|
||||
color: rgba(23, 28, 38, 0.78);
|
||||
max-width: 720px;
|
||||
margin: 0 auto 1rem;
|
||||
line-height: 1.75;
|
||||
}
|
||||
.section-dark .bc-lead,
|
||||
.bc-lead.on-dark {
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
.bc-subline {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.15rem;
|
||||
color: var(--midnight);
|
||||
text-align: center;
|
||||
max-width: 720px;
|
||||
margin: 1.75rem auto 1.25rem;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.bc-action {
|
||||
text-align: center;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
/* Grids — auto-fit so no breakpoint is needed */
|
||||
.bc-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1rem;
|
||||
max-width: 1040px;
|
||||
}
|
||||
|
||||
/* Cards on midnight */
|
||||
.bc-cards {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1rem;
|
||||
max-width: 1040px;
|
||||
}
|
||||
.bc-cards li {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid var(--line-brass);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.35rem 1.4rem;
|
||||
/* the two course cards carry a CTA: flex column lets .bc-card-cta sit on the
|
||||
card floor so the two buttons line up across the grid row */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.bc-cards .bc-card-cta {
|
||||
margin-top: auto;
|
||||
padding-top: 0.8rem;
|
||||
}
|
||||
.bc-cards h3 {
|
||||
font-size: 1rem;
|
||||
color: #fff;
|
||||
margin-bottom: 0.45rem;
|
||||
}
|
||||
.bc-cards p {
|
||||
font-size: 0.86rem;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
line-height: 1.65;
|
||||
margin: 0;
|
||||
}
|
||||
/* ADDITION 1 — the bootcamp's card carries a single paragraph; the course cards
|
||||
here carry price, promise, format and a button. One spacing rule, no new look. */
|
||||
.bc-cards li > * + * {
|
||||
margin-top: 0.7rem;
|
||||
}
|
||||
.bc-cards p.bc-card-price {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.05rem;
|
||||
color: var(--brass);
|
||||
}
|
||||
.bc-cards .bc-card-format {
|
||||
font-size: 0.78rem;
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
.bc-note {
|
||||
max-width: 720px;
|
||||
margin: 1.5rem auto 0;
|
||||
font-size: 0.86rem;
|
||||
color: rgba(23, 28, 38, 0.78);
|
||||
line-height: 1.65;
|
||||
}
|
||||
.bc-note.on-dark {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
.bc-note strong {
|
||||
color: var(--midnight);
|
||||
}
|
||||
.bc-note.on-dark strong {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Pull quote (hero-adjacent, the old page's treatment) */
|
||||
.bc-quote {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.55;
|
||||
color: var(--midnight);
|
||||
text-align: center;
|
||||
max-width: 760px;
|
||||
margin: 0 auto 0.75rem;
|
||||
}
|
||||
.bc-quote-attr {
|
||||
font-family: Inter, sans-serif;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.15em;
|
||||
text-transform: uppercase;
|
||||
/* midnight, not brass-deep: brass-deep on cream measures 4.2:1 and fails AA
|
||||
at this size (detector finding, 2026-10-28) */
|
||||
color: var(--midnight);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Related links */
|
||||
.bc-related {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 2rem auto 0;
|
||||
max-width: 720px;
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.bc-related li {
|
||||
position: relative;
|
||||
padding-left: 1.4rem;
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
.bc-related li::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0.25rem;
|
||||
top: 0.55rem;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--brass);
|
||||
}
|
||||
.bc-related a {
|
||||
color: var(--midnight);
|
||||
text-decoration: underline;
|
||||
text-decoration-color: var(--brass);
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
.bc-related a:hover {
|
||||
text-decoration-color: var(--brass-deep);
|
||||
text-decoration-thickness: 2px;
|
||||
}
|
||||
|
||||
/* FAQ (native details/summary — no JS) */
|
||||
.bc-faq-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
align-items: start;
|
||||
}
|
||||
.bc-faq {
|
||||
background: var(--ivory);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.4rem 1.25rem;
|
||||
box-shadow: var(--shadow-rest);
|
||||
transition: box-shadow 0.25s;
|
||||
}
|
||||
.bc-faq[open],
|
||||
.bc-faq:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
}
|
||||
.bc-faq summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
padding: 0.85rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.98rem;
|
||||
color: var(--midnight);
|
||||
}
|
||||
.bc-faq summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.bc-faq summary::after {
|
||||
content: "+";
|
||||
font-family: Inter, sans-serif;
|
||||
color: var(--brass);
|
||||
font-size: 1.15rem;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.bc-faq[open] summary::after {
|
||||
content: "\2212";
|
||||
}
|
||||
.bc-faq summary:focus-visible {
|
||||
outline: 2px solid var(--brass);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.bc-faq .bc-a {
|
||||
font-size: 0.87rem;
|
||||
color: rgba(23, 28, 38, 0.78);
|
||||
line-height: 1.7;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.bc-faq .bc-a p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* ADDITION 2 — comparison table, copied verbatim from odoo-hosting-2027.html
|
||||
(same component, same dark palette, no new look). */
|
||||
.cmp-table-wrap {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--line-brass);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
}
|
||||
.cmp-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
min-width: 860px;
|
||||
}
|
||||
.cmp-table th,
|
||||
.cmp-table td {
|
||||
padding: 0.7rem 0.9rem;
|
||||
font-size: 0.85rem;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
border-bottom: 1px solid rgba(201, 162, 39, 0.1);
|
||||
}
|
||||
.cmp-table thead th {
|
||||
font-family: Marcellus, Georgia, serif;
|
||||
font-size: 0.82rem;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--brass);
|
||||
background: rgba(13, 27, 46, 0.55);
|
||||
border-bottom: 1px solid var(--line-brass);
|
||||
white-space: normal;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.cmp-table tbody th {
|
||||
font-family: Inter, sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 0.82rem;
|
||||
color: #fff;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
.cmp-table td {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.cmp-table tbody tr:hover td,
|
||||
.cmp-table tbody tr:hover th {
|
||||
background: rgba(201, 162, 39, 0.06);
|
||||
}
|
||||
.cmp-table tbody tr:last-child th,
|
||||
.cmp-table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
.cmp-table a {
|
||||
color: var(--brass-bright);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.bc-faq-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* ADDITION 3 — focus states for the two new interactive elements on this page
|
||||
(the anchor CTA and the card buttons); the bootcamp's two rules unchanged. */
|
||||
.btn:focus-visible,
|
||||
.bc-topbar-links a:focus-visible,
|
||||
.bc-related a:focus-visible,
|
||||
.cmp-table a:focus-visible {
|
||||
outline: 3px solid var(--brass-bright);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.btn-brass:focus-visible {
|
||||
outline-color: #fff;
|
||||
}
|
||||
</style>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ItemList",
|
||||
"name": "ODOO4projects workshops and classes",
|
||||
"url": "https://odoo4projects.com/workshops/",
|
||||
"itemListElement": [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"item": {
|
||||
"@type": "Course",
|
||||
"name": "ODOO × N8N Masterclass",
|
||||
"url": "https://odoo4projects.com/odoo-n8n-masterclass/",
|
||||
"provider": { "@type": "Organization", "name": "ODOO4projects", "url": "https://odoo4projects.com/" },
|
||||
"instructor": { "@type": "Person", "name": "Oliver Arnold", "jobTitle": "Technical Lead" },
|
||||
"inLanguage": "en",
|
||||
"offers": { "@type": "Offer", "price": "120.00", "priceCurrency": "USD", "category": "Paid" },
|
||||
"hasCourseInstance": { "@type": "CourseInstance", "courseMode": "online", "courseWorkload": "PT2H" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"item": {
|
||||
"@type": "Course",
|
||||
"name": "ODOO ERP Automation Bootcamp",
|
||||
"url": "https://odoo4projects.com/odoo-erp-automation-bootcamp/",
|
||||
"provider": { "@type": "Organization", "name": "ODOO4projects", "url": "https://odoo4projects.com/" },
|
||||
"instructor": { "@type": "Person", "name": "Oliver Arnold", "jobTitle": "Technical Lead" },
|
||||
"inLanguage": "en",
|
||||
"offers": { "@type": "Offer", "price": "595.00", "priceCurrency": "USD", "category": "Paid" },
|
||||
"hasCourseInstance": { "@type": "CourseInstance", "courseMode": "online", "courseWorkload": "PT10H" }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<!-- Privacy-friendly analytics by Plausible -->
|
||||
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
||||
<script>
|
||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||
plausible.init()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
||||
<div class="bc-topbar">
|
||||
<div class="container">
|
||||
<a class="bc-brand" href="/">ODOO4<span>projects</span></a>
|
||||
<nav class="bc-topbar-links" aria-label="Page links">
|
||||
<a href="/index.html#pricing">Plans & pricing</a>
|
||||
<a href="/odoo-erp-automation-bootcamp/">Bootcamp</a>
|
||||
<a href="/support.html">Support</a>
|
||||
</nav>
|
||||
<div data-lang-switcher class="lang-switch-slot"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<main>
|
||||
<section class="hero bc-hero">
|
||||
<div class="container">
|
||||
<p class="hero-kicker">TWO LIVE COURSES · ONLINE · OLIVER ARNOLD · ENGLISH</p>
|
||||
<h1>Workshops and Classes</h1>
|
||||
<p class="hero-sub">
|
||||
Two live courses, one instructor, and a working system at the end of both. You work on real data
|
||||
with the person who runs this platform, and you leave able to do the thing the course is named
|
||||
after.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a class="btn btn-brass btn-lg" href="#our-workshops">See the two courses</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Pull quote (kept verbatim, attributed) -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<p class="bc-quote">
|
||||
“You need to learn your skills from people who use them on a daily basis!”
|
||||
“That is what I teach my kids and that is how we organize our workshops.”
|
||||
</p>
|
||||
<p class="bc-quote-attr">— Oliver Arnold, Technical Lead, ODOO4projects</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Our Workshops -->
|
||||
<section class="section-dark" id="our-workshops">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Our Workshops</h2>
|
||||
<p class="bc-lead">
|
||||
Two courses. Both live, both online, both taught by Oliver Arnold, and both end with something
|
||||
running in front of you rather than notes to file away. Pick the one that matches where your
|
||||
business is today.
|
||||
</p>
|
||||
<ul class="bc-cards">
|
||||
<li>
|
||||
<h3>ODOO × N8N Masterclass</h3>
|
||||
<p class="bc-card-price">USD 120.00 · 2 hours</p>
|
||||
<p>You leave able to make Odoo start its own jobs: <a href="/blog/posts/howto-ai-automation.html">an automated action fires on a business event, calls an n8n webhook</a>, and n8n carries the work forward while you are somewhere else.</p>
|
||||
<p class="bc-card-format">Live webinar with a Q&A at the end · Online · English</p>
|
||||
<p class="bc-card-cta"><a class="btn btn-brass" href="/odoo-n8n-masterclass/">More Info</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<h3>ODOO ERP Automation Bootcamp</h3>
|
||||
<p class="bc-card-price">USD 595.00 · 10 live sessions, 1 hour each</p>
|
||||
<p>You leave with a working ERP for your own company: your products, your customers, your quotes, your invoices and your stock in one system you can keep running yourself.</p>
|
||||
<p class="bc-card-format">Live and online, every Thursday 18:00–19:00 Central Time · One year of hosted Odoo Community Edition included · Limited to 6 participants · English</p>
|
||||
<p class="bc-card-cta"><a class="btn btn-brass" href="/odoo-erp-automation-bootcamp/">More Info</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Which one is yours -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Which one is yours</h2>
|
||||
<p class="bc-lead">
|
||||
The two courses answer two different problems, and the price difference is the honest measure of
|
||||
how much work is in front of you.
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
<strong>If Odoo already runs your business.</strong> Take the masterclass if Odoo is already
|
||||
running your business and the gap is between the systems. You know what workflows and automated
|
||||
actions are and where they live in the interface, and you are comfortable enough with code to
|
||||
read a payload. Two hours later the automation you have been doing by hand is running without
|
||||
you.
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
<strong>If you do not have a system yet.</strong> Take the bootcamp if the system is the thing
|
||||
you do not have. You run the business, the stock and the invoices, and most of it lives in a
|
||||
spreadsheet and one person's memory. No ERP knowledge and no coding are assumed, because the ten
|
||||
sessions are about your business running, not about the software under it.
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
<strong>The honest limit.</strong> If you have never opened Odoo, or an API is still a vague word
|
||||
to you, start with the
|
||||
<a href="/odoo-erp-automation-bootcamp/">bootcamp</a>. The masterclass assumes you are already
|
||||
past that line.
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
If you want n8n but not the technical depth, lesson 9 of the bootcamp is n8n and AI for your
|
||||
business, built for the owner rather than the developer.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- How our sessions work -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">How our sessions work</h2>
|
||||
<ul class="bc-cards">
|
||||
<li>
|
||||
<h3>Live and online.</h3>
|
||||
<p>Everything runs in your browser, on the computer you already have, with nothing to install on it.</p>
|
||||
</li>
|
||||
<li>
|
||||
<h3>One instructor.</h3>
|
||||
<p>Oliver Arnold, Technical Lead at ODOO4projects, teaches every session of both courses. You get the same person in week ten that you met in week one.</p>
|
||||
</li>
|
||||
<li>
|
||||
<h3>English, with your questions answered in the room.</h3>
|
||||
<p>The masterclass ends in a Q&A; the bootcamp's last session is an open workshop where we fix whatever is still broken in your setup.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="bc-note on-dark">
|
||||
<strong>On n8n, in plain words:</strong> n8n is a third-party tool, used on n8n's own free plan.
|
||||
The free plan is not part of either price and is not included.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Your instructor -->
|
||||
<section class="section-light">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Your instructor</h2>
|
||||
<p class="bc-lead">
|
||||
<strong>Oliver Arnold, Technical Lead at ODOO4projects.</strong>
|
||||
</p>
|
||||
<p class="bc-lead">
|
||||
Oliver has spent more than 25 years building software that has to keep working, and he is the lead
|
||||
architect of the platform these courses run on. He teaches by putting the real system in front of
|
||||
you and fixing the real problem with you, which is the whole reason the courses are live instead
|
||||
of recorded.
|
||||
</p>
|
||||
<p class="bc-lead">He is the only instructor on both courses.</p>
|
||||
<ul class="bc-related">
|
||||
<li><a href="/odoo-n8n-masterclass/">The two-hour ODOO × N8N Masterclass</a></li>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">The ten-session ODOO ERP Automation Bootcamp</a></li>
|
||||
<li><a href="/support.html#contact">Questions before you book? Talk to us first</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Questions people ask first</h2>
|
||||
<div class="bc-faq-grid">
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">Which one should I take?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Take the masterclass if Odoo already runs your business and you want Odoo and n8n working together. Take the bootcamp if you do not have a system yet and want to build one. If you have never opened Odoo, the bootcamp comes first.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">Do I need technical skills?</summary>
|
||||
<div class="bc-a">
|
||||
<p>For the bootcamp, no. The sessions assume no ERP knowledge and no coding. For the masterclass, two things: you already run Odoo and know what workflows and automated actions are, and you know what an API is and how one gets called. You do not need to be a developer.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">What do I need installed?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Nothing. A computer and a browser. The masterclass hands you a free Odoo trial system and you use n8n on n8n's own free plan; the bootcamp runs on your own hosted system from the first session.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">What language are the courses in?</summary>
|
||||
<div class="bc-a">
|
||||
<p>English.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="bc-faq">
|
||||
<summary class="plausible-event-name=FAQ">What is the difference in length?</summary>
|
||||
<div class="bc-a">
|
||||
<p>Two hours, once, for the masterclass. Ten sessions of one hour across three months for the bootcamp, ten hours of teaching in total.</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Both courses, side by side -->
|
||||
<section class="section-dark">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Both courses, side by side</h2>
|
||||
<div class="cmp-table-wrap">
|
||||
<table class="cmp-table">
|
||||
<caption class="bc-sr-only">
|
||||
The two live courses compared on price, length, format, class size, prerequisites and what is included.
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"> </th>
|
||||
<th scope="col">ODOO × N8N Masterclass</th>
|
||||
<th scope="col">ODOO ERP Automation Bootcamp</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Price</th>
|
||||
<td>USD 120.00</td>
|
||||
<td>USD 595.00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Length</th>
|
||||
<td>2 hours</td>
|
||||
<td>10 sessions × 1 hour (10 hours)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Format</th>
|
||||
<td>Live webinar with Q&A</td>
|
||||
<td>Live and online, Thursdays 18:00–19:00 Central Time</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Class size</th>
|
||||
<td>—</td>
|
||||
<td>Limited to 6 participants</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Prerequisites</th>
|
||||
<td>Basic Odoo, basic programming</td>
|
||||
<td>None</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Included</th>
|
||||
<td>2 live hours, Q&A, free Odoo trial system, certificate</td>
|
||||
<td>10 live sessions, one year of hosted Odoo CE, alumni chat, setup review</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">More info</th>
|
||||
<td><a href="/odoo-n8n-masterclass/">/odoo-n8n-masterclass/</a></td>
|
||||
<td><a href="/odoo-erp-automation-bootcamp/">/odoo-erp-automation-bootcamp/</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||
carries no external icon dependency) -->
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="fgrid">
|
||||
<div>
|
||||
<h4>Useful Links</h4>
|
||||
<ul>
|
||||
<li><a href="/odoo-erp-automation-bootcamp/">ODOO Bootcamp</a></li>
|
||||
<li><a href="/odoo-hosting-2027.html">ODOO Hosting in 2027</a></li>
|
||||
<li><a href="/odoo-community-developers/">Odoo Freelancer Directory</a></li>
|
||||
<li><a href="/support.html">Support</a></li>
|
||||
<li><a href="/legal.html">Legal</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Partners</h4>
|
||||
<div class="partner-list">
|
||||
<a href="https://oc-guy.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OC Guy</a>
|
||||
<a href="https://oca-py.org" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OCA Paraguay</a>
|
||||
<a href="https://OD8N.com" target="_blank" rel="noopener" class="partner-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#c9a227" stroke-width="2" aria-hidden="true"><path d="M20 7h-9M14 17H5M20 7l-4-4M20 7l-4 4M4 17l4 4M4 17l4-4" /></svg> OD8N</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcol-desc">
|
||||
<h4>About us</h4>
|
||||
<p>We build smart, scalable business solutions by combining the <strong>stability</strong> of Odoo ERP with the <strong>power</strong> of AI Agents and N8N automations.</p>
|
||||
<p>From streamlined sales to global rollouts, our <strong>lean, eco-friendly</strong> approach helps businesses cut costs, boost efficiency, and grow without limits.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Follow us on</h4>
|
||||
<div class="social">
|
||||
<a href="https://www.linkedin.com/company/odoo4projects/" target="_blank" aria-label="LinkedIn"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-.95 1.83-1.95 3.76-1.95 4.02 0 4.76 2.5 4.76 5.75V21h-4v-5.5c0-1.31-.02-3-1.9-3-1.9 0-2.19 1.42-2.19 2.9V21H9z" /></svg></a>
|
||||
<a href="https://www.youtube.com/@ODOO4projects" target="_blank" aria-label="YouTube"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M23 12s0-3.2-.41-4.73a2.5 2.5 0 0 0-1.76-1.77C19.3 5.1 12 5.1 12 5.1s-7.3 0-8.83.4A2.5 2.5 0 0 0 1.4 7.27C1 8.8 1 12 1 12s0 3.2.41 4.73a2.5 2.5 0 0 0 1.76 1.77c1.53.4 8.83.4 8.83.4s7.3 0 8.83-.4a2.5 2.5 0 0 0 1.76-1.77C23 15.2 23 12 23 12zM9.75 15.02V8.98L15.5 12z" /></svg></a>
|
||||
</div>
|
||||
<form class="footer-contact-form" id="footerContactForm" action="mailto:support@odoo4projects.com" method="post" enctype="text/plain">
|
||||
<label class="bc-sr-only" for="footerContactEmail">Your email address</label>
|
||||
<input type="email" id="footerContactEmail" name="email" placeholder="Your email address" required />
|
||||
<div class="footer-textarea-wrap">
|
||||
<label class="bc-sr-only" for="footerContactText">Your message</label>
|
||||
<textarea id="footerContactText" name="message" placeholder="Your message..." required></textarea>
|
||||
<button type="submit" class="footer-send-btn" aria-label="Send message"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M2 21l21-9L2 3v7l15 2-15 2z" /></svg></button>
|
||||
</div>
|
||||
<div class="footer-form-status" id="footerFormStatus" role="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script defer src="/static/lang.js?v=3ec49a7e62"></script>
|
||||
</body>
|
||||
</html>
|
||||