Files
goodie/addons/project/models/project.go
Marc 0ed29fe2fd Odoo ERP ported to Go — complete backend + original OWL frontend
Full port of Odoo's ERP system from Python to Go, with the original
Odoo JavaScript frontend (OWL framework) running against the Go server.

Backend (10,691 LoC Go):
- Custom ORM: CRUD, domains→SQL with JOINs, computed fields, sequences
- 93 models across 14 modules (base, account, sale, stock, purchase, hr,
  project, crm, fleet, product, l10n_de, google_address/translate/calendar)
- Auth with bcrypt + session cookies
- Setup wizard (company, SKR03 chart, admin, demo data)
- Double-entry bookkeeping constraint
- Sale→Invoice workflow (confirm SO → generate invoice → post)
- SKR03 chart of accounts (110 accounts) + German taxes (USt/VSt)
- Record rules (multi-company filter)
- Google integrations as opt-in modules (Maps, Translate, Calendar)

Frontend:
- Odoo's original OWL webclient (503 JS modules, 378 XML templates)
- JS transpiled via Odoo's js_transpiler (ES modules → odoo.define)
- SCSS compiled to CSS (675KB) via dart-sass
- XML templates compiled to registerTemplate() JS calls
- Static file serving from Odoo source addons
- Login page, session management, menu navigation
- Contacts list view renders with real data from PostgreSQL

Infrastructure:
- 14MB single binary (CGO_ENABLED=0)
- Docker Compose (Go server + PostgreSQL 16)
- Zero phone-home (no outbound calls to odoo.com)

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

125 lines
5.2 KiB
Go

package models
import "odoo-go/pkg/orm"
// initProjectProject registers the project.project model.
// Mirrors: odoo/addons/project/models/project_project.py
func initProjectProject() {
m := orm.NewModel("project.project", orm.ModelOpts{
Description: "Project",
Order: "sequence, name, id",
})
m.AddFields(
orm.Char("name", orm.FieldOpts{String: "Name", Required: true, Index: true, Translate: true}),
orm.Text("description", orm.FieldOpts{String: "Description"}),
orm.Boolean("active", orm.FieldOpts{String: "Active", Default: true}),
orm.Integer("sequence", orm.FieldOpts{String: "Sequence", Default: 10}),
orm.Many2one("partner_id", "res.partner", orm.FieldOpts{String: "Customer"}),
orm.Many2one("company_id", "res.company", orm.FieldOpts{
String: "Company", Required: true, Index: true,
}),
orm.Many2one("stage_id", "project.task.type", orm.FieldOpts{String: "Stage"}),
orm.Many2many("favorite_user_ids", "res.users", orm.FieldOpts{String: "Favorite Users"}),
orm.Integer("task_count", orm.FieldOpts{
String: "Task Count",
Compute: "_compute_task_count",
}),
orm.Integer("color", orm.FieldOpts{String: "Color Index"}),
orm.Boolean("allow_task_dependencies", orm.FieldOpts{String: "Task Dependencies"}),
orm.Boolean("allow_milestones", orm.FieldOpts{String: "Milestones"}),
)
}
// initProjectTask registers the project.task model.
// Mirrors: odoo/addons/project/models/project_task.py
func initProjectTask() {
m := orm.NewModel("project.task", orm.ModelOpts{
Description: "Task",
Order: "priority desc, sequence, id desc",
})
m.AddFields(
orm.Char("name", orm.FieldOpts{String: "Title", Required: true, Index: true}),
orm.HTML("description", orm.FieldOpts{String: "Description"}),
orm.Boolean("active", orm.FieldOpts{String: "Active", Default: true}),
orm.Integer("sequence", orm.FieldOpts{String: "Sequence", Default: 10}),
orm.Many2one("project_id", "project.project", orm.FieldOpts{String: "Project", Index: true}),
orm.Many2one("parent_id", "project.task", orm.FieldOpts{String: "Parent Task", Index: true}),
orm.One2many("child_ids", "project.task", "parent_id", orm.FieldOpts{String: "Sub-tasks"}),
orm.Many2one("stage_id", "project.task.type", orm.FieldOpts{String: "Stage", Index: true}),
orm.Selection("state", []orm.SelectionItem{
{Value: "open", Label: "In Progress"},
{Value: "done", Label: "Done"},
{Value: "cancel", Label: "Cancelled"},
}, orm.FieldOpts{String: "State", Default: "open"}),
orm.Selection("priority", []orm.SelectionItem{
{Value: "0", Label: "Normal"},
{Value: "1", Label: "Important"},
}, orm.FieldOpts{String: "Priority", Default: "0"}),
orm.Integer("color", orm.FieldOpts{String: "Color Index"}),
orm.Many2many("user_ids", "res.users", orm.FieldOpts{String: "Assignees"}),
orm.Date("date_deadline", orm.FieldOpts{String: "Deadline", Index: true}),
orm.Datetime("date_assign", orm.FieldOpts{String: "Assigning Date"}),
orm.Many2many("tag_ids", "project.tags", orm.FieldOpts{String: "Tags"}),
orm.Many2one("partner_id", "res.partner", orm.FieldOpts{String: "Customer"}),
orm.Many2one("company_id", "res.company", orm.FieldOpts{
String: "Company", Required: true, Index: true,
}),
orm.Many2one("milestone_id", "project.milestone", orm.FieldOpts{String: "Milestone"}),
orm.Many2many("depend_ids", "project.task", orm.FieldOpts{String: "Depends On"}),
orm.Boolean("recurring_task", orm.FieldOpts{String: "Recurrent"}),
orm.Selection("display_type", []orm.SelectionItem{
{Value: "", Label: ""},
{Value: "line_section", Label: "Section"},
{Value: "line_note", Label: "Note"},
}, orm.FieldOpts{String: "Display Type"}),
)
}
// initProjectTaskType registers the project.task.type model (stages).
// Mirrors: odoo/addons/project/models/project_task_type.py
func initProjectTaskType() {
m := orm.NewModel("project.task.type", orm.ModelOpts{
Description: "Task Stage",
Order: "sequence, id",
})
m.AddFields(
orm.Char("name", orm.FieldOpts{String: "Name", Required: true, Translate: true}),
orm.Integer("sequence", orm.FieldOpts{String: "Sequence", Default: 1}),
orm.Boolean("fold", orm.FieldOpts{String: "Folded in Kanban"}),
orm.Many2many("project_ids", "project.project", orm.FieldOpts{String: "Projects"}),
)
}
// initProjectMilestone registers the project.milestone model.
// Mirrors: odoo/addons/project/models/project_milestone.py
func initProjectMilestone() {
m := orm.NewModel("project.milestone", orm.ModelOpts{
Description: "Project Milestone",
Order: "deadline, is_reached desc, name",
})
m.AddFields(
orm.Char("name", orm.FieldOpts{String: "Name", Required: true}),
orm.Many2one("project_id", "project.project", orm.FieldOpts{
String: "Project", Required: true, OnDelete: orm.OnDeleteCascade, Index: true,
}),
orm.Date("deadline", orm.FieldOpts{String: "Deadline"}),
orm.Boolean("is_reached", orm.FieldOpts{String: "Reached"}),
)
}
// initProjectTags registers the project.tags model.
// Mirrors: odoo/addons/project/models/project_tags.py
func initProjectTags() {
orm.NewModel("project.tags", orm.ModelOpts{
Description: "Project Tags",
Order: "name",
}).AddFields(
orm.Char("name", orm.FieldOpts{String: "Name", Required: true, Translate: true}),
orm.Integer("color", orm.FieldOpts{String: "Color Index"}),
)
}