feat(tncsc_deployment): migrate real tncsc.com content into the website pages

Replaces the Phase 7 "content to be finalized" placeholder pages with
TNCSC's actual site content (captured 2026-08-20), verified against a
live Odoo container on a dedicated fresh database (tncsc_site):

- Home, About, About/Tamil Nadu, About/Board of Directors (12 real
  members), Membership hub, Membership Benefits, Tamil Class, and
  Contact pages, with nav restructured to match tncsc.com's real
  structure (About and Membership as dropdowns).
- Real images downloaded from tncsc.com and self-hosted under
  static/src/img/ instead of hotlinking the WordPress site.
- Home's "Upcoming Events" and the membership pricing tables are wired
  to live event.event / community.membership.tier records instead of
  being static copies; Tamil Class links to the real /school/register
  flow. One real event seeded (Summer Picnic 2026).
- Deliberately not reproduced: tncsc.com's own Sponsors page and Contact
  phone number are unmigrated WordPress theme demo placeholders on the
  live site itself (generic client-01..09 logos, a non-Canadian demo
  number) - confirmed by inspection, not assumed. Contact page uses the
  real, verified email and social links instead.
- post_init_hook now also fixes two Odoo website Copy-On-Write gotchas
  that silently prevented the new homepage and nav dropdowns from
  rendering at all (auto-forked per-website duplicates winning over
  this module's records) - see HANDOFF.md for the full explanation.
This commit is contained in:
metatroncubeswdev 2026-08-20 12:32:59 -04:00
parent 8dd97dec9b
commit 24be6360e2
38 changed files with 706 additions and 48 deletions

View File

@ -16,7 +16,7 @@ file is the "where things actually stand" companion to it.
| 4 | `community_classifieds` + `community_benefits` | ✅ Done, committed | | 4 | `community_classifieds` + `community_benefits` | ✅ Done, committed |
| 5 | `community_interac` (Interac e-Transfer payment provider) | ✅ Done, committed | | 5 | `community_interac` (Interac e-Transfer payment provider) | ✅ Done, committed |
| 6 | `community_theme_base` + `community_portal` | ✅ Done, committed | | 6 | `community_theme_base` + `community_portal` | ✅ Done, committed |
| 7 | `tncsc_deployment` (client config layer) | ✅ Done, committed | | 7 | `tncsc_deployment` (client config layer) | ✅ Done, committed. Website pages content migrated from live tncsc.com in a later session — see "TNCSC website migration" below |
| 8 | TNCSC data migration scripts | ✅ Done, committed (`9a24691`) | | 8 | TNCSC data migration scripts | ✅ Done, committed (`9a24691`) |
| 9 | Packaging for resale + production go-live | 🟡 9-A in progress (see below); 9-B not started | | 9 | Packaging for resale + production go-live | 🟡 9-A in progress (see below); 9-B not started |
@ -46,6 +46,12 @@ docker compose up -d
exist) — it was instead verified on throwaway fresh databases exist) — it was instead verified on throwaway fresh databases
(`tncsc_freshN`, all dropped after verification). A real TNCSC production (`tncsc_freshN`, all dropped after verification). A real TNCSC production
database should be a genuinely fresh install, not this dev one. database should be a genuinely fresh install, not this dev one.
- `tncsc_site` is another fresh DB (with `tncsc_deployment` installed), used
for the website content migration below — kept around this time (not
dropped) since it's the one with the real seeded event/tiers to look at.
Since multiple DBs coexist, a plain `http://localhost:8069/` won't know
which to serve — select one explicitly first, e.g.
`http://localhost:8069/web?db=tncsc_site`, then it's remembered by cookie.
- **After any module code change**, the *running* `deploy-odoo-1` container - **After any module code change**, the *running* `deploy-odoo-1` container
has a stale in-memory registry until you either upgrade the module (`-u`) has a stale in-memory registry until you either upgrade the module (`-u`)
and restart the container, or just restart it: and restart the container, or just restart it:
@ -159,11 +165,10 @@ Two sub-parts with very different risk profiles:
file — the Apps-list/App-Store banner image doesn't exist yet. Needs file — the Apps-list/App-Store banner image doesn't exist yet. Needs
a real designed asset per module, not a placeholder. a real designed asset per module, not a placeholder.
- No `v1.0.0` git tag yet, and no release report — holding off on both - No `v1.0.0` git tag yet, and no release report — holding off on both
until the banner-image gap above is resolved and the full until the banner-image gap above is resolved. (A later session did run
`--test-enable` suite has actually been run against live Odoo (this `--test-enable` for `tncsc_deployment` specifically against live Odoo
session had no Docker available, so only the static checks — while doing the website migration below — 9/9 passing — but that
brand-leak grep, manifest completeness — were re-verified, not the wasn't a full suite-wide run across every `community_*` module.)
live module install/tests).
- No role guides (admin/treasurer/teacher/parent) written yet. - No role guides (admin/treasurer/teacher/parent) written yet.
- **9-B (go-live)**: not started. `deploy/odoo.conf` is still dev config - **9-B (go-live)**: not started. `deploy/odoo.conf` is still dev config
(`list_db = True`, `proxy_mode = False`, no `workers`) and (`list_db = True`, `proxy_mode = False`, no `workers`) and
@ -172,6 +177,59 @@ Two sub-parts with very different risk profiles:
server** all remain. This needs a human in the loop with actual server server** all remain. This needs a human in the loop with actual server
access/credentials — don't let an agent run this unattended. access/credentials — don't let an agent run this unattended.
## TNCSC website migration (from live tncsc.com, WordPress -> Odoo)
`addons/tncsc_deployment/views/website_pages.xml` was rewritten from the
Phase 7 placeholder pages ("content to be finalized") into the real site
content, adapted from tncsc.com (captured 2026-08-20). Tested against a
dedicated fresh database, `tncsc_site` (not `communityos_dev` or
`tncsc_migration_test`) — `docker compose exec odoo odoo -d tncsc_site -i
tncsc_deployment --stop-after-init` recreates it from scratch.
- Real pages built: Home, About, About/Tamil Nadu (bilingual EN/Tamil),
About/Board of Directors (12 real named members + photos), Membership
hub, Membership Benefits (real 8-point benefit copy), Tamil Class,
Contact, plus the pre-existing Sponsors placeholder. Nav restructured to
match tncsc.com's real structure (Home / About dropdown / Events /
Membership dropdown / Tamil Class / Contact) instead of the old flat
Classifieds/Benefits/Sponsors list.
- Real assets pulled from tncsc.com and committed under
`addons/tncsc_deployment/static/src/img/` (~1.1MB: logo, board photos,
section imagery) rather than hotlinking the WordPress site.
- Events, Membership, and Tamil Class are wired to the real product
modules (`event.event` for the homepage's "Upcoming Events", live
`community.membership.tier` records for pricing, `/school/register` for
Tamil Class signup) instead of being static copies — see each page's
QWeb for the exact query.
- One real event was seeded (`data/events_data.xml`): TNCSC's Summer
Picnic 2026, matching what's live on tncsc.com/events.
- **Deliberately not reproduced**, because it isn't real: tncsc.com's own
Sponsors page (generic `client-01..09` stock logos, dead links) and its
Contact page phone number (`+7 (800) 123 45 69`, a non-Canadian WordPress
theme demo placeholder) are themselves unmigrated theme demo content on
the live site, not real TNCSC data — confirmed by inspecting alt
text/hrefs, not assumed. Contact page ships with the real, verified
email (`support@tncsc.ca`) and social links (Facebook/YouTube/Instagram)
instead.
- **Real gap, not paved over**: `community_membership` has no public
self-service "join online" flow (portal only handles renewal for
partners a staff member already created) — every "Become a Member" CTA
points at `/contact` rather than a fake/broken signup link. Building
that flow is follow-on work, not done here.
- **Known cosmetic leftover**: Odoo's own stock header/footer snippets
ship a placeholder phone number (`+1 555-555-5556`) baked into core
`website` module views (`website.header_text_element`,
`website.footer_custom`, `website.s_contact_info`), independent of
anything in this module. It's normal, editable-in-the-website-builder
content on any fresh Odoo site, not something this module introduced —
left for whoever does the go-live content pass to delete via the
Website editor (Edit -> click the text -> delete), rather than patched
with a defensive XML override here.
- Text throughout was reconstructed via automated extraction from the live
pages, not copy-pasted from raw HTML — treat it as a faithful draft.
**Have TNCSC proofread the migrated copy against the original site
before go-live.**
## Gotchas discovered this build (Odoo 19 API drift + environment quirks) ## Gotchas discovered this build (Odoo 19 API drift + environment quirks)
This Odoo 19 build (`19.0-20260817`, essentially a nightly) diverges from This Odoo 19 build (`19.0-20260817`, essentially a nightly) diverges from
@ -214,6 +272,21 @@ re-discovering it:
is also sandboxed and forbids direct attribute assignment (`STORE_ATTR`) is also sandboxed and forbids direct attribute assignment (`STORE_ATTR`)
— use `.write(...)`. Both fully explained in the Phase 7 commit message, — use `.write(...)`. Both fully explained in the Phase 7 commit message,
fix pattern is in `addons/tncsc_deployment/models/res_company.py`. fix pattern is in `addons/tncsc_deployment/models/res_company.py`.
- Not version drift, but a real trap worth indexing here since it cost
significant debugging time during the website migration: the `website`
module auto-forks its own website-bound ("Copy-On-Write") copy of both
the homepage (`website.homepage`) and the top nav tree (`website.menu_id`)
the first time a website exists. A generic (`website_id`-unset) page or
menu record renders fine at ordinary URLs, but is silently ignored for
the homepage route and the rendered nav specifically — those two routes
only resolve records explicitly bound to the current `website_id`, and on
a same-URL tie the auto-forked stock copy wins over a same-priority
custom one by insertion order. Confirmed empirically against a live
container (not from docs). Fix pattern — explicitly bind `website_id`,
and where a stock auto-forked duplicate exists, remove it — is in
`addons/tncsc_deployment/__init__.py` (`_remove_stock_homepage_page`,
`_fix_website_menus`), both run from `post_init_hook`. Relevant if you
add more top-level pages/menu items later.
## Handing off to a team ## Handing off to a team

