package models import ( "fmt" "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("user_id", "res.users", orm.FieldOpts{String: "Project Manager"}), orm.Many2one("company_id", "res.company", orm.FieldOpts{ String: "Company", Required: true, Index: true, }), orm.Date("date_start", orm.FieldOpts{String: "Start Date"}), orm.Date("date", orm.FieldOpts{String: "Expiration Date"}), 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() { task := orm.NewModel("project.task", orm.ModelOpts{ Description: "Task", Order: "priority desc, sequence, id desc", }) task.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.Selection("kanban_state", []orm.SelectionItem{ {Value: "normal", Label: "In Progress"}, {Value: "done", Label: "Ready"}, {Value: "blocked", Label: "Blocked"}, }, orm.FieldOpts{String: "Kanban State", Default: "normal"}), 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.Datetime("planned_date_start", orm.FieldOpts{String: "Planned Start Date"}), orm.Datetime("planned_date_end", orm.FieldOpts{String: "Planned End Date"}), orm.Selection("display_type", []orm.SelectionItem{ {Value: "", Label: ""}, {Value: "line_section", Label: "Section"}, {Value: "line_note", Label: "Note"}, }, orm.FieldOpts{String: "Display Type"}), ) // DefaultGet: set company_id from session task.DefaultGet = func(env *orm.Environment, fields []string) orm.Values { vals := make(orm.Values) if env.CompanyID() > 0 { vals["company_id"] = env.CompanyID() } return vals } // action_done: mark task as done task.RegisterMethod("action_done", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) { env := rs.Env() for _, id := range rs.IDs() { if _, err := env.Tx().Exec(env.Ctx(), `UPDATE project_task SET state = 'done' WHERE id = $1`, id); err != nil { return nil, fmt.Errorf("project.task: done %d: %w", id, err) } } return true, nil }) task.RegisterMethod("action_cancel", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) { env := rs.Env() for _, id := range rs.IDs() { if _, err := env.Tx().Exec(env.Ctx(), `UPDATE project_task SET state = 'cancel' WHERE id = $1`, id); err != nil { return nil, fmt.Errorf("project.task: cancel %d: %w", id, err) } } return true, nil }) task.RegisterMethod("action_reopen", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) { env := rs.Env() for _, id := range rs.IDs() { if _, err := env.Tx().Exec(env.Ctx(), `UPDATE project_task SET state = 'open' WHERE id = $1`, id); err != nil { return nil, fmt.Errorf("project.task: reopen %d: %w", id, err) } } return true, nil }) task.RegisterMethod("action_blocked", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) { env := rs.Env() for _, id := range rs.IDs() { if _, err := env.Tx().Exec(env.Ctx(), `UPDATE project_task SET kanban_state = 'blocked' WHERE id = $1`, id); err != nil { return nil, fmt.Errorf("project.task: blocked %d: %w", id, err) } } return true, nil }) task.RegisterMethod("toggle_active", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) { env := rs.Env() for _, id := range rs.IDs() { if _, err := env.Tx().Exec(env.Ctx(), `UPDATE project_task SET active = NOT active WHERE id = $1`, id); err != nil { return nil, fmt.Errorf("project.task: toggle_active %d: %w", id, err) } } return true, nil }) // Ensure fmt is used _ = fmt.Sprintf } // 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"}), ) } // initProjectTaskChecklist registers the project.task.checklist model. // Mirrors: odoo/addons/project/models/project_task_checklist.py func initProjectTaskChecklist() { m := orm.NewModel("project.task.checklist", orm.ModelOpts{ Description: "Task Checklist Item", Order: "sequence, id", }) m.AddFields( orm.Many2one("task_id", "project.task", orm.FieldOpts{ String: "Task", Required: true, OnDelete: orm.OnDeleteCascade, Index: true, }), orm.Char("name", orm.FieldOpts{String: "Name", Required: true}), orm.Boolean("is_done", orm.FieldOpts{String: "Done", Default: false}), orm.Integer("sequence", orm.FieldOpts{String: "Sequence", Default: 10}), ) // action_toggle_done: Toggle the checklist item done status. m.RegisterMethod("action_toggle_done", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) { env := rs.Env() for _, id := range rs.IDs() { if _, err := env.Tx().Exec(env.Ctx(), `UPDATE project_task_checklist SET is_done = NOT is_done WHERE id = $1`, id); err != nil { return nil, fmt.Errorf("project.task.checklist: toggle_done %d: %w", id, err) } } return true, nil }) } // initProjectSharing registers the project.sharing model. // Mirrors: odoo/addons/project/models/project_sharing.py func initProjectSharing() { m := orm.NewModel("project.sharing", orm.ModelOpts{ Description: "Project Sharing", Order: "id", }) m.AddFields( orm.Many2one("partner_id", "res.partner", orm.FieldOpts{ String: "Partner", Required: true, Index: true, }), orm.Many2one("project_id", "project.project", orm.FieldOpts{ String: "Project", Required: true, OnDelete: orm.OnDeleteCascade, Index: true, }), orm.Selection("access_level", []orm.SelectionItem{ {Value: "read", Label: "Read"}, {Value: "edit", Label: "Edit"}, {Value: "admin", Label: "Admin"}, }, orm.FieldOpts{String: "Access Level", Required: true, Default: "read"}), ) m.AddSQLConstraint( "unique_partner_project", "UNIQUE(partner_id, project_id)", "A partner can only have one sharing entry per project.", ) }