Fix action domain/context parsing for fresh DB usability

Action domain strings like [("move_type","in",["out_invoice"])] were
returned as raw strings. The OWL client needs JSON arrays.

- parseDomainOrDefault: converts Python-style domain to JSON array
  (replaces () with [], ' with ", True/False/None)
- parseContextOrDefault: same for context dicts
- Fixes empty Invoice/Vendor Bills list views on fresh DB

Full flow verified on clean DB:
Contact → Sale Order → Confirm → Invoice → Post → all working.
All 9 module actions load correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc
2026-04-04 11:58:08 +02:00
parent 5973a445c0
commit cc6184a18b

View File

@@ -162,8 +162,8 @@ func (s *Server) handleActionLoad(w http.ResponseWriter, r *http.Request) {
"view_mode": coalesce(viewMode, "list,form"), "view_mode": coalesce(viewMode, "list,form"),
"views": views, "views": views,
"search_view_id": false, "search_view_id": false,
"domain": coalesce(deref(domain), "[]"), "domain": parseDomainOrDefault(deref(domain)),
"context": coalesce(deref(actCtx), "{}"), "context": parseContextOrDefault(deref(actCtx)),
"target": coalesce(deref(target), "current"), "target": coalesce(deref(target), "current"),
"limit": coalesceInt(limit, 80), "limit": coalesceInt(limit, 80),
"help": deref(help), "help": deref(help),
@@ -225,6 +225,45 @@ func coalesceInt(p *int, fallback int) int {
return fallback return fallback
} }
// parseDomainOrDefault tries to parse a Python-style domain string to JSON.
// Returns parsed []interface{} if valid JSON, otherwise returns "[]".
func parseDomainOrDefault(s string) interface{} {
s = strings.TrimSpace(s)
if s == "" || s == "[]" {
return []interface{}{}
}
// Try JSON parse directly (handles [["field","op","val"]] format)
var result []interface{}
// Convert Python-style to JSON: replace ( with [, ) with ], True/False/None
jsonStr := strings.ReplaceAll(s, "(", "[")
jsonStr = strings.ReplaceAll(jsonStr, ")", "]")
jsonStr = strings.ReplaceAll(jsonStr, "'", "\"")
jsonStr = strings.ReplaceAll(jsonStr, "True", "true")
jsonStr = strings.ReplaceAll(jsonStr, "False", "false")
jsonStr = strings.ReplaceAll(jsonStr, "None", "null")
if err := json.Unmarshal([]byte(jsonStr), &result); err == nil {
return result
}
// Fallback: return as-is string (client may handle it)
return s
}
// parseContextOrDefault tries to parse context string to JSON object.
func parseContextOrDefault(s string) interface{} {
s = strings.TrimSpace(s)
if s == "" || s == "{}" {
return map[string]interface{}{}
}
var result map[string]interface{}
jsonStr := strings.ReplaceAll(s, "'", "\"")
jsonStr = strings.ReplaceAll(jsonStr, "True", "true")
jsonStr = strings.ReplaceAll(jsonStr, "False", "false")
if err := json.Unmarshal([]byte(jsonStr), &result); err == nil {
return result
}
return map[string]interface{}{}
}
// deref returns the value of a string pointer, or "" if nil. // deref returns the value of a string pointer, or "" if nil.
func deref(p *string) string { func deref(p *string) string {
if p != nil { if p != nil {