Commit de503827 by jhrabal

radegast

parent 6a7a102c
package com.jh.radegast.api;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -11,6 +10,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.jh.common.web.list.DefaultSorting;
......@@ -28,7 +28,6 @@ public class RatingApiController {
@Autowired
private RatingService service;
//paged endpoint
@RequestMapping(path = "ratings", method = RequestMethod.GET)
@DefaultSorting(field = "key", trend = SortTrend.DESCENDING)
public ResponseEntity<List<Rating>> filterRatings(/*Date from, Date to, */PagingInfo pagingInfo) {
......@@ -42,6 +41,9 @@ public class RatingApiController {
service.saveBulk(ratings);
}
//stats endpoint
@RequestMapping(path = "ratings/stats", method = RequestMethod.GET)
public @ResponseBody RatingsStats ratingsStats(/*Date from, Date to */) {
return service.calculateStats(new RatingsFilter());
}
}
package com.jh.radegast.api;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class RatingsStats {
private Long ratings;
private BigDecimal average;
private HashMap<Long, Long> values;
public RatingsStats() {
this.values = new LinkedHashMap<>();
ratings = 0L;
}
public RatingsStats(Long ratings, BigDecimal average, HashMap<Long, Long> values) {
super();
this.ratings = ratings;
this.values = values;
this.average = average;
}
public Long getRatings() {
return ratings;
}
public void setRatings(Long ratings) {
this.ratings = ratings;
}
public HashMap<Long, Long> getValues() {
return values;
}
public void setValues(HashMap<Long, Long> values) {
this.values = values;
}
public BigDecimal getAverage() {
return average;
}
public void setAverage(BigDecimal average) {
this.average = average;
}
}
package com.jh.radegast.model;
public class RatingStat {
private Long rating;
private Long count;
public RatingStat() {
}
public RatingStat(Long rating, Long count) {
super();
this.rating = rating;
this.count = count;
}
public Long getRating() {
return rating;
}
public void setRating(Long rating) {
this.rating = rating;
}
public Long getCount() {
return count;
}
public void setCount(Long count) {
this.count = count;
}
}
package com.jh.radegast.rating;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
......@@ -8,6 +9,7 @@ import java.util.Set;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.query.NativeQuery;
import org.springframework.stereotype.Repository;
import com.jh.common.jpa.AbstractHibernateRepository;
......@@ -15,6 +17,7 @@ import com.jh.common.web.list.Page;
import com.jh.common.web.list.PagingInfo;
import com.jh.radegast.api.RatingsFilter;
import com.jh.radegast.model.Rating;
import com.jh.radegast.model.RatingStat;
@Repository
......@@ -67,4 +70,38 @@ public class RatingRepository extends AbstractHibernateRepository {
}
public List<RatingStat> stats(RatingsFilter filter) {
StringBuilder sql = new StringBuilder("select rating, count(*) from rating where 1=1");
if (filter != null) {
if (filter.getFrom() != null) {
sql.append(" and key >= :from ");
}
if (filter.getTo() != null) {
sql.append(" and key <= :to ");
}
}
sql.append(" group by rating");
NativeQuery query = getSession().createNativeQuery(sql.toString());
if (filter != null) {
if (filter.getFrom() != null) {
query.setParameter("from", String.valueOf(filter.getFrom().getTime()));
}
if (filter.getTo() != null) {
query.setParameter("to", String.valueOf(filter.getTo().getTime()));
}
}
List<RatingStat> stats = new ArrayList<>();
List<Object[]> rows = query.list();
if (rows != null) {
for (Object[] row : rows) {
stats.add(new RatingStat(((Number) row[0]).longValue(), ((Number) row[1]).longValue()));
}
}
return stats;
}
}
package com.jh.radegast.rating;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
......@@ -12,10 +15,13 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.jh.common.utils.Utils;
import com.jh.common.web.list.Page;
import com.jh.common.web.list.PagingInfo;
import com.jh.radegast.api.RatingsFilter;
import com.jh.radegast.api.RatingsStats;
import com.jh.radegast.model.Rating;
import com.jh.radegast.model.RatingStat;
@Service
public class RatingService {
......@@ -69,4 +75,32 @@ public class RatingService {
return repo.filter(ratingsFilter);
}
@Transactional
public RatingsStats calculateStats(RatingsFilter filter) {
Long total = 0L;
Long value = 0L;
BigDecimal average = BigDecimal.ZERO;
HashMap<Long, Long> ratings = new LinkedHashMap<>();
for (int i = 10; i > 0; i--) {
ratings.put(Long.valueOf(i), 0L);
}
List<RatingStat> list = repo.stats(filter);
if (list != null) {
for (RatingStat rs : list) {
ratings.put(rs.getRating(), rs.getCount());
total += rs.getCount();
value += rs.getRating() * rs.getCount();
}
}
if (total > 0) {
average = Utils.divide(new BigDecimal(value), new BigDecimal(total), 2);
}
return new RatingsStats(total, average, ratings);
}
}
......@@ -9,10 +9,7 @@ class UserInfo extends Component {
render() {
let { user, name } = this.props;
if (!user) {
user = ( window.cfg && window.cfg.user ) || {};
}
if (!name) {
name = window.cfg && window.cfg.unit && window.cfg.unit.name;
user = ( window.cfg && window.cfg.principal ) || {};
}
let img = user.avatar || require("./user-placeholder.png");
......@@ -21,11 +18,7 @@ class UserInfo extends Component {
<div className="user-placeholder">
<img src={ img } />
<br/>
<span className="user-name">{ name || (user.firstName + " " + user.lastName) }</span>
<br/>
<span>{ user.email || "" }</span>
<br/>
<span>{ user.position || "" }</span>
<span className="user-name">{ user && (user.firstName + " " + user.lastName) }</span>
</div>
);
......
......@@ -14,7 +14,6 @@ export default () => new Promise((resolve) => {
global._transitions = true; //FIXME
//set colors
let chartColors = ["4ec3e0", "1287ed", "929ba3"]; //, "678096", "5beeff"];
//let pal = palette(chartColors, 17);
......
......@@ -22,8 +22,8 @@ export default injectIntl((props) => {
let menuItems = [
{
id: 'home',
route: '/home',
id: 'stats',
route: '/stats',
title: intl.formatMessage(messages.homeMenu),
icon: icons.reports
}, {
......
......@@ -127,6 +127,10 @@
color: #009A00;
}
.list-row-data .main-value.neutral-amount {
color: #f5ab00;
}
.list-row-data .main-value.minus-amount {
color: #FF0000;
}
......
......@@ -18,31 +18,19 @@ let initialState = {
status: 'pending',
fresh: true,
paging: {
pageSize: 7
pageSize: 15
},
data: []
},
summary: {
stats: {
status: 'pending',
},
cashflow: {
status: 'pending',
fresh: true,
data: {
empty: true
}
},
statuses: {
status: 'pending',
fresh: true,
data: {
income: {},
outcome: {},
data: {},
empty: true
total: 0,
values: {
}
}
},
};
let reducer = createReducer(initialState);
......@@ -55,97 +43,41 @@ let api = reduxList("home/dashboard", {
});
//export actions
export const fetchDashboardRecordsAction = api.actions.fetchList;
export const fetchRatingsAction = api.actions.fetchList;
//TODO
export const selector = settingsSelector((state, props) => {
let home = safe(state.get("home"));
let periodParams = safe(state.getIn(["params", "period"]));
let list = api.selector(state, props);
return { ...home, periodParams };
return home;
});
export function fetchSummary(unitId, from, to, dateType) {
return {
type: 'home/FETCH_SUMMARY',
payload: backendRequest('/api/' + unitId + '/home/dashboard', 'GET', { params: { from, to } })
};
};
reducer.handleAction('home/FETCH_SUMMARY_PENDING', (state, action) =>
state.setIn(["summary", "status"], "pending")
);
reducer.handleAction('home/FETCH_SUMMARY_FULFILLED', (state, action) =>
state
.setIn(["summary", "status"], "success")
.setIn(["summary", "data"], action.payload.body)
.deleteIn(["summary", "error"])
);
reducer.handleAction('home/FETCH_SUMMARY_REJECTED', (state, action) =>
state.setIn(["summary", "status"], "failed").deleteIn(["summary", "data"]).setIn(["summary", "error"], true)
);
export function fetchCashflow(unitId, from, to, dateType) {
export function fetchStatsAction(unitId, from, to, dateType) {
return {
type: 'home/FETCH_CASHFLOW',
payload: backendRequest('/api/' + unitId + '/home/cashflow', 'GET', { params: { from, to, dateType } })
type: 'home/FETCH_STATS',
payload: backendRequest('/api/ratings/stats', 'GET', { params: { from, to } })
};
};
reducer.handleAction('home/FETCH_CASHFLOW_PENDING', (state, action) =>
state.setIn(["cashflow", "status"], "pending")
reducer.handleAction('home/FETCH_STATS_PENDING', (state, action) =>
state.setIn(["stats", "status"], "pending")
);
reducer.handleAction('home/FETCH_CASHFLOW_FULFILLED', (state, action) =>
reducer.handleAction('home/FETCH_STATS_FULFILLED', (state, action) =>
state
.withMutations(s => {
let b = action.payload.body;
s = s.setIn(["cashflow", "data"], b.data);
s = s.setIn(["cashflow", "labels"], b.labels);
s = s.setIn(["cashflow", "params"], b.params);
s = s.setIn(["cashflow", "currency"], b.currency);
s = s.setIn(["cashflow", "currencySymbol"], b.currencySymbol);
s = s.deleteIn(["cashflow", "error"]);
return s;
})
.setIn(["cashflow", "status"], "success")
.setIn(["stats", "status"], "success")
.setIn(["stats", "data"], action.payload.body)
.deleteIn(["stats", "error"])
);
reducer.handleAction('home/FETCH_CASHFLOW_REJECTED', (state, action) =>
state.setIn(["cashflow", "status"], "failed").setIn(["cashflow", "error"], true)
reducer.handleAction('home/FETCH_STATS_REJECTED', (state, action) =>
state.setIn(["stats", "status"], "failed").deleteIn(["stats", "data"]).setIn(["stats", "error"], true)
);
export function fetchStatuses(unitId, from, to, dateType) {
return {
type: 'home/FETCH_STATUSES',
payload: backendRequest('/api/' + unitId + '/home/statuses', 'GET', { params: { from, to, dateType } })
};
};
reducer.handleAction('home/FETCH_STATUSES_PENDING', (state, action) =>
state.setIn(["statuses", "status"], "pending")
);
reducer.handleAction('home/FETCH_STATUSES_FULFILLED', (state, action) =>
state
.withMutations(s => {
s = s.set("statuses", fromJS(action.payload.body));
s = s.setIn(["statuses", "status"], "success");
s = s.deleteIn(["statuses", "error"]);
return s;
})
);
reducer.handleAction('home/FETCH_STATUSES_REJECTED', (state, action) =>
state.setIn(["statuses", "status"], "failed").setIn(["statuses", "error"], true)
);
//export reducer
export default reducer.export();
//TODO transform summary response
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment