//go:generate reform --gofmt=false package asuModels import ( "database/sql" "fmt" "github.com/xaionaro-go/extime" "html/template" "reflect" "strings" ) //reform:unit type Unit struct { Id int `reform:"id" view:"readonly"` OrgInn string `reform:"OrgInn" view:"readonly"` Name *string `reform:"Name" view:"readonly"` ParentId *int `reform:"ParentId" view:"readonly"` LevelIdx int `reform:"LevelIdx" view:"readonly"` IsHidden int `reform:"IsHidden" view:"readonly"` OKVED *string `reform:"OKVED" view:"readonly"` BriefName *string `reform:"BriefName" view:"readonly"` CreateOrderNo *string `reform:"CreateOrderNo" view:"readonly"` CreateOrderDate *extime.Time `reform:"CreateOrderDate" view:"readonly"` CloseOrderNo *string `reform:"CloseOrderNo" view:"readonly"` CloseOrderDate *extime.Time `reform:"CloseOrderDate" view:"readonly"` ChiefName *string `reform:"ChiefName" view:"readonly"` PersNumber *int `reform:"PersNumber" view:"readonly"` Code string `reform:"Code" view:"readonly"` SortNumber *int `reform:"SortNumber" view:"readonly"` ChiefTabN *string `reform:"ChiefTabN" view:"readonly"` children []*Unit `reform:"-"` childrenReady bool `reform:"-"` formulars Formulars `reform:"-"` formularsReady bool `reform:"-"` isActive bool `reform:"-"` isActiveReady bool `reform:"-"` } func (u *Unit) AfterFind() error { if u.Name != nil { *u.Name = strings.Trim(*u.Name, " ") } if u.BriefName != nil { *u.BriefName = strings.Trim(*u.BriefName, " ") } return nil } func (sql Unit) ActiveOnly() *UnitScope { return sql.Scope().ActiveOnly() } func (sql *UnitScope) ActiveOnly() *UnitScope { cond := "((CreateOrderDate IS NULL OR CreateOrderDate < NOW()) AND (CloseOrderDate IS NULL OR CloseOrderDate+24*3600 > NOW()))" return sql.Where(cond + " OR (Id IN (SELECT ParentId FROM unit WHERE " + cond + "))") } func (sql Unit) RealOnly() *UnitScope { return sql.Scope().RealOnly() } func (sql *UnitScope) RealOnly() *UnitScope { return sql.Where("LENGTH(Code) = 6") } func (sql Unit) UnhiddenOnly() *UnitScope { return sql.Scope().UnhiddenOnly() } func (sql *UnitScope) UnhiddenOnly() *UnitScope { return sql.Where("IsHidden=1") } func (sql Unit) NonEmptyOnly() *UnitScope { return sql.Scope().UnhiddenOnly() } func (sql *UnitScope) NonEmptyOnly() *UnitScope { return sql.Where("Id IN (SELECT * FROM formular WHERE (StartDate IS NULL OR StartDate < NOW()) AND (EndDate IS NULL OR EndDate+24*3600 > NOW()))") } // TODO: Remove this "VIEW" from this model func (u Unit) View_readTag(fieldName string, parent interface{}, args []interface{}) template.HTML { if u.Id == 0 { return template.HTML(fmt.Sprintf(`Не назначено`)) } name := "" if u.BriefName != nil { name = *u.BriefName } if u.Name != nil { name += " (" + *u.Name + ")" } return template.HTML(fmt.Sprintf(`%v — %v`, u.Id, u.Code, name)) } func (unit Unit) IsChildrenReady() bool { return unit.childrenReady } type Units []Unit func (units Units) ToPersNumberMap() map[int]*Unit { unitMap := map[int]*Unit{} for idx, unit := range units { if unit.PersNumber == nil { continue } unitMap[*unit.PersNumber] = &units[idx] } return unitMap } func (units Units) ToMap() map[int]*Unit { unitMap := map[int]*Unit{} for idx, unit := range units { unitMap[unit.Id] = &units[idx] } return unitMap } func (units Units) calculateTree(strict bool) { unitMap := units.ToMap() for idx, _ := range units { unit := &units[idx] if unit.ParentId == nil { continue } parent := unitMap[*unit.ParentId] if parent == nil { if strict { panic(fmt.Sprintf("Not full units list. len(units) == %v; *unit.ParentId == %v", units, *unit.ParentId)) } continue } parent.children = append(parent.children, unit) } for idx, _ := range units { units[idx].childrenReady = true } } func (units Units) CalculateTree() Units { units.calculateTree(true) return units } func (unit *Unit) DoRecursive(f func(*Unit, interface{}) bool, arg interface{}) bool { if !f(unit, arg) { return false } for _, child := range unit.GetChildrenPtrs() { if !child.DoRecursive(f, arg) { return false } } return true } func (units Units) DoRecursive(f func(*Unit, interface{}) bool, arg interface{}) bool { for _, unit := range units { unit.DoRecursive(f, arg) } return true } func (u Unit) GetChildrenPtrs() []*Unit { if !u.childrenReady { panic("unit is not ready for method GetChildrenPtrs: it's required to call CalculateTree method, first") } return u.children } func (u *Unit) PrepareFormulars() *Unit { var err error if u.PersNumber == nil { u.formulars, err = FormularSQL.Select(Formular{UnitId: u.Id}) } else { u.formulars, err = FormularSQL.Select(Formular{PersNumber: u.PersNumber}) for idx, _ := range u.formulars { u.formulars[idx].UnitId = u.Id } } if err != nil && err != sql.ErrNoRows { panic(err) } u.formularsReady = true return u } func (u Unit) GetFormularsPtr() *Formulars { return &u.formulars } func (u Unit) IsFormularsReady() bool { return u.formularsReady } func (u Unit) GetFormulars() Formulars { if !u.formularsReady { panic("unit is not ready for method GetFormulars: it's required to call PrepareFormulars method, first") } return u.formulars } func (units Units) PrepareFormulars(activeOnly bool) Units { ids := units.GetUnitIds() nums := units.GetPersNumbers() scope := FormularSQL.Scope() if activeOnly { scope = scope.ActiveOnly() } formulars, err := scope.Select("PersNumber IN (?) OR OrgDiv IN (?)", nums, ids) if err != nil && err != sql.ErrNoRows { panic(err) } unitsMap := units.ToMap() unitsPMap := units.ToPersNumberMap() for _, formular := range formulars { if formular.PersNumber == nil { (*unitsMap[formular.UnitId]).formulars = append((*unitsMap[formular.UnitId]).formulars, formular) continue } unitPtr := unitsPMap[*formular.PersNumber] formular.UnitId = (*unitPtr).Id (*unitPtr).formulars = append((*unitPtr).formulars, formular) } for idx, _ := range units { units[idx].formularsReady = true } return units } func (units Units) GetFormulars() (formulars Formulars) { for _, unit := range units { formulars = append(formulars, unit.GetFormulars()...) } return } func (u *Unit) PrepareIsActive() *Unit { now := extime.Now() startIsGood := false endIsGood := false if u.CreateOrderDate != nil { startIsGood = u.CreateOrderDate.UnixNano() <= now.UnixNano() } if u.CloseOrderDate == nil { endIsGood = true } else { endIsGood = u.CloseOrderDate.UnixNano()+24*3600*1000*1000*1000 >= now.UnixNano() } u.isActive = startIsGood && endIsGood return u } func (u Unit) IsActive() bool { if !u.isActiveReady { panic("unit is not ready for method IsActive: it's required to call PrepareIsActive method, first") } return u.isActive } func (u *Unit) prepareChildrenTree(recursive bool) *Unit { if u.childrenReady { return u } children, err := UnitSQL.Select(Unit{ParentId: &u.Id}) if err == sql.ErrNoRows { u.childrenReady = true return u } if err != nil { panic(err) } for idx, _ := range children { child := &children[idx] if recursive { child.PrepareChildrenTree() } u.children = append(u.children, child) } u.childrenReady = true return u } func (u *Unit) PrepareChildrenTree() *Unit { return u.prepareChildrenTree(true) } func (u *Unit) PrepareChildren() *Unit { return u.prepareChildrenTree(false) } func (units Units) PrepareChildrenTree() Units { for idx, _ := range units { units[idx].PrepareChildrenTree() } return units } func (units Units) PrepareChildren() Units { for idx, _ := range units { units[idx].PrepareChildren() } return units } func GetUnitsHeadedBy(empGUID int) (units Units) { var formulars Formulars trueValue := true formulars, err := FormularSQL.ActiveOnly().Select(Formular{EmpGUID: empGUID, IsHead: &trueValue}) if err != nil { panic(err) } for _, formular := range formulars { if !formular.PrepareIsActive().IsActive() { continue } formular.PrepareUnit() unit := formular.GetUnit() unit.PrepareChildrenTree() units = append(units, unit) } return } func (units Units) GetPersNumbers() (persNumbers []int) { for _, unit := range units { if unit.PersNumber == nil { continue } persNumbers = append(persNumbers, *unit.PersNumber) } return } func (units Units) GetUnitIds() (unitIds []int) { for _, unit := range units { unitIds = append(unitIds, unit.Id) } return } func (unit Unit) Flush() { unit.children = []*Unit{} unit.childrenReady = false unit.formulars = Formulars{} unit.formularsReady = false unit.isActive = false unit.isActiveReady = false } func (unit Unit) IsEqualsTo(compareTo Unit) bool { unit.Flush() compareTo.Flush() return reflect.DeepEqual(unit, compareTo) }