View File

@ -9,3 +9,80 @@ def post_init_hook(env):
transaction isn't reliable on this Odoo build. transaction isn't reliable on this Odoo build.
""" """
env.company._tncsc_setup_accounting() env.company._tncsc_setup_accounting()
_remove_stock_homepage_page(env)
_fix_website_menus(env)
def _remove_stock_homepage_page(env):
"""The website module auto-creates its own website-bound "homepage"
page/view (key 'website.homepage') for every website, independently of
this module. That page ties on priority with data/../views/website_pages.xml's
own website-bound page_home record (same url "/", same website_id) -
confirmed empirically against a live container that the url "/" route
(unlike every other page url) only resolves a website-bound page, so an
unbound generic page or an inherited view has no effect here, and on a
tie the stock page wins by insertion order (it's created before this
module installs). Removing it is what makes page_home actually serve.
"""
website = env.ref('website.default_website', raise_if_not_found=False)
if not website:
return
stock_view = env['ir.ui.view'].sudo().search([
('key', '=', 'website.homepage'),
('website_id', '=', website.id),
])
stock_page = env['website.page'].sudo().search([
('url', '=', '/'),
('website_id', '=', website.id),
('view_id', 'in', stock_view.ids),
])
# unlinking the page cascades to its underlying view - unlinking the
# (already-cascaded) view afterward would raise a MissingError.
stock_page.unlink()
# xmlid (without module prefix) of each top-level nav entry -> xmlids of its
# children, as declared in views/website_pages.xml.
_MENU_TREE = {
'menu_home': [],
'menu_about': ['menu_about_tamil_nadu', 'menu_about_board'],
'menu_events': [],
'menu_membership': ['menu_membership_benefits', 'menu_membership_registration'],
'menu_tamil_class': [],
'menu_contact': [],
}
def _fix_website_menus(env):
"""Same Copy-On-Write pattern as _remove_stock_homepage_page, applied to
website.menu: the website module auto-forks its own website-bound copy
of the top nav tree (a "Top Menu for Website <n>" record, referenced by
website.menu_id) independently of this module. website_pages.xml's menu
records attach to the generic tree (website.main_menu) instead, so they
never render, while Odoo's auto-forked copy renders as flat top-level
items with none of our children - confirmed empirically against a live
container. Fix: re-parent our records onto the actual rendered tree, and
drop every other child Odoo forked there so only ours show.
"""
website = env.ref('website.default_website', raise_if_not_found=False)
if not website:
return
root = website.menu_id
if not root:
return
mine = env['website.menu']
for top_xmlid, child_xmlids in _MENU_TREE.items():
top_menu = env.ref(f'tncsc_deployment.{top_xmlid}', raise_if_not_found=False)
if not top_menu:
continue
top_menu.write({'website_id': website.id, 'parent_id': root.id})
mine |= top_menu
for child_xmlid in child_xmlids:
child_menu = env.ref(f'tncsc_deployment.{child_xmlid}', raise_if_not_found=False)
if child_menu:
child_menu.write({'website_id': website.id, 'parent_id': top_menu.id})
mine |= child_menu
stray = env['website.menu'].sudo().search([('parent_id', '=', root.id), ('id', 'not in', mine.ids)])
stray.unlink()

View File

@ -42,6 +42,7 @@ that applies to the community_* product modules.
'data/theme_data.xml', 'data/theme_data.xml',
'data/membership_data.xml', 'data/membership_data.xml',
'data/mail_template_overrides.xml', 'data/mail_template_overrides.xml',
'data/events_data.xml',
'data/ir_cron.xml', 'data/ir_cron.xml',
'views/website_pages.xml', 'views/website_pages.xml',
], ],

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<!-- Real upcoming event, matching what's live on tncsc.com/events (2026-08-20).
Update/replace once TNCSC confirms the venue address. -->
<record id="partner_summer_picnic_venue" model="res.partner">
<field name="name">Mississauga, Ontario</field>
<field name="city">Mississauga</field>
<field name="state_id" ref="base.state_ca_on"/>
<field name="country_id" ref="base.ca"/>
<field name="type">other</field>
</record>
<record id="event_summer_picnic_2026" model="event.event">
<field name="name">TNCSC's Summer Picnic 2026</field>
<field name="date_begin" eval="'2026-07-11 14:00:00'"/>
<field name="date_end" eval="'2026-07-11 20:00:00'"/>
<field name="address_id" ref="partner_summer_picnic_venue"/>
<field name="website_published">True</field>
</record>
</odoo>

View File

@ -14,8 +14,25 @@
suppresses that auto-trigger so only our explicit load runs. --> suppresses that auto-trigger so only our explicit load runs. -->
<record id="base.main_company" model="res.company"> <record id="base.main_company" model="res.company">
<field name="name">Tamil Nadu Cultural Society of Canada</field> <field name="name">Tamil Nadu Cultural Society of Canada</field>
<field name="email">info@tncsc.example.org</field> <field name="email">support@tncsc.ca</field>
<field name="website">https://www.tncsc.example.org</field> <field name="website">https://tncsc.com</field>
<field name="logo" type="base64" file="tncsc_deployment/static/src/img/brand/logo.png"/>
</record>
<!-- Public social links, confirmed live on tncsc.com/contact (2026-08-20).
No street address or phone number is set: tncsc.com does not publish
either (its "Contact" page phone number is unmigrated WordPress
theme demo content, not a real TNCSC number) - add both here once
TNCSC provides them. -->
<record id="website.default_website" model="website">
<field name="name">Tamil Nadu Cultural Society of Canada</field>
<field name="social_facebook">https://www.facebook.com/TNCSCCanada/</field>
<field name="social_youtube">https://www.youtube.com/@tamilnaduculturalsocietyof5866</field>
<field name="social_instagram">https://www.instagram.com/tncsc_canada</field>
<!-- website.logo is its own stored field (defaults to Odoo's own
placeholder logo), not a related/computed fallback to
res.company.logo - both need to be set explicitly. -->
<field name="logo" type="base64" file="tncsc_deployment/static/src/img/brand/logo.png"/>
</record> </record>
</odoo> </odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -67,7 +67,12 @@ class TestTncscDeployment(TransactionCase):
self.assertEqual(tier.product_id.property_account_income_id, dues_account) self.assertEqual(tier.product_id.property_account_income_id, dues_account)
def test_website_pages_published(self): def test_website_pages_published(self):
for url in ('/', '/about', '/tamil-school', '/sponsors', '/contact'): urls = (
'/', '/about', '/about/tamil-nadu', '/about/board-of-directors',
'/membership', '/membership/benefits', '/tamil-school',
'/sponsors', '/contact',
)
for url in urls:
page = self.env['website.page'].search([('url', '=', url)], limit=1) page = self.env['website.page'].search([('url', '=', url)], limit=1)
self.assertTrue(page, f"Expected a website.page for {url}") self.assertTrue(page, f"Expected a website.page for {url}")
self.assertTrue(page.is_published) self.assertTrue(page.is_published)

View File

@ -1,21 +1,152 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1"> <odoo noupdate="1">
<!-- ================================================================
Content on this page is adapted from the live tncsc.com site
(captured 2026-08-20) as part of migrating it into this Odoo
website. It should be proofread by TNCSC against the original
before go-live - text was reconstructed via automated extraction,
not copy-pasted from raw HTML, so treat it as a faithful draft,
not a byte-exact mirror. Two known gaps, deliberately not
fabricated here:
- No public self-service "join online" flow exists yet in
community_membership (portal only handles renewal for partners
already created by staff) - every "Become a Member" CTA below
points at the /contact form instead of a broken/fake signup link.
- tncsc.com's own Sponsors page and Contact-page phone number are
unmigrated WordPress theme demo placeholders (generic
"client-01..09" logos, a non-Canadian demo phone number) with no
real data behind them - neither is reproduced here.
================================================================ -->
<!-- Home --> <!-- Home. The website module's homepage route ("/") is special-cased:
it only serves a website.page whose website_id explicitly matches
the current website. A generic (website_id-unset) page at "/"
renders fine at every OTHER url but is silently ignored for the
homepage specifically, and inheriting the stock "website.homepage"
view has no effect either, because Odoo already auto-forks a
website-specific copy of that view (Copy-On-Write) with no
inherit_id of its own the first time the website is customized -
confirmed empirically against a live container. So both records
below explicitly bind website_id to the default website, matching
what the homepage route actually looks up. -->
<record id="view_page_home" model="ir.ui.view"> <record id="view_page_home" model="ir.ui.view">
<field name="name">TNCSC Home</field> <field name="name">TNCSC Home</field>
<field name="type">qweb</field> <field name="type">qweb</field>
<field name="key">tncsc_deployment.page_home</field> <field name="key">tncsc_deployment.page_home</field>
<field name="website_id" ref="website.default_website"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<t t-name="tncsc_deployment.page_home"> <t t-name="tncsc_deployment.page_home">
<t t-call="website.layout"> <t t-call="website.layout">
<div class="container" style="margin-top: 40px; margin-bottom: 60px;"> <div id="wrap">
<h1>Tamil Nadu Cultural Society of Canada</h1> <section class="pt80 pb80 text-white" style="background: linear-gradient(135deg, var(--community-primary) 0%, #10193f 100%);">
<p class="lead">Celebrating Tamil language, arts, and culture in Canada.</p> <div class="container text-center">
<p>Content to be finalized by TNCSC - this is a placeholder home page <h1 class="display-4 fw-bold">Connecting Tamil Hearts Across Canada</h1>
generated by the deployment layer.</p> <p class="lead">Join Canada's Largest Tamil Nadu Cultural Community</p>
<a href="/school/register" class="btn btn-primary me-2">Register for Tamil School</a> <a href="/membership" class="btn btn-lg me-2" style="background-color: var(--community-secondary); color: #fff;">Become a Member</a>
<a href="/classifieds" class="btn btn-outline-secondary">Browse Classifieds</a> <a href="/event" class="btn btn-outline-light btn-lg">Explore Events</a>
</div>
</section>
<section class="pt56 pb56">
<div class="container">
<div class="row align-items-center g-4">
<div class="col-lg-6">
<span class="text-uppercase fw-bold" style="color: var(--community-accent);">Celebrating Cultural Excellence</span>
<h2>About TNCSC</h2>
<h3 class="h4">Canada's Largest Tamil Cultural Organization — Bridging Heritage &amp; Community Since 1997</h3>
<p>
The Tamil Nadu Cultural Society of Canada (TNCSC) has been a cornerstone of the
Tamil community since 1997, connecting generations of Tamil families through
culture, education, and service. As a registered non-profit organization, TNCSC
preserves the rich heritage of Tamil Nadu while fostering a sense of belonging
among Tamil Canadians across provinces. From vibrant Pongal festivals to Tamil
language schools, every initiative is a celebration of identity, resilience, and
community spirit. With programs designed for youth, seniors, newcomers, and
families, TNCSC continues to build a vibrant cultural bridge between Tamil
traditions and Canadian values.
</p>
<a href="/about" class="btn btn-outline-primary">Learn More</a>
</div>
<div class="col-lg-6">
<img src="/tncsc_deployment/static/src/img/home/about-01.webp" class="img-fluid rounded" alt="TNCSC community gathering"/>
</div>
</div>
</div>
</section>
<section class="pt56 pb56 bg-light">
<div class="container">
<div class="row g-4 text-center">
<div class="col-md-4">
<img src="/tncsc_deployment/static/src/img/home/cultural-events-icon.webp" alt="" style="height:64px;"/>
<h4 class="mt-3">Cultural Networking Events</h4>
<p>Build friendships and professional connections with Tamil families across Canada.</p>
</div>
<div class="col-md-4">
<img src="/tncsc_deployment/static/src/img/home/youth-mentorship.webp" alt="" style="height:64px;"/>
<h4 class="mt-3">Youth &amp; Career Mentorship</h4>
<p>Programs connecting the next generation with mentors from the Tamil-Canadian community.</p>
</div>
<div class="col-md-4">
<img src="/tncsc_deployment/static/src/img/home/frends-gathering.webp" alt="" style="height:64px;"/>
<h4 class="mt-3">Festivals &amp; Family Gatherings</h4>
<p>From Pongal feasts to Deepavali musical nights — celebrating together, every season.</p>
</div>
</div>
</div>
</section>
<section class="pt56 pb56">
<div class="container text-center">
<h2>Speak the Language of Your Heritage</h2>
<p class="lead">
Tamil classes blending traditional Tamil values with modern teaching methods —
for children ages 4 and up.
</p>
<a href="/tamil-school" class="btn btn-primary">Start Learning Today</a>
</div>
</section>
<t t-set="upcoming_events" t-value="env['event.event'].sudo().search([('website_published', '=', True)], order='date_begin', limit=3)"/>
<section class="pt56 pb56 bg-light" t-if="upcoming_events">
<div class="container">
<h2 class="text-center mb-4">Upcoming Events</h2>
<div class="row g-4">
<t t-foreach="upcoming_events" t-as="upcoming_event">
<div class="col-md-4">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title" t-out="upcoming_event.name"/>
<p class="card-text text-muted" t-out="upcoming_event.date_begin"/>
<p class="card-text" t-if="upcoming_event.address_id" t-out="upcoming_event.address_id.city"/>
<a t-attf-href="/event/#{ slug(upcoming_event) }" class="btn btn-outline-primary btn-sm">Register</a>
</div>
</div>
</div>
</t>
</div>
</div>
</section>
<section class="pt56 pb56 text-white text-center" style="background-color: var(--community-primary);">
<div class="container">
<h2>Join Canada's Tamil Cultural Heartbeat</h2>
<p class="lead">Membership is open year-round! Choose from annual, lifetime, or family plans.</p>
<div class="row justify-content-center g-3 mt-2">
<t t-foreach="env['community.membership.tier'].sudo().search([('active', '=', True)], order='sequence')" t-as="tier">
<div class="col-6 col-md-2">
<div class="card bg-transparent border-light text-white h-100">
<div class="card-body">
<h5 class="card-title" t-out="tier.name"/>
<p class="card-text" t-out="'%s %s' % (tier.currency_id.symbol, int(tier.price))"/>
</div>
</div>
</div>
</t>
</div>
<a href="/membership" class="btn btn-lg mt-3" style="background-color: var(--community-secondary); color: #fff;">Join TNCSC Today</a>
</div>
</section>
</div> </div>
</t> </t>
</t> </t>
@ -24,6 +155,7 @@
<record id="page_home" model="website.page"> <record id="page_home" model="website.page">
<field name="url">/</field> <field name="url">/</field>
<field name="view_id" ref="view_page_home"/> <field name="view_id" ref="view_page_home"/>
<field name="website_id" ref="website.default_website"/>
<field name="is_published">True</field> <field name="is_published">True</field>
</record> </record>
@ -35,10 +167,55 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<t t-name="tncsc_deployment.page_about"> <t t-name="tncsc_deployment.page_about">
<t t-call="website.layout"> <t t-call="website.layout">
<div class="container" style="margin-top: 40px; margin-bottom: 60px;"> <div id="wrap" class="container pt56 pb56">
<h1>About Us</h1> <h1>Celebrating Community, Culture, and Connection Since 1997</h1>
<p>Placeholder content - to be filled in with TNCSC's real history, mission, <h2 class="h4 text-muted">Tamil Nadu Cultural Society of Canada</h2>
and board information.</p> <p class="lead">
TNCSC is a one and only largest Indian Tamil Organisation in Canada for the
people of Tamilnadu as a whole.
</p>
<p>
Tamil Nadu Cultural Society of Canada (TNCSC) is a Not-for-Profit Ontario
Corporation serving Indian Tamils in Canada. It was established in May 1997
on an informal basis as an association of like minded Indian Tamils. It was
registered in February 1998 as a not-for-profit corporation in the province
of Ontario to connect Tamil Diasporas of Indian Tamils in Canada.
</p>
<h3 class="mt-5">Preserving Tamil Heritage</h3>
<p>
The purpose is to serve Tamils of Indian origin in Canada and preserve and
promote the heritage of our culture in Canada by celebrating festivals like
Pongal combined with Christmas and English New Year, Tamil New Year and
Deepavali combined with Eid. This will facilitate the people of Tamil Nadu
from different religion to feel Canada as a home away from home. We also help
Tamil kids of Indo-Canadian Tamils to understand our rich heritage and the
culture. Association is also assisting the new immigrants from Tamilnadu to
settle down fast in Canada by providing necessary information relating to
Canadian society, settlement, job search and community support by means of
networking.
</p>
<div class="row g-4 mt-4">
<div class="col-md-6">
<div class="card h-100">
<img src="/tncsc_deployment/static/src/img/tamil_nadu/tamilnadu-1.webp" class="card-img-top" alt="Tamil Nadu"/>
<div class="card-body">
<h4 class="card-title">Tamil Nadu</h4>
<p class="card-text">The land whose heritage and language TNCSC exists to celebrate.</p>
<a href="/about/tamil-nadu" class="btn btn-outline-primary">Discover Tamil Nadu</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<img src="/tncsc_deployment/static/src/img/about/unity.webp" class="card-img-top" alt="Board of Directors"/>
<div class="card-body">
<h4 class="card-title">Board of Directors</h4>
<p class="card-text">Meet the volunteers leading TNCSC.</p>
<a href="/about/board-of-directors" class="btn btn-outline-primary">Meet the Board</a>
</div>
</div>
</div>
</div>
</div> </div>
</t> </t>
</t> </t>
@ -50,7 +227,203 @@
<field name="is_published">True</field> <field name="is_published">True</field>
</record> </record>
<!-- Tamil School --> <!-- About / Tamil Nadu -->
<record id="view_page_tamil_nadu" model="ir.ui.view">
<field name="name">TNCSC Tamil Nadu</field>
<field name="type">qweb</field>
<field name="key">tncsc_deployment.page_tamil_nadu</field>
<field name="arch" type="xml">
<t t-name="tncsc_deployment.page_tamil_nadu">
<t t-call="website.layout">
<div id="wrap" class="container pt56 pb56">
<h1>தமிழ்நாடு <small class="text-muted">/ Tamil Nadu</small></h1>
<p class="lead" lang="ta">
தமிழ்நாடு — தமிழர்களின் ஆன்மாவும் அடையாளமும்! இது ஆயிரக்கணக்கான ஆண்டுகள்
பழமை வாய்ந்த வரலாற்றைக் கொண்ட நிலம்.
</p>
<img src="/tncsc_deployment/static/src/img/tamil_nadu/tamilnadu-1.webp" class="img-fluid rounded my-4" alt="Tamil Nadu coastline"/>
<p>
Tamil Nadu is the land of the Tamils, and it has a history that dates back
several thousand years. It is an enchanting and ancient Dravidian land in the
extreme south of peninsular India, where traditions and culture blend and
continue to live in harmony — from its temples and sculptures to its living
classical language.
</p>
<p>
The state's coastline runs nearly 1,000 km along the Coromandel Coast and the
Bay of Bengal, dotted with coconut palms, fishing villages, and rich maritime
wildlife. It is this land — its language, its coast, its temples, and its
people — that TNCSC exists to keep alive for Tamil families across Canada.
</p>
<img src="/tncsc_deployment/static/src/img/tamil_nadu/tamilnadu-2.webp" class="img-fluid rounded my-4" alt="Tamil Nadu heritage"/>
<a href="/about" class="btn btn-outline-secondary">Back to About</a>
</div>
</t>
</t>
</field>
</record>
<record id="page_tamil_nadu" model="website.page">
<field name="url">/about/tamil-nadu</field>
<field name="view_id" ref="view_page_tamil_nadu"/>
<field name="is_published">True</field>
</record>
<!-- About / Board of Directors -->
<record id="view_page_board" model="ir.ui.view">
<field name="name">TNCSC Board of Directors</field>
<field name="type">qweb</field>
<field name="key">tncsc_deployment.page_board</field>
<field name="arch" type="xml">
<t t-name="tncsc_deployment.page_board">
<t t-call="website.layout">
<div id="wrap" class="container pt56 pb56">
<h1>Board of Directors</h1>
<p class="lead">The volunteers currently leading TNCSC.</p>
<t t-set="board_members" t-value="[
{'name': 'Anand Babu Gurusamy', 'title': 'President', 'img': 'anand.webp'},
{'name': 'Rachel Daniel', 'title': 'Vice President', 'img': 'rachel.webp'},
{'name': 'Murugan Sriramulu', 'title': 'Secretary', 'img': 'murugan.webp'},
{'name': 'Palanimurugan Palanichamy', 'title': 'Treasurer', 'img': 'palani.webp'},
{'name': 'Karunamoorthy Samu', 'title': 'Joint Secretary', 'img': 'karuna.webp'},
{'name': 'Nandhini Senthil Kumar', 'title': 'Joint Treasurer', 'img': 'nandhini.webp'},
{'name': 'Amirthavarshini Thirugnanasambandam', 'title': 'Director, Muthamizh Paadasaalai', 'img': 'amirtha.webp'},
{'name': 'Ashraph Sulaiman', 'title': 'Director, IT Wing', 'img': 'asraph.webp'},
{'name': 'Brindha Rajamanickam', 'title': 'Director, Muthamizh Paadasaalai', 'img': 'brindha.webp'},
{'name': 'Mari Mutharasan', 'title': 'Director, Muthamizh Paadasaalai', 'img': 'mari.webp'},
{'name': 'Shanmuga', 'title': 'Director, IT Wing', 'img': 'shanmuga.webp'},
{'name': 'Sekar Karuppan', 'title': 'Director, IT Wing', 'img': 'sekar.webp'},
]"/>
<div class="row g-4">
<t t-foreach="board_members" t-as="member">
<div class="col-6 col-md-3 text-center">
<img t-attf-src="/tncsc_deployment/static/src/img/board/#{member['img']}" class="rounded-circle mb-2" style="width:120px;height:120px;object-fit:cover;" t-att-alt="member['name']"/>
<h5 t-out="member['name']"/>
<p class="text-muted small" t-out="member['title']"/>
</div>
</t>
</div>
<a href="/about" class="btn btn-outline-secondary mt-4">Back to About</a>
</div>
</t>
</t>
</field>
</record>
<record id="page_board" model="website.page">
<field name="url">/about/board-of-directors</field>
<field name="view_id" ref="view_page_board"/>
<field name="is_published">True</field>
</record>
<!-- Membership hub -->
<record id="view_page_membership" model="ir.ui.view">
<field name="name">TNCSC Membership</field>
<field name="type">qweb</field>
<field name="key">tncsc_deployment.page_membership</field>
<field name="arch" type="xml">
<t t-name="tncsc_deployment.page_membership">
<t t-call="website.layout">
<div id="wrap" class="container pt56 pb56">
<h1>Membership</h1>
<p class="lead">
For over 28+ years, TNCSC has been a pillar for Tamil families across
Canada — preserving language, celebrating tradition, and uniting generations
through community events and cultural programs.
</p>
<div class="row g-4 my-2">
<div class="col-md-6">
<div class="card h-100">
<img src="/tncsc_deployment/static/src/img/membership/membership-benefits.webp" class="card-img-top" alt="Membership benefits"/>
<div class="card-body">
<h4 class="card-title">Membership Benefits</h4>
<p class="card-text">Festivals, networking, Tamil school priority, and more.</p>
<a href="/membership/benefits" class="btn btn-outline-primary">See Benefits</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<img src="/tncsc_deployment/static/src/img/membership/membership-registration.webp" class="card-img-top" alt="Become a member"/>
<div class="card-body">
<h4 class="card-title">Become a Member</h4>
<p class="card-text">Online sign-up is launching soon — for now, contact us to get started.</p>
<a href="/contact" class="btn btn-primary">Contact Us to Join</a>
</div>
</div>
</div>
</div>
<h3 class="mt-5">Membership Plans</h3>
<div class="row g-3">
<t t-foreach="env['community.membership.tier'].sudo().search([('active', '=', True)], order='sequence')" t-as="tier">
<div class="col-6 col-lg-2 col-md-4">
<div class="card h-100 text-center">
<div class="card-body">
<h5 class="card-title" t-out="tier.name"/>
<p class="card-text fw-bold" t-out="'%s %s' % (tier.currency_id.symbol, int(tier.price))"/>
<p class="card-text text-muted small" t-out="dict(tier._fields['period'].selection).get(tier.period)"/>
</div>
</div>
</div>
</t>
</div>
<p class="text-muted small mt-3">Already a member? <a href="/my/membership">Manage your membership</a>.</p>
</div>
</t>
</t>
</field>
</record>
<record id="page_membership" model="website.page">
<field name="url">/membership</field>
<field name="view_id" ref="view_page_membership"/>
<field name="is_published">True</field>
</record>
<!-- Membership benefits -->
<record id="view_page_membership_benefits" model="ir.ui.view">
<field name="name">TNCSC Membership Benefits</field>
<field name="type">qweb</field>
<field name="key">tncsc_deployment.page_membership_benefits</field>
<field name="arch" type="xml">
<t t-name="tncsc_deployment.page_membership_benefits">
<t t-call="website.layout">
<div id="wrap" class="container pt56 pb56">
<h1>Membership Benefits</h1>
<h2 class="h5 text-muted">TNCSC Memberships</h2>
<p class="lead">Join Hands to Keep Our Tamil Heritage Alive — Right Here in Canada!</p>
<p>
Becoming a member of Tamil Nadu Cultural Society of Canada (TNCSC) is more
than just signing up — it's becoming part of a family that celebrates Tamil
identity, language, and culture in every heartbeat.
</p>
<div class="row g-4 align-items-center">
<div class="col-md-6">
<ul class="list-group list-group-flush">
<li class="list-group-item">Experience the joy of celebrating Tamil festivals like Pongal, Tamil New Year, and Deepavali just the way we do back home.</li>
<li class="list-group-item">Meet new friends, families, and professionals who share your values and heritage.</li>
<li class="list-group-item">Our community events bring together people from all walks of life — from entrepreneurs to IT professionals to artists.</li>
<li class="list-group-item">Members' children get priority access to our Muthamizh Padasaalai, where they learn Tamil reading, writing, and speaking.</li>
<li class="list-group-item">Every member is welcome to participate as a volunteer in TNCSC events.</li>
<li class="list-group-item">Enjoy free or discounted entry to select TNCSC programs, workshops, and cultural events.</li>
<li class="list-group-item">Voting rights and board election participation privileges.</li>
<li class="list-group-item">Your membership keeps Tamil culture alive — your involvement keeps our community strong.</li>
</ul>
</div>
<div class="col-md-6">
<img src="/tncsc_deployment/static/src/img/membership/members-img.webp" class="img-fluid rounded" alt="TNCSC members"/>
</div>
</div>
<a href="/contact" class="btn btn-primary btn-lg mt-4">Become a Member</a>
</div>
</t>
</t>
</field>
</record>
<record id="page_membership_benefits" model="website.page">
<field name="url">/membership/benefits</field>
<field name="view_id" ref="view_page_membership_benefits"/>
<field name="is_published">True</field>
</record>
<!-- Tamil School / Tamil Class -->
<record id="view_page_tamil_school" model="ir.ui.view"> <record id="view_page_tamil_school" model="ir.ui.view">
<field name="name">TNCSC Tamil School</field> <field name="name">TNCSC Tamil School</field>
<field name="type">qweb</field> <field name="type">qweb</field>
@ -58,11 +431,29 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<t t-name="tncsc_deployment.page_tamil_school"> <t t-name="tncsc_deployment.page_tamil_school">
<t t-call="website.layout"> <t t-call="website.layout">
<div class="container" style="margin-top: 40px; margin-bottom: 60px;"> <div id="wrap" class="container pt56 pb56">
<h1>Tamil School</h1> <h1>Tamil Class</h1>
<p>Weekend Tamil language classes for children and youth. See current terms, <h2 class="h5 text-muted">முத்தமிழ் பாடசாலை</h2>
levels, and class schedules below.</p> <div class="row g-4 align-items-center">
<a href="/school/register" class="btn btn-primary">Register</a> <div class="col-md-6">
<p class="lead">
தமிழ்மொழி, தமிழ்க் கலாச்சாரம், தமிழ் மரபு — the Tamil language, culture,
and heritage form the identity and foundation of our community.
</p>
<p>
Operating since 2013, our Tamil classes serve children ages 4 and older,
building speaking, reading, and writing skills through a curriculum based
on Tamil Nadu's own education system, taught from custom textbooks
developed for accessibility abroad. Our teachers are experienced educators
from Tamil Nadu who bring language, history, culture, and tradition into
every class.
</p>
<a href="/school/register" class="btn btn-primary">Register</a>
</div>
<div class="col-md-6">
<img src="/tncsc_deployment/static/src/img/tamil_class/tamil_class.webp" class="img-fluid rounded" alt="Tamil class"/>
</div>
</div>
</div> </div>
</t> </t>
</t> </t>
@ -74,7 +465,10 @@
<field name="is_published">True</field> <field name="is_published">True</field>
</record> </record>
<!-- Sponsors --> <!-- Sponsors: tncsc.com's own Sponsors page is unmigrated WordPress
theme demo content (generic client-01..09 stock logos, dead links,
no real sponsor names) - left as a placeholder, deliberately not
linked from the main nav, until TNCSC provides real sponsor data. -->
<record id="view_page_sponsors" model="ir.ui.view"> <record id="view_page_sponsors" model="ir.ui.view">
<field name="name">TNCSC Sponsors</field> <field name="name">TNCSC Sponsors</field>
<field name="type">qweb</field> <field name="type">qweb</field>
@ -105,10 +499,51 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<t t-name="tncsc_deployment.page_contact"> <t t-name="tncsc_deployment.page_contact">
<t t-call="website.layout"> <t t-call="website.layout">
<div class="container" style="margin-top: 40px; margin-bottom: 60px;"> <div id="wrap" class="container pt56 pb56">
<h1>Contact Us</h1> <h1>Contact Us</h1>
<p>Email: <t t-out="env.company.email or ''"/></p> <p class="lead">We'd Love to Hear From You</p>
<p>Placeholder content - add a real address, phone number, and contact form.</p> <div class="row g-5">
<div class="col-lg-5">
<h5>Visit / Call Us Anytime</h5>
<p>
Email:
<a t-attf-href="mailto:#{env.company.email}" t-out="env.company.email"/>
</p>
<p class="text-muted small">
No public phone line or street address is published yet — email or
social media is the fastest way to reach us.
</p>
<p>
<a href="https://www.facebook.com/TNCSCCanada/" target="_blank" class="me-3">Facebook</a>
<a href="https://www.youtube.com/@tamilnaduculturalsocietyof5866" target="_blank" class="me-3">YouTube</a>
<a href="https://www.instagram.com/tncsc_canada" target="_blank">Instagram</a>
</p>
</div>
<div class="col-lg-7">
<section class="s_website_form" data-snippet="s_website_form">
<form id="contactus_form" action="/website/form/" method="post" enctype="multipart/form-data" class="o_mark_required" data-mark="*" data-model_name="mail.mail" data-success-mode="redirect" data-success-page="/contactus-thank-you">
<input type="hidden" name="email_to" t-att-value="env.company.email"/>
<div class="mb-3">
<label class="form-label" for="contact_name">Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="name" id="contact_name" required="1"/>
</div>
<div class="mb-3">
<label class="form-label" for="contact_email">Email <span class="text-danger">*</span></label>
<input type="email" class="form-control" name="email_from" id="contact_email" required="1"/>
</div>
<div class="mb-3">
<label class="form-label" for="contact_subject">Subject</label>
<input type="text" class="form-control" name="subject" id="contact_subject"/>
</div>
<div class="mb-3">
<label class="form-label" for="contact_description">Message <span class="text-danger">*</span></label>
<textarea class="form-control" name="description" id="contact_description" rows="5" required="1"/>
</div>
<button type="submit" class="btn btn-primary">Submit Now</button>
</form>
</section>
</div>
</div>
</div> </div>
</t> </t>
</t> </t>
@ -120,41 +555,72 @@
<field name="is_published">True</field> <field name="is_published">True</field>
</record> </record>
<!-- Main nav menu entries --> <!-- Main nav menu, matching tncsc.com's real structure:
Home / About (Tamil Nadu, Board Of Directors) / Events /
Membership (Membership Benefits, Membership Registration) /
Tamil Class / Contact.
Classifieds and the vendor Benefits directory are still fully
functional CommunityOS features - they're reachable from the
member portal (/my), just not on the public marketing nav, matching
tncsc.com's own structure. -->
<record id="menu_home" model="website.menu">
<field name="name">Home</field>
<field name="url">/</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence">5</field>
</record>
<record id="menu_about" model="website.menu"> <record id="menu_about" model="website.menu">
<field name="name">About</field> <field name="name">About</field>
<field name="url">/about</field> <field name="url">/about</field>
<field name="parent_id" ref="website.main_menu"/> <field name="parent_id" ref="website.main_menu"/>
<field name="sequence">10</field> <field name="sequence">10</field>
</record> </record>
<record id="menu_tamil_school" model="website.menu"> <record id="menu_about_tamil_nadu" model="website.menu">
<field name="name">Tamil School</field> <field name="name">Tamil Nadu</field>
<field name="url">/tamil-school</field> <field name="url">/about/tamil-nadu</field>
<field name="parent_id" ref="menu_about"/>
<field name="sequence">10</field>
</record>
<record id="menu_about_board" model="website.menu">
<field name="name">Board Of Directors</field>
<field name="url">/about/board-of-directors</field>
<field name="parent_id" ref="menu_about"/>
<field name="sequence">20</field>
</record>
<record id="menu_events" model="website.menu">
<field name="name">Events</field>
<field name="url">/event</field>
<field name="parent_id" ref="website.main_menu"/> <field name="parent_id" ref="website.main_menu"/>
<field name="sequence">20</field> <field name="sequence">20</field>
</record> </record>
<record id="menu_classifieds" model="website.menu"> <record id="menu_membership" model="website.menu">
<field name="name">Classifieds</field> <field name="name">Membership</field>
<field name="url">/classifieds</field> <field name="url">/membership</field>
<field name="parent_id" ref="website.main_menu"/> <field name="parent_id" ref="website.main_menu"/>
<field name="sequence">30</field> <field name="sequence">30</field>
</record> </record>
<record id="menu_benefits" model="website.menu"> <record id="menu_membership_benefits" model="website.menu">
<field name="name">Benefits</field> <field name="name">Membership Benefits</field>
<field name="url">/benefits</field> <field name="url">/membership/benefits</field>
<field name="parent_id" ref="menu_membership"/>
<field name="sequence">10</field>
</record>
<record id="menu_membership_registration" model="website.menu">
<field name="name">Membership Registration</field>
<field name="url">/contact</field>
<field name="parent_id" ref="menu_membership"/>
<field name="sequence">20</field>
</record>
<record id="menu_tamil_class" model="website.menu">
<field name="name">Tamil Class</field>
<field name="url">/tamil-school</field>
<field name="parent_id" ref="website.main_menu"/> <field name="parent_id" ref="website.main_menu"/>
<field name="sequence">40</field> <field name="sequence">40</field>
</record> </record>
<record id="menu_sponsors" model="website.menu">
<field name="name">Sponsors</field>
<field name="url">/sponsors</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence">50</field>
</record>
<record id="menu_contact" model="website.menu"> <record id="menu_contact" model="website.menu">
<field name="name">Contact</field> <field name="name">Contact</field>
<field name="url">/contact</field> <field name="url">/contact</field>
<field name="parent_id" ref="website.main_menu"/> <field name="parent_id" ref="website.main_menu"/>
<field name="sequence">60</field> <field name="sequence">50</field>
</record> </record>
</odoo> </odoo>