package budget import ( "encoding/json" "errors" "strings" "zhiyuan/models" "zhiyuan/models/budget" "zhiyuan/models/final" "zhiyuan/pkg/db" "zhiyuan/pkg/logger" "github.com/Knetic/govaluate" "github.com/gin-gonic/gin" ) var evaluableExpressionCache map[string]*govaluate.EvaluableExpression type Call struct { Expression string //Instance Instance Instance *InstanceData } type Context struct { Order *Order //Current Instance Current *InstanceData Calls []Call Modify bool C *gin.Context MatTypeCache map[int64]final.FinalMatType MatTypePidNameCache map[int64]map[string]final.FinalMatType MatCache map[int64]final.FinalMat CustomerCache *budget.Customer AdminCache *models.Admin GlobalProp map[string]interface{} LoadInstanceMap map[*InstanceData]bool ItemTypeCache map[int64]budget.ItemType ItemTypePidNameCache map[int64]map[string]budget.ItemType SupplierCache map[int64]final.FinalSupplier SupplierNameCache map[string]final.FinalSupplier CurrentPropKey uint64 } func NewContext(order *Order, c *gin.Context) *Context { if evaluableExpressionCache == nil { evaluableExpressionCache = make(map[string]*govaluate.EvaluableExpression) } context := new(Context) context.Order = order context.Calls = make([]Call, 0) context.C = c context.GlobalProp = make(map[string]interface{}) context.Current = context.Order.Form context.LoadInstanceMap = make(map[*InstanceData]bool) return context } func filterValue(value interface{}) interface{} { switch val := value.(type) { case float32: return float64(val) case int: return float64(val) case uint: return float64(val) case int8: return float64(val) case uint8: return float64(val) case int16: return float64(val) case uint16: return float64(val) case int32: return float64(val) case uint32: return float64(val) case int64: return float64(val) case uint64: return float64(val) case json.Number: if ret, err := val.Float64(); err == nil { return ret } } return value } func (context *Context) ModifyAfter(key uint64) { context.Modify = true for key := range context.Order.Prop { context.Order.Prop[key].UseKeys = make([]uint64, 0) } /*if prop, ok := context.Order.Prop[key]; ok { if useKeys := context.Order.PropUseCahce[prop.Key]; ok { for _, k := range useKeys { if useProp, ok := context.Order.Prop[k]; ok { for i, uk := range useProp.UseKeys { if uk == prop.Key { useProp.UseKeys = append(useProp.UseKeys[:i], useProp.UseKeys[i+1:]...) break } } } } context.Order.PropUseCahce[prop.Key] = make([]uint64, 0) } tmpKeys := append([]uint64{}, prop.UseKeys...) for _, k := range tmpKeys { context.ModifyAfter(k) } prop.UseKeys = make([]uint64, 0) }*/ context.LoadInstanceMap = make(map[*InstanceData]bool) } func (context *Context) Customer() *budget.Customer { if context.CustomerCache == nil { db.GetModel(map[string]interface{}{"id": context.Order.CustomerId}, &context.CustomerCache) } return context.CustomerCache } func (context *Context) Admin() *models.Admin { if context.AdminCache == nil { db.GetModel(map[string]interface{}{"id": context.Order.AdminId}, &context.AdminCache) } return context.AdminCache } func (context *Context) ItemTypeInit() { if context.ItemTypeCache == nil { context.ItemTypeCache = make(map[int64]budget.ItemType) context.ItemTypePidNameCache = make(map[int64]map[string]budget.ItemType) types := make([]budget.ItemType, 0) db.GetModel(map[string]interface{}{ "deleted_at": 0, }, &types) for _, typ := range types { if _, ok := context.ItemTypePidNameCache[typ.Pid]; !ok { context.ItemTypePidNameCache[typ.Pid] = make(map[string]budget.ItemType) } context.ItemTypeCache[typ.ID] = typ context.ItemTypePidNameCache[typ.Pid][typ.Name] = typ } } } func (context *Context) MatTypeInit() { if context.MatTypeCache == nil { context.MatTypeCache = make(map[int64]final.FinalMatType) context.MatTypePidNameCache = make(map[int64]map[string]final.FinalMatType) types := make([]final.FinalMatType, 0) db.GetModel(map[string]interface{}{ "deleted_at": 0, }, &types) for _, typ := range types { if _, ok := context.MatTypePidNameCache[typ.Pid]; !ok { context.MatTypePidNameCache[typ.Pid] = make(map[string]final.FinalMatType) } context.MatTypeCache[typ.ID] = typ context.MatTypePidNameCache[typ.Pid][typ.Name] = typ } } } func (context *Context) SupplierInit() { if context.SupplierCache == nil { context.SupplierCache = make(map[int64]final.FinalSupplier) context.SupplierNameCache = make(map[string]final.FinalSupplier) suppliers := make([]final.FinalSupplier, 0) db.GetModel(map[string]interface{}{ "deleted_at": 0, }, &suppliers) for _, supplier := range suppliers { context.SupplierCache[supplier.ID] = supplier context.SupplierNameCache[supplier.Name] = supplier } } } func (context *Context) GetMat(id int64) *final.FinalMat { if context.MatCache == nil { context.MatCache = make(map[int64]final.FinalMat) } if _, ok := context.MatCache[id]; !ok { var mat final.FinalMat db.GetModel(map[string]interface{}{ "id": id, "deleted_at": 0, }, &mat) if mat.ID != 0 { context.MatCache[id] = mat } } if mat, ok := context.MatCache[id]; ok { return &mat } return nil } /*func (context *Context) GetProp(name string) (*PropForm, error) { last := context.Current defer func() { context.Current = last }() for instance := context.Current; instance != nil; instance = instance.GetParent() { var expression string ok := false switch val := instance.(type) { case *QuoteForm: expression, ok = context.Order.Quote.Prop[name] case *TableInstance: expression, ok = context.Order.Table[val.GetID()].Prop[name] case *ModuleInstance: expression, ok = context.Order.Module[val.GetID()].Prop[name] case *GroupInstance: expression, ok = context.Order.Group[val.GetID()].Prop[name] case *RowInstance: expression, ok = context.Order.Row[val.GetID()].Prop[name] if !ok { err := context.LoadInstance(instance) if err != nil { return nil, err } if val.Item != nil { expression, ok = context.Order.Item[val.Item.ID].Prop[name] if !ok { expression, ok = context.Order.Item[val.Item.ID].ParentProp[name] } if ok { instance = val.Item } } } case *ItemInstance: expression, ok = context.Order.Item[val.GetID()].Prop[name] if !ok { expression, ok = context.Order.Item[val.GetID()].ParentProp[name] } } if ok { context.Current = instance prop := instance.GetPropResult(name) result, err := context.GetForm(expression, prop) if err != nil { return nil, err } prop = result instance.SetPropResult(name, prop) return prop, nil } } //return nil, errors.New("undeclared name: " + name) return nil, nil }*/ func (context *Context) GetProp(name string) (*PropForm, error) { last := context.Current defer func() { context.Current = last }() for instance := context.Current; instance != nil; instance = instance.Parent { var expression string ok := false if model, ok1 := context.Order.Models[instance.Type]; ok1 { if data, ok2 := model[instance.GetID()]; ok2 { expression, ok = data.GetProp(name) } } if !ok && instance.Type == Row { err := context.LoadInstance(instance) if err != nil { return nil, err } if instance.Item != nil { if model, ok1 := context.Order.Models[instance.Item.Type]; ok1 { if data, ok2 := model[instance.Item.GetID()]; ok2 { expression, ok = data.GetProp(name) } } if ok { instance = instance.Item } } } if ok { context.Current = instance prop := instance.GetPropResult(name) result, err := context.GetForm(expression, prop) if err != nil { return nil, err } prop = result instance.SetPropResult(name, prop) return prop, nil } /*switch instance.Type { case Quote: expression, ok = context.Order.Quote.Prop[name] case Table: expression, ok = context.Order.Table[instance.GetID()].Prop[name] case Module: expression, ok = context.Order.Module[instance.GetID()].Prop[name] case Group: expression, ok = context.Order.Group[instance.GetID()].Prop[name] case Row: expression, ok = context.Order.Row[instance.GetID()].Prop[name] if !ok { err := context.LoadInstance(instance) if err != nil { return nil, err } if instance.Item != nil { expression, ok = context.Order.Item[instance.Item.ID].Prop[name] if !ok { expression, ok = context.Order.Item[instance.Item.ID].ParentProp[name] } if ok { instance = instance.Item } } } case Item: expression, ok = context.Order.Item[instance.GetID()].Prop[name] if !ok { expression, ok = context.Order.Item[instance.GetID()].ParentProp[name] } } if ok { context.Current = instance prop := instance.GetPropResult(name) result, err := context.GetForm(expression, prop) if err != nil { return nil, err } prop = result instance.SetPropResult(name, prop) return prop, nil }*/ } //return nil, errors.New("undeclared name: " + name) return nil, nil } func (context *Context) Get(name string) (interface{}, error) { if value, ok := context.GlobalProp[name]; ok { return filterValue(value), nil } prop, err := context.GetProp(name) if prop == nil { return nil, err } return filterValue(prop.Result), err } func (context *Context) Error(err error) { //logger.Sugar.Infof("context.Current: %v", context.Current) logger.Sugar.Infof("context.Current.Type(): %v", context.Current.Type) //logger.Sugar.Infof("context.Current.GetObject(): %v", context.Current.GetObject()) logger.Sugar.Infof("context.Calls: %v", context.Calls) logger.Sugar.Infof("err: %v", err) } func (context *Context) EvaluableExpression(expression string) (interface{}, error) { for _, call := range context.Calls { if call.Instance == context.Current && call.Expression == expression { return nil, errors.New("circular reference: " + expression) } } context.Calls = append(context.Calls, Call{expression, context.Current}) defer func() { context.Calls = context.Calls[:len(context.Calls)-1] }() //logger.Sugar.Infof("expression: %v", expression) expr, ok := evaluableExpressionCache[expression] if !ok { s, err := govaluate.NewEvaluableExpressionWithFunctions(expression, context.Functions()) if err != nil { context.Error(err) return nil, err } expr = s } result, err := expr.Eval(context) if err != nil { context.Error(err) return nil, err } //logger.Sugar.Infof("expressionend: %v", expression) return result, nil } func (context *Context) Exec(expression string) (interface{}, error) { return context.EvaluableExpression(expression) } func (context *Context) ParseValue(value string) (interface{}, error) { if len(value) == 0 { return "", nil } switch value[0] { case '.': n, _ := db.ToFloat64(value[1:]) return n, nil case '\'': return db.ToString(value[1:]), nil case '=': return context.Exec(value[1:]) case '@': var count string var val string n := strings.Index(value[1:], "@") if n == -1 { count = value[1:] } else { count = value[1 : n+1] val = value[n+2:] } countResult, err := context.ParseValue(count) if err != nil { return nil, err } counts, _ := db.ToInt64(countResult) results := make([]interface{}, counts) for i := range results { globalProp := map[string]interface{}{ "key": float64(i), } result, err := context.ParseValueinGlobalProp(val, globalProp) if err != nil { return nil, err } results[i] = result } return results, nil default: return db.ToString(value), nil } } // func (context *Context) ParseValueinInstance(value string, instance Instance) (interface{}, error) { func (context *Context) ParseValueinInstance(value string, instance *InstanceData) (interface{}, error) { last := context.Current context.Current = instance defer func() { context.Current = last }() return context.ParseValue(value) } func (context *Context) ParseValueinGlobalProp(value string, globalProp map[string]interface{}) (interface{}, error) { last := context.GlobalProp context.GlobalProp = make(map[string]interface{}) for k, v := range last { context.GlobalProp[k] = v } for k, v := range globalProp { context.GlobalProp[k] = v } defer func() { context.GlobalProp = last }() return context.ParseValue(value) } // func (context *Context) ParseValueInInstanceAndGlobalProp(value string, instance Instance, globalProp map[string]interface{}) (interface{}, error) { func (context *Context) ParseValueInInstanceAndGlobalProp(value string, instance *InstanceData, globalProp map[string]interface{}) (interface{}, error) { lastCurrent := context.Current lastGlobalProp := context.GlobalProp context.Current = instance context.GlobalProp = make(map[string]interface{}) for k, v := range lastGlobalProp { context.GlobalProp[k] = v } for k, v := range globalProp { context.GlobalProp[k] = v } defer func() { context.Current = lastCurrent context.GlobalProp = lastGlobalProp }() return context.ParseValue(value) } func (context *Context) ParseForm(value string) (*PropForm, error) { prop := new(PropForm) prop.Instance = context.Current if len(value) != 0 { switch value[0] { case '!': prop.Cycle = Immediate value = value[1:] case '%': prop.Cycle = Save value = value[1:] } } results, err := context.ParseValue(value) if err != nil { return prop, err } if control, ok := results.(Control); ok { prop.Control = &control prop.Result = control.Value } else if control, ok := results.(*Control); ok { prop.Control = control prop.Result = control.Value } else { prop.Result = results } return prop, nil } func (context *Context) GetForm(value string, prop *PropForm) (*PropForm, error) { lastPropKey := context.CurrentPropKey defer func() { context.CurrentPropKey = lastPropKey }() if prop == nil || prop.Result == nil || len(prop.UseKeys) == 0 && (prop.Cycle == Immediate || prop.Cycle == Modify && context.Modify) { if prop != nil { context.CurrentPropKey = prop.Key } else { context.CurrentPropKey = context.Order.NewPropKey() } props, err := context.ParseForm(value) if err != nil { return nil, err } props.Key = context.CurrentPropKey if prop != nil { props.UseKeys = prop.UseKeys } if prop != nil && props.Control != nil && props.Control.Last { props.Result = prop.Result } prop = props context.Order.Prop[prop.Key] = prop } prop.AddUseKey(lastPropKey) context.Order.SetPropUse(lastPropKey, prop.Key) return prop, nil } /*func (context *Context) CreateObject(id int64, name string, parent Instance) (BaseObject, error) { var object BaseObject object.ID = id object.Init(parent, context.Order) prop, err := context.GetForm(name, nil) if err != nil { return object, err } object.NameResult = prop return object, nil } func (context *Context) CreateInstance(object Object, name interface{}, index int) (BaseInstance, error) { var instance BaseInstance instance.Init(object, index, context.Order) if nameMap, ok := name.(map[string]interface{}); ok { instance.Name = db.ToString(nameMap["name"]) instance.Show = db.ToString(nameMap["show"]) instance.ItemId, _ = db.ToInt64(nameMap["item"]) instance.Key = db.ToString(nameMap["key"]) } else { instance.Name = db.ToString(name) instance.Show = "" } return instance, nil } func (context *Context) CreateInstances(object Object, name interface{}) ([]BaseInstance, error) { instances := make([]BaseInstance, 0) if names, ok := name.([]interface{}); ok { for i, name := range names { instance, err := context.CreateInstance(object, name, i) if err != nil { return instances, err } instances = append(instances, instance) } } else { instance, err := context.CreateInstance(object, name, 0) if err != nil { return instances, err } instances = append(instances, instance) } return instances, nil } func (context *Context) CreateObject(id int64, name string, parent *InstanceData) (*ObjectData, error) { object := new(ObjectData) object.ID = id typ := parent.Type + 1 if parent.Type == Table { typ = Module } object.Init(parent, typ, context.Order) prop, err := context.GetForm(name, nil) if err != nil { return object, err } object.NameResult = prop return object, nil } func (context *Context) CreateInstance(object *ObjectData, name interface{}, index int) (*InstanceData, error) { instance := new(InstanceData) instance.Init(object, object.Type, index, context.Order) if nameMap, ok := name.(map[string]interface{}); ok { instance.Name = db.ToString(nameMap["name"]) instance.Show = db.ToString(nameMap["show"]) instance.ItemId, _ = db.ToInt64(nameMap["item"]) instance.Key = db.ToString(nameMap["key"]) } else { instance.Name = db.ToString(name) instance.Show = "" } return instance, nil } func (context *Context) CreateInstances(object *ObjectData, name interface{}) ([]InstanceData, error) { instances := make([]InstanceData, 0) if names, ok := name.([]interface{}); ok { for i, name := range names { instance, err := context.CreateInstance(object, name, i) if err != nil { return instances, err } instances = append(instances, *instance) } } else { instance, err := context.CreateInstance(object, name, 0) if err != nil { return instances, err } instances = append(instances, *instance) } return instances, nil } func (context *Context) LoadInstance(instance Instance) error { last := context.Current context.Current = instance defer func() { context.Current = last }() if load, ok := context.LoadInstanceMap[instance]; ok && load { switch val := instance.(type) { case *QuoteForm: for _, qdata := range val.Tables { if qdata.NameResult != nil { qdata.NameResult.AddUseKey(context.CurrentPropKey) } } case *TableInstance: for _, qdata := range val.Headers { if qdata.NameResult != nil { qdata.NameResult.AddUseKey(context.CurrentPropKey) } } for _, qdata := range val.Modules { if qdata.NameResult != nil { qdata.NameResult.AddUseKey(context.CurrentPropKey) } } case *HeaderInstance: val.Result.AddUseKey(context.CurrentPropKey) case *ModuleInstance: for _, qdata := range val.Groups { if qdata.NameResult != nil { qdata.NameResult.AddUseKey(context.CurrentPropKey) } } case *GroupInstance: for _, qdata := range val.Rows { if qdata.NameResult != nil { qdata.NameResult.AddUseKey(context.CurrentPropKey) } } } return nil } switch val := instance.(type) { case *QuoteForm: tables := make([]TableObject, 0) for _, qtable := range context.Order.Quote.Tables { var object *TableObject for i, table := range val.Tables { if table.ID == qtable.ID { object = &val.Tables[i] } } if object == nil { o, err := context.CreateObject(qtable.ID, qtable.Name, instance) if err != nil { return err } object = new(TableObject) object.BaseObject = o object.Init(instance, context.Order) } nameResult, err := context.GetForm(context.Order.Table[object.ID].Name, object.NameResult) if err != nil { return err } object.NameResult = nameResult instances, err := context.CreateInstances(object, object.NameResult.Result) if err != nil { return err } objectInstances := make(map[int]TableInstance) objectInstanceMap := make(map[string]TableInstance) for _, instance := range object.Instances { objectInstances[instance.Index] = instance if instance.Key != "" { objectInstanceMap[instance.Key] = instance } } //object.Instances = make([]TableInstance, 0) for _, instance := range instances { var objectInstance *TableInstance if instance.Key == "" { if i, ok := objectInstances[instance.Index]; ok { objectInstance = &i } } else { if i, ok := objectInstanceMap[instance.Key]; ok { objectInstance = &i } } if objectInstance == nil { objectInstance = new(TableInstance) objectInstance.BaseInstance = instance } else { delete(objectInstances, objectInstance.Index) delete(objectInstanceMap, objectInstance.Key) objectInstance.Name = instance.Name objectInstance.Show = instance.Show objectInstance.ItemId = instance.ItemId objectInstance.Key = instance.Key } objectInstance.Init(object, instance.Index, context.Order) if len(object.Instances) > instance.Index { object.Instances[instance.Index] = *objectInstance } else { object.Instances = append(object.Instances, *objectInstance) } } if len(object.Instances) > len(instances) { object.Instances = object.Instances[:len(instances)] } tables = append(tables, *object) } val.Tables = tables case *TableInstance: headers := make([]HeaderObject, 0) for _, qdata := range context.Order.Table[val.GetID()].Headers { var object *HeaderObject for i, o := range val.Headers { if o.ID == qdata.ID { object = &val.Headers[i] } } if object == nil { o, err := context.CreateObject(qdata.ID, qdata.Name, instance) if err != nil { return err } object = new(HeaderObject) object.BaseObject = o object.Init(instance, context.Order) } nameResult, err := context.GetForm(context.Order.Header[object.ID].Name, object.NameResult) if err != nil { return err } object.NameResult = nameResult instances, err := context.CreateInstances(object, object.NameResult.Result) if err != nil { return err } objectInstances := make(map[int]HeaderInstance) objectInstanceMap := make(map[string]HeaderInstance) for _, instance := range object.Instances { objectInstances[instance.Index] = instance if instance.Key != "" { objectInstanceMap[instance.Key] = instance } } //object.Instances = make([]HeaderInstance, 0) for _, instance := range instances { var objectInstance *HeaderInstance if instance.Key == "" { if i, ok := objectInstances[instance.Index]; ok { objectInstance = &i } } else { if i, ok := objectInstanceMap[instance.Key]; ok { objectInstance = &i } } if objectInstance == nil { objectInstance = new(HeaderInstance) objectInstance.BaseInstance = instance } else { delete(objectInstances, objectInstance.Index) delete(objectInstanceMap, objectInstance.Key) objectInstance.Name = instance.Name objectInstance.Show = instance.Show objectInstance.ItemId = instance.ItemId objectInstance.Key = instance.Key } objectInstance.Init(object, instance.Index, context.Order) if len(object.Instances) > instance.Index { object.Instances[instance.Index] = *objectInstance } else { object.Instances = append(object.Instances, *objectInstance) } } if len(object.Instances) > len(instances) { object.Instances = object.Instances[:len(instances)] } headers = append(headers, *object) } val.Headers = headers modules := make([]ModuleObject, 0) for _, qdata := range context.Order.Table[val.GetID()].Modules { var object *ModuleObject for i, o := range val.Modules { if o.ID == qdata.ID { object = &val.Modules[i] } } if object == nil { o, err := context.CreateObject(qdata.ID, qdata.Name, instance) if err != nil { return err } object = new(ModuleObject) object.BaseObject = o object.Init(instance, context.Order) } nameResult, err := context.GetForm(context.Order.Module[object.ID].Name, object.NameResult) if err != nil { return err } object.NameResult = nameResult instances, err := context.CreateInstances(object, object.NameResult.Result) if err != nil { return err } objectInstances := make(map[int]ModuleInstance) objectInstanceMap := make(map[string]ModuleInstance) for _, instance := range object.Instances { objectInstances[instance.Index] = instance if instance.Key != "" { objectInstanceMap[instance.Key] = instance } } //object.Instances = make([]ModuleInstance, 0) for _, instance := range instances { var objectInstance *ModuleInstance if instance.Key == "" { if i, ok := objectInstances[instance.Index]; ok { objectInstance = &i } } else { if i, ok := objectInstanceMap[instance.Key]; ok { objectInstance = &i } } if objectInstance == nil { objectInstance = new(ModuleInstance) objectInstance.BaseInstance = instance } else { delete(objectInstances, objectInstance.Index) delete(objectInstanceMap, objectInstance.Key) objectInstance.Name = instance.Name objectInstance.Show = instance.Show objectInstance.ItemId = instance.ItemId objectInstance.Key = instance.Key } objectInstance.Init(object, instance.Index, context.Order) if len(object.Instances) > instance.Index { object.Instances[instance.Index] = *objectInstance } else { object.Instances = append(object.Instances, *objectInstance) } } if len(object.Instances) > len(instances) { object.Instances = object.Instances[:len(instances)] } modules = append(modules, *object) } val.Modules = modules case *HeaderInstance: prop, err := context.GetForm(context.Order.Header[val.GetID()].Value, val.Result) if err != nil { return err } val.Result = prop case *ModuleInstance: groups := make([]GroupObject, 0) for _, qdata := range context.Order.Module[val.GetID()].Groups { var object *GroupObject for i, o := range val.Groups { if o.ID == qdata.ID { object = &val.Groups[i] } } if object == nil { o, err := context.CreateObject(qdata.ID, qdata.Name, instance) if err != nil { return err } object = new(GroupObject) object.BaseObject = o object.Init(instance, context.Order) } nameResult, err := context.GetForm(context.Order.Group[object.ID].Name, object.NameResult) if err != nil { return err } object.NameResult = nameResult instances, err := context.CreateInstances(object, object.NameResult.Result) if err != nil { return err } objectInstances := make(map[int]GroupInstance) objectInstanceMap := make(map[string]GroupInstance) for _, instance := range object.Instances { objectInstances[instance.Index] = instance if instance.Key != "" { objectInstanceMap[instance.Key] = instance } } //object.Instances = make([]GroupInstance, 0) for _, instance := range instances { var objectInstance *GroupInstance if instance.Key == "" { if i, ok := objectInstances[instance.Index]; ok { objectInstance = &i } } else { if i, ok := objectInstanceMap[instance.Key]; ok { objectInstance = &i } } if objectInstance == nil { objectInstance = new(GroupInstance) objectInstance.BaseInstance = instance } else { delete(objectInstances, objectInstance.Index) delete(objectInstanceMap, objectInstance.Key) objectInstance.Name = instance.Name objectInstance.Show = instance.Show objectInstance.ItemId = instance.ItemId objectInstance.Key = instance.Key } objectInstance.Init(object, instance.Index, context.Order) if len(object.Instances) > instance.Index { object.Instances[instance.Index] = *objectInstance } else { object.Instances = append(object.Instances, *objectInstance) } } if len(object.Instances) > len(instances) { object.Instances = object.Instances[:len(instances)] } groups = append(groups, *object) } val.Groups = groups case *GroupInstance: rows := make([]RowObject, 0) for _, qdata := range context.Order.Group[val.GetID()].Rows { var object *RowObject for i, o := range val.Rows { if o.ID == qdata.ID { object = &val.Rows[i] } } if object == nil { o, err := context.CreateObject(qdata.ID, qdata.Name, instance) if err != nil { return err } object = new(RowObject) object.BaseObject = o object.Init(instance, context.Order) } nameResult, err := context.GetForm(context.Order.Row[object.ID].Name, object.NameResult) if err != nil { return err } object.NameResult = nameResult instances, err := context.CreateInstances(object, object.NameResult.Result) if err != nil { return err } objectInstances := make(map[int]RowInstance) objectInstanceMap := make(map[string]RowInstance) for _, instance := range object.Instances { objectInstances[instance.Index] = instance if instance.Key != "" { objectInstanceMap[instance.Key] = instance } } //object.Instances = make([]RowInstance, 0) for _, instance := range instances { var objectInstance *RowInstance if instance.Key == "" { if i, ok := objectInstances[instance.Index]; ok { objectInstance = &i } } else { if i, ok := objectInstanceMap[instance.Key]; ok { objectInstance = &i } } if objectInstance == nil { objectInstance = new(RowInstance) objectInstance.BaseInstance = instance } else { delete(objectInstances, objectInstance.Index) delete(objectInstanceMap, objectInstance.Key) objectInstance.Name = instance.Name objectInstance.Show = instance.Show objectInstance.ItemId = instance.ItemId objectInstance.Key = instance.Key } objectInstance.Init(object, instance.Index, context.Order) if len(object.Instances) > instance.Index { object.Instances[instance.Index] = *objectInstance } else { object.Instances = append(object.Instances, *objectInstance) } } if len(object.Instances) > len(instances) { object.Instances = object.Instances[:len(instances)] } rows = append(rows, *object) } val.Rows = rows case *RowInstance: if val.ItemId != 0 { if _, ok := context.Order.Item[val.ItemId]; !ok { items := budget.GetItemModels(map[string]interface{}{ "id": val.ItemId, "deleted_at": 0, }) if len(items) != 0 { context.Order.Item[val.ItemId] = items[0] } } } itemId := int64(0) if val.ItemId != 0 { if item, ok := context.Order.Item[val.ItemId]; ok { itemId = item.ID } } else if context.Order.Row[val.GetID()].Item != nil { itemId = context.Order.Row[val.GetID()].Item.ID } if itemId == 0 { val.Item = nil } else { if val.Item == nil || itemId != val.Item.ID { val.Item = new(ItemInstance) val.Item.ID = itemId val.Item.Init(val.Object, 0, context.Order) } val.Item.Row = val } } context.LoadInstanceMap[instance] = true return nil }*/ func (context *Context) LoadInstance(instance *InstanceData) error { last := context.Current context.Current = instance defer func() { context.Current = last }() if load, ok := context.LoadInstanceMap[instance]; ok && load { if instance.Subs != nil { for _, sub := range instance.Subs { if sub.NameResult != nil { sub.NameResult.AddUseKey(context.CurrentPropKey) context.Order.SetPropUse(context.CurrentPropKey, sub.NameResult.Key) } } } if instance.Headers != nil { for _, header := range instance.Headers { if header.NameResult != nil { header.NameResult.AddUseKey(context.CurrentPropKey) context.Order.SetPropUse(context.CurrentPropKey, header.NameResult.Key) } } } if instance.Result != nil { instance.Result.AddUseKey(context.CurrentPropKey) context.Order.SetPropUse(context.CurrentPropKey, instance.Result.Key) } return nil } if model, ok := context.Order.Models[instance.Type]; ok { if data, ok := model[instance.GetID()]; ok { var err error qsubs := data.GetSubs() if qsubs != nil { if instance.Subs == nil { instance.Subs = make([]ObjectData, 0) } subType := instance.Type + 1 if instance.Type == Table { subType = Module } instance.Subs, err = context.LoadSubs(instance, subType, &instance.Subs, qsubs) if err != nil { return err } } qheaders := data.GetHeaders() if qheaders != nil { if instance.Headers == nil { instance.Headers = make([]ObjectData, 0) } instance.Headers, err = context.LoadSubs(instance, Header, &instance.Headers, qheaders) if err != nil { return err } } itemId := int64(0) if instance.ItemId != 0 { item := context.LoadItem(instance.ItemId) if item != nil { itemId = item.GetID() } } else if data.GetItem() != nil { itemId = data.GetItem().GetID() } if itemId == 0 { instance.Item = nil } else { if instance.Item == nil || itemId != instance.Item.ID { instance.Item = new(InstanceData) instance.Item.ID = itemId instance.Item.Init(instance, instance.Object, Item, instance.Index, context.Order) } } if instance.Type == Header { prop, err := context.GetForm(data.GetValue(), instance.Result) if err != nil { return err } instance.Result = prop } } } context.LoadInstanceMap[instance] = true return nil } func (context *Context) LoadItem(itemId int64) budget.QuoteData { if _, ok := context.Order.Models[Item][itemId]; !ok { _, items := budget.GetItemModels(map[string]interface{}{ "id": itemId, "deleted_at": 0, }) if len(items) != 0 { context.Order.Models[Item][itemId] = items[0] } } if item, ok := context.Order.Models[Item][itemId]; ok { return item } return nil } func (context *Context) LoadSubs(instance *InstanceData, typ int, oldSubs *[]ObjectData, quoteDatas *[]budget.QuoteData) ([]ObjectData, error) { subs := make([]ObjectData, 0) for _, qsub := range *quoteDatas { var object *ObjectData for i, sub := range *oldSubs { if sub.ID == qsub.GetID() { object = &(*oldSubs)[i] } } if object == nil { object = new(ObjectData) object.ID = qsub.GetID() object.Init(instance, typ, context.Order) } nameResult, err := context.GetForm(qsub.GetName(), object.NameResult) if err != nil { return nil, err } object.NameResult = nameResult var instanceNames []interface{} if names, ok := object.NameResult.Result.([]interface{}); ok { instanceNames = names } else { instanceNames = []interface{}{object.NameResult.Result} } objectInstanceMap := make(map[string]*InstanceData) for i, instance := range object.Instances { if instance.Key != "" { objectInstanceMap[instance.Key] = &object.Instances[i] } } subInstances := make([]InstanceData, 0) for i, instanceName := range instanceNames { var subInstance *InstanceData var name, show, key string var itemid int64 if nameMap, ok := instanceName.(map[string]interface{}); ok { name = db.ToString(nameMap["name"]) show = db.ToString(nameMap["show"]) itemid, _ = db.ToInt64(nameMap["item"]) key = db.ToString(nameMap["key"]) } else { name = db.ToString(instanceName) } if key == "" { if len(object.Instances) > i { subInstance = &object.Instances[i] } } else { if i, ok := objectInstanceMap[key]; ok { subInstance = i } } if subInstance == nil { subInstance = new(InstanceData) } else { delete(objectInstanceMap, subInstance.Key) } subInstance.Name = name subInstance.Show = show subInstance.ItemId = itemid subInstance.Key = key subInstance.Init(instance, object, object.Type, i, context.Order) subInstances = append(subInstances, *subInstance) } object.Instances = subInstances subs = append(subs, *object) } return subs, nil } func (context *Context) LoadNameResult(instance *InstanceData) (*PropForm, error) { last := context.Current context.Current = instance defer func() { context.Current = last }() nameResult, err := context.GetForm(instance.Name, instance.NameResult) if err != nil { return nil, err } if nameResult != nil && instance.Object != nil && instance.Object.NameResult != nil { instance.Object.NameResult.AddUseKey(nameResult.Key) context.Order.SetPropUse(nameResult.Key, instance.Object.NameResult.Key) } instance.SetNameResult(nameResult) return nameResult, nil } func (context *Context) LoadShowResult(instance *InstanceData) (*PropForm, error) { last := context.Current context.Current = instance defer func() { context.Current = last }() showResult, err := context.GetForm(instance.Show, instance.ShowResult) if err != nil { return nil, err } if showResult != nil && instance.Object != nil && instance.Object.NameResult != nil { instance.Object.NameResult.AddUseKey(showResult.Key) context.Order.SetPropUse(showResult.Key, instance.Object.NameResult.Key) } instance.SetShowResult(showResult) return showResult, nil } func (context *Context) EvalRowHeaderResult(row *InstanceData, table *InstanceData) error { last := context.Current context.Current = row defer func() { context.Current = last }() for _, header := range table.Headers { row.HeaderResult[header.ID] = make([]*PropForm, 0) for _, hInstance := range header.Instances { if hInstance.Result == nil { row.HeaderResult[header.ID] = append(row.HeaderResult[header.ID], nil) continue } prop, err := context.GetProp(db.ToString(hInstance.Result.Result)) if err != nil { return err } if prop != nil { prop.Header = true } row.HeaderResult[header.ID] = append(row.HeaderResult[header.ID], prop) } } return nil } func (context *Context) EvalResult() error { err := context.LoadInstance(context.Order.Form) if err != nil { return err } for i := range context.Order.Form.Subs { table := &context.Order.Form.Subs[i] for tableIndex := 0; tableIndex < len(table.Instances); tableIndex++ { tableInstance := &table.Instances[tableIndex] _, err := context.LoadNameResult(tableInstance) if err != nil { return err } _, err = context.LoadShowResult(tableInstance) if err != nil { return err } err = context.LoadInstance(tableInstance) if err != nil { return err } for i := range tableInstance.Headers { header := &tableInstance.Headers[i] for headerIndex := 0; headerIndex < len(header.Instances); headerIndex++ { _, err := context.LoadNameResult(&header.Instances[headerIndex]) if err != nil { return err } _, err = context.LoadShowResult(&header.Instances[headerIndex]) if err != nil { return err } err = context.LoadInstance(&header.Instances[headerIndex]) if err != nil { return err } } } for i := range tableInstance.Subs { module := &tableInstance.Subs[i] for moduleIndex := 0; moduleIndex < len(module.Instances); moduleIndex++ { moduleInstance := &module.Instances[moduleIndex] _, err := context.LoadNameResult(moduleInstance) if err != nil { return err } _, err = context.LoadShowResult(moduleInstance) if err != nil { return err } err = context.LoadInstance(moduleInstance) if err != nil { return err } for i := range moduleInstance.Subs { group := &moduleInstance.Subs[i] for groupIndex := 0; groupIndex < len(group.Instances); groupIndex++ { groupInstance := &group.Instances[groupIndex] _, err := context.LoadNameResult(groupInstance) if err != nil { return err } _, err = context.LoadShowResult(groupInstance) if err != nil { return err } err = context.LoadInstance(groupInstance) if err != nil { return err } for i := range groupInstance.Subs { row := &groupInstance.Subs[i] for rowIndex := 0; rowIndex < len(row.Instances); rowIndex++ { rowInstance := &row.Instances[rowIndex] _, err := context.LoadNameResult(rowInstance) if err != nil { return err } _, err = context.LoadShowResult(rowInstance) if err != nil { return err } err = context.LoadInstance(rowInstance) if err != nil { return err } err = context.EvalRowHeaderResult(rowInstance, tableInstance) if err != nil { return err } } } } } } } } } return nil } func (context *Context) Eval() error { //if context.Current == nil { /*err := context.LoadInstance(context.Order.Form) if err != nil { return err }*/ return context.EvalResult() //} return nil } func (context *Context) Handle(key uint64, typ string, value interface{}) error { if prop, ok := context.Order.Prop[key]; ok { last := context.Current context.Current = prop.Instance defer func() { context.Current = last }() if prop.Control == nil { return errors.New("undeclared control: " + db.ToString(key)) } err := prop.Control.Handle(typ, value, prop, context) if err != nil { context.Error(err) return err } } else { return errors.New("undeclared object: " + db.ToString(key)) } return nil }