Browse Source

Added features required for https://devel.mephi.ru/dyokunev/cps-api

Dmitry Yu Okunev 5 years ago
parent
commit
409a989306
5 changed files with 295 additions and 26 deletions
  1. 1 0
      .gitignore
  2. 1 0
      README.md
  3. 55 7
      formular.go
  4. 27 2
      person.go
  5. 211 17
      unit.go

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+*_reform.go

+ 1 - 0
README.md

@@ -0,0 +1 @@
+Usage example is here [https://devel.mephi.ru/dyokunev/cps-api/src/master/app/init.go](https://devel.mephi.ru/dyokunev/cps-api/src/master/app/init.go)

+ 55 - 7
formular.go

@@ -29,8 +29,14 @@ type Formular struct {
 	IsHead               *bool        `reform:"IsHead"         view:"readonly"`
 	UnitId               int          `reform:"OrgDiv"         view:"readonly"`
 
-	Unit   Unit   `reform:"-"`
-	Person Person `reform:"-"`
+	unit      Unit `reform:"-"`
+	unitReady bool `reform:"-"`
+
+	person      Person `reform:"-"`
+	personReady bool   `reform:"-"`
+
+	isActive      bool `reform:"-"`
+	isActiveReady bool `reform:"-"`
 
 	//PersNumber           *int         `reform:"PersNumber"`
 	//FormularTypeCode   int     `reform:"Cod_Tip_formular"`
@@ -51,6 +57,14 @@ type Formular struct {
 	//ExtraVacDays       *int    `reform:"ExtraVacDays"`
 }
 
+func (sql Formular) ActiveOnly() *FormularScope {
+	return sql.Scope().ActiveOnly()
+}
+func (sql *FormularScope) ActiveOnly() *FormularScope {
+	return sql.Where("(StartDate IS NULL OR StartDate < NOW()) AND (EndDate IS NULL OR EndDate+24*3600 > NOW())")
+}
+
+// TODO: Remove this "VIEW" from this model
 func (f Formular) View_readTag(fieldName string, parent interface{}, args []interface{}) template.HTML {
 	unitName := f.UnitName
 	if f.UnitShortName != nil {
@@ -61,23 +75,41 @@ func (f Formular) View_readTag(fieldName string, parent interface{}, args []inte
 
 func (f *Formular) PrepareUnit() *Formular {
 	var err error
-	f.Unit, err = UnitSQL.First(Unit{Id: f.UnitId})
+	f.unit, err = UnitSQL.First(Unit{Id: f.UnitId})
 	if err != nil {
 		revel.ERROR.Printf("Got error: %v", err.Error())
+		return f
 	}
+	f.unitReady = true
 	return f
 }
 
+func (f Formular) GetUnit() Unit {
+	if !f.unitReady {
+		panic("formular is not ready for method GetUnit: it's required to call PrepareUnit method, first")
+	}
+	return f.unit
+}
+
 func (f *Formular) PreparePerson() *Formular {
 	var err error
-	f.Person, err = PersonSQL.First(Person{EmpGUID: f.EmpGUID})
+	f.person, err = PersonSQL.First(Person{EmpGUID: f.EmpGUID})
 	if err != nil {
 		revel.ERROR.Printf("Got error: %v", err.Error())
+		return f
 	}
+	f.personReady = true
 	return f
 }
 
-func (f Formular) IsActive() bool {
+func (f Formular) GetPerson() Person {
+	if !f.personReady {
+		panic("formular is not ready for method GetPerson: it's required to call PreparePerson method, first")
+	}
+	return f.person
+}
+
+func (f *Formular) PrepareIsActive() *Formular {
 	now := extime.Now()
 
 	startIsGood := false
@@ -90,8 +122,24 @@ func (f Formular) IsActive() bool {
 	if f.EndDate == nil {
 		endIsGood = true
 	} else {
-		endIsGood = f.EndDate.UnixNano() + 3600 * 24 >= now.UnixNano()
+		endIsGood = f.EndDate.UnixNano()+24*3600*1000*1000*1000 >= now.UnixNano()
+	}
+
+	f.isActive = startIsGood && endIsGood
+	f.isActiveReady = true
+
+	return f
+}
+
+func (f Formular) IsActive() bool {
+	if !f.isActiveReady {
+		panic("formular is not ready for method IsActive: it's required to call PrepareIsReady method, first")
 	}
+	return f.isActive
+}
+
+type Formulars []Formular
 
-	return startIsGood && endIsGood
+func (formulars Formulars) GetPeople() (people People) {
+	return
 }

+ 27 - 2
person.go

@@ -21,10 +21,11 @@ type Person struct {
 	Phone2      *string `reform:"Phone2"      view:"readonly"`
 	Phone3      *string `reform:"Phone3"      view:"readonly"`
 
-	// for rendering:
-	Formulars []Formular
+	formulars      Formulars `reform:"-"`
+	formularsReady bool      `reform:"-"`
 }
 
+// TODO: Remove this "VIEW" from this model
 func (u Person) View_readTag(fieldName string, parent interface{}, args []interface{}) template.HTML {
 	if u.EmpGUID == 0 {
 		return template.HTML(fmt.Sprintf(`Не назначено`))
@@ -42,3 +43,27 @@ func (u Person) View_readTag(fieldName string, parent interface{}, args []interf
 
 	return template.HTML(fmt.Sprintf(`<a href="/asu/people/%v?fullscreen=true">%v</a>`, u.EmpGUID, description))
 }
+
+type People []Person
+
+func (people People) Deduplicate() (deduplicated People) {
+	personMap := map[int]*Person{}
+
+	for idx, person := range people {
+		personMap[person.EmpGUID] = &people[idx]
+	}
+
+	for _, person := range personMap {
+		deduplicated = append(deduplicated, *person)
+	}
+
+	return
+}
+
+func (people People) GetEmpGUIDs() (empGUIDs []int) {
+	for _, person := range people {
+		empGUIDs = append(empGUIDs, person.EmpGUID)
+	}
+
+	return
+}

+ 211 - 17
unit.go

@@ -2,31 +2,50 @@
 package asuModels
 
 import (
+	"database/sql"
 	"fmt"
+	"github.com/xaionaro-go/extime"
 	"html/template"
 )
 
 //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 *string `reform:"CreateOrderDate" view:"readonly"`
-	CloseOrderNo    *string `reform:"CloseOrderNo"    view:"readonly"`
-	CloseOrderDate  *string `reform:"CloseOrderDate"  view:"readonly"`
-	ChiefName       *string `reform:"ChiefName"       view:"readonly"`
-	PersNumber      *int    `reform:"PersNumber"      view:"readonly"`
-	Code            string  `reform:"Code"            view:"readonly"`
-	SortNumber      *string `reform:"SortNumber"      view:"readonly"`
-	ChiefTabN       *string `reform:"ChiefTabN"       view:"readonly"`
+	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      *string      `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 (sql Unit) ActiveOnly() *UnitScope {
+	return sql.Scope().ActiveOnly()
+}
+func (sql *UnitScope) ActiveOnly() *UnitScope {
+	return sql.Where("(CreateOrderDate IS NULL OR CreateOrderDate < NOW()) AND (CloseOrderDate IS NULL OR CloseOrderDate+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(`Не назначено`))
@@ -42,3 +61,178 @@ func (u Unit) View_readTag(fieldName string, parent interface{}, args []interfac
 
 	return template.HTML(fmt.Sprintf(`<a href="/asu/unitsByID/%v?fullscreen=true">%v — %v</a>`, u.Id, u.Code, name))
 }
+
+type Units []Unit
+
+func (units Units) calculateTree(strict bool) {
+	unitMap := map[int]*Unit{}
+
+	for idx, unit := range units {
+		unitMap[unit.Id] = &units[idx]
+	}
+
+	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{}), arg interface{}) {
+	f(unit, arg)
+
+	for _, child := range unit.GetChildrenPtrs() {
+		child.DoRecursive(f, arg)
+	}
+}
+
+func (units Units) DoRecursive(f func(*Unit, interface{}), arg interface{}) {
+	for _, unit := range units {
+		unit.DoRecursive(f, arg)
+	}
+}
+
+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
+	u.formulars, err = FormularSQL.Select(Formular{UnitId: u.Id})
+	if err != nil {
+		panic(err)
+	}
+
+	u.formularsReady = true
+	return u
+}
+
+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() Units {
+	for idx, _ := range units {
+		units[idx].PrepareFormulars()
+	}
+
+	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 PrepareIsReady method, first")
+	}
+	return u.isActive
+}
+
+func (u *Unit) PrepareChildrenTree() *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]
+		child.PrepareChildrenTree()
+
+		u.children = append(u.children, child)
+	}
+
+	u.childrenReady = true
+
+	return u
+}
+func (units Units) PrepareChildrenTree() Units {
+	for idx, _ := range units {
+		units[idx].PrepareChildrenTree()
+	}
+
+	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
+}