Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курсач.docx
Скачиваний:
10
Добавлен:
20.04.2015
Размер:
692.58 Кб
Скачать

5. Тестирование дневника расходов и поступлений

  1. Выполнение действий 4.1 и 4.2. Переход в дневник. Отображается сегодняшняя дата: 9.03.2015. Отображается действие 4.1, баланс: 1000, количество: 1. Смена даты на 10.03.2015. Отображается действие 3.2, баланс: 500, количество: 1.

  2. Добавление платежа – сумма: -200, категория: «Eat». Платёж успешно добавлен, отображается баланс – 300, количество: 2.

6. Тестирование списка долгов и списка выплат

  1. Переход на страницу списка долгов. Добавление долга – дата: 10.03.2015, окончание: 10.03.2016, сумма: 100000, сумма выплаты: 1000, частота выплат: 1 месяц, категория: «Relax». Долг успешно добавлен и отображён в списке, также успешно добавлены и отображены 12 выплат суммой по 1000.

  2. Удаление долга – после нажатии кнопки удаления долг был успешно удалён.

7. Тестирование графика изменения баланса

Выполненение действий 4.1, 4.2, 5.2. Добавление долга – дата: 10.03.2015, окончание 10.03.2016, сумма: 10000, сумма выплаты: 2000, частота выплат: 1 день, категория: «Auto». На странице графика выбираем диапазон отображается следующая динамика баланса: 800, 10300, 8300, 6300, 4300, 2300.

8. Тестирование графика сравнения дней по сумме финансовых операций

Выполнение действий из пункта 7. Полученный график: 800, 9500, -2000, -2000, -2000, -2000.

9. Тестирование графика сравнения дней по сумме задолженностей

Выполнение действий 7.

10. Тестирование графика сравнения категорий по сумме финансовых операций

Выполнение действий 4.1, 4.2, 5.2. Полученный график: 1000, -500, -200.

Заключение

В ходе выполнения курсовой работы были использованы гибкие методологии разработки продукта, язык программирования – Java. На выходе получен продукт, удовлетворяющий потребности заказчика.

Выбранная методология позволила сформировать жесткие сроки на создание функционала программы, а также обеспечить достаточное количество времени на каждую итерацию. Причём все заданные функции выполнены в срок, без каких-либо накладок и выбора наиболее и наименее важных функций.

Процесс конструирования позволил избежать накладок при работе приложения(например, введения некорректных данных и “падения” программы), а также доработать диалоговые окна для взаимодействия с пользователем и протестировать корректность работы БД с помощью тестовых данных. Соответственно данные действия повысили качество программы.

Приложение 1. Код программы

BalanceBacking.java

package ru.ulstu.secretary.chart;

import java.util.Date;

import javax.faces.view.ViewScoped;

import javax.inject.Inject;

import javax.inject.Named;

import ru.ulstu.secretary.db.ActionByDateService;

@Named

@ViewScoped

public class BalanceBacking extends DateChartBacking {

private static final long serialVersionUID = 8470304964338154695L;

@Inject

private ActionByDateService actionByDateService;

protected double getNextY(double y, Date x) {

return y + actionByDateService.getList(x).stream().mapToDouble(task -> task.getBalance()).sum();

}

@Override

protected String getRedirect() {

return "diary";

}

}

CategoryBalanceBacking.cs

package ru.ulstu.secretary.chart;

import javax.faces.view.ViewScoped;

import javax.inject.Inject;

import javax.inject.Named;

import ru.ulstu.secretary.db.CategoryService;

import ru.ulstu.secretary.db.TaskByCategoryService;

import ru.ulstu.secretary.entity.Category;

@Named

@ViewScoped

public class CategoryBalanceBacking extends ChartBacking<Category> {

private static final long serialVersionUID = 1L;

@Inject

private CategoryService categoryService;

@Inject

private TaskByCategoryService taskByCategoryService;

@Override

protected Iterable<Category> getRangeOfX() {

return categoryService.getList();

}

@Override

protected double getNextY(double y, Category x) {

return taskByCategoryService.getList(x).stream().mapToDouble(task -> task.getBalance()).sum();

}

@Override

protected String getRedirect() {

return "";

}

@Override

protected void prepareRedirect(Category category) {

}

}

ChartBacking.java

package ru.ulstu.secretary.chart;

import java.io.Serializable;

import org.primefaces.model.chart.BarChartModel;

import org.primefaces.model.chart.ChartSeries;

public abstract class ChartBacking<X> implements Serializable {

private static final long serialVersionUID = 5722395681760535076L;

protected abstract Iterable<X> getRangeOfX();

protected abstract double getNextY(double y, X x);

public BarChartModel getModel() {

BarChartModel model = new BarChartModel();

ChartSeries series = new ChartSeries();

double y = 0;

for (X x : getRangeOfX()) {

y = getNextY(y, x);

series.set(x, y);

}

model.addSeries(series);

return model;

}

public X getMin() {

X result = null;

double resultValue = Double.MAX_VALUE;

double y = 0;

for (X x : getRangeOfX()) {

y = getNextY(y, x);

if (y <= resultValue) {

resultValue = y;

result = x;

}

}

return result;

}

public X getMax() {

X result = null;

double resultValue = Double.MIN_VALUE;

double y = 0;

for (X x : getRangeOfX()) {

y = getNextY(y, x);

if (y >= resultValue) {

resultValue = y;

result = x;

}

}

return result;

}

public double getMinValue() {

double resultValue = Double.MAX_VALUE;

double y = 0;

for (X x : getRangeOfX()) {

y = getNextY(y, x);

if (y <= resultValue) {

resultValue = y;

}

}

return resultValue;

}

public double getMaxValue() {

double resultValue = Double.MIN_VALUE;

double y = 0;

for (X x : getRangeOfX()) {

y = getNextY(y, x);

if (y >= resultValue) {

resultValue = y;

}

}

if (resultValue == Double.MIN_VALUE) {

return 0;

}

return resultValue;

}

protected abstract void prepareRedirect(X selected);

protected abstract String getRedirect();

public String redirect(X selected) {

prepareRedirect(selected);

String redirect = getRedirect() + "?faces-redirect=true";

return redirect;

}

}

DateChartBacking.java

package ru.ulstu.secretary.chart;

import java.util.Calendar;

import java.util.Date;

import java.util.GregorianCalendar;

import java.util.concurrent.TimeUnit;

import java.util.stream.IntStream;

import javax.annotation.PostConstruct;

import javax.inject.Inject;

import ru.ulstu.secretary.grid.DateBacking;

import ru.ulstu.secretary.utils.DateUtil;

public abstract class DateChartBacking extends ChartBacking<Date> {

private static final long serialVersionUID = -5928036826842490016L;

private Date from;

private Date to;

@Inject

private DateBacking dateBacking;

@PostConstruct

private void init() {

from = DateUtil.getToday();

to = DateUtil.getToday();

change(-1, 1);

}

@Override

protected Iterable<Date> getRangeOfX() {

long dayCount = TimeUnit.DAYS.convert(to.getTime() - from.getTime(), TimeUnit.MILLISECONDS) + 1;

return () -> IntStream.iterate(0, i -> i + 1).limit(dayCount).mapToObj(i -> {

Calendar calendar = new GregorianCalendar();

calendar.setTime(from);

calendar.add(Calendar.DATE, i);

return calendar.getTime();

}).iterator();

}

public Date getFrom() {

return from;

}

public void setFrom(Date from) {

this.from = from;

}

public Date getTo() {

return to;

}

public void setTo(Date to) {

this.to = to;

}

public void change(int left, int right) {

Calendar calendar = new GregorianCalendar();

calendar.setTime(from);

calendar.add(Calendar.DATE, left);

from = calendar.getTime();

calendar.setTime(to);

calendar.add(Calendar.DATE, right);

to = calendar.getTime();

}

@Override

protected void prepareRedirect(Date selected) {

dateBacking.setDate(selected);

}

}

DayBacking.java

package ru.ulstu.secretary.chart;

import java.util.Date;

import javax.faces.view.ViewScoped;

import javax.inject.Inject;

import javax.inject.Named;

import ru.ulstu.secretary.db.ActionByDateService;

@Named

@ViewScoped

public class DayBacking extends DateChartBacking {

private static final long serialVersionUID = 8470304964338154695L;

@Inject

private ActionByDateService actionByDateService;

protected double getNextY(double y, Date x) {

return actionByDateService.getList(x).stream().mapToDouble(task -> task.getBalance()).sum();

}

@Override

protected String getRedirect() {

return "diary";

}

}

UnpaidBacking.java

package ru.ulstu.secretary.chart;

import java.util.Date;

import javax.faces.view.ViewScoped;

import javax.inject.Inject;

import javax.inject.Named;

import ru.ulstu.secretary.db.EntityService;

import ru.ulstu.secretary.entity.Debt;

@Named

@ViewScoped

public class UnpaidBacking extends DateChartBacking {

private static final long serialVersionUID = 981680502855109121L;

@Inject

private EntityService entityService;

@Override

protected double getNextY(double y, Date x) {

return entityService.getList(Debt.class).stream().mapToDouble(debt -> debt.getUnpaid(x)).sum();

}

@Override

protected String getRedirect() {

return "diary";

}

}

CriteriaService.java

package ru.ulstu.secretary.criteria;

import java.util.Collection;

import javax.annotation.PostConstruct;

import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

import javax.persistence.criteria.CriteriaBuilder;

import javax.persistence.criteria.CriteriaQuery;

import javax.persistence.criteria.Predicate;

import javax.persistence.criteria.Root;

public abstract class CriteriaService<Entity> {

@PersistenceContext

private EntityManager entityManager;

private CriteriaBuilder builder;

private CriteriaQuery<Entity> query;

private Root<Entity> root;

@PostConstruct

private void initCriteriaService() {

builder = entityManager.getCriteriaBuilder();

query = builder.createQuery(getType());

root = query.from(getType());

}

protected abstract Class<Entity> getType();

protected CriteriaBuilder getBuilder() {

return builder;

}

protected CriteriaQuery<Entity> getQuery() {

return query;

}

protected Root<Entity> getRoot() {

return root;

}

protected Collection<Entity> getList(Predicate restriction) {

query.where(restriction);

return entityManager.createQuery(query).getResultList();

}

}

PropertyCriteriaService.java

package ru.ulstu.secretary.criteria;

import java.util.Collection;

public abstract class PropertyCriteriaService<Entity, Property> extends CriteriaService<Entity> {

public Collection<Entity> getList(Property property) {

return getList(getBuilder().equal(getRoot().get(getProperty()), property));

}

protected abstract String getProperty();

}

RangeCriteriaService.java

package ru.ulstu.secretary.criteria;

import java.util.Collection;

public abstract class RangeCriteriaService<Entity, Property extends Comparable<Property>> extends CriteriaService<Entity> {

public Collection<Entity> getAll(Property from, Property to) {

return getList(getBuilder().between(getRoot().get(getProperty()), from, to));

}

protected abstract String getProperty();

}

UpperLimitCriteriaService.java

package ru.ulstu.secretary.criteria;

import java.util.Collection;

public abstract class UpperLimitCriteriaService<X extends Comparable<X>, Y> extends CriteriaService<Y> {

public Collection<Y> getList(X x) {

return getList(getBuilder().lessThanOrEqualTo(getRoot().get(getProperty()), x));

}

protected abstract String getProperty();

}

ActionByDateService.java

package ru.ulstu.secretary.db;

import java.util.Date;

import javax.ejb.Stateless;

import ru.ulstu.secretary.criteria.PropertyCriteriaService;

import ru.ulstu.secretary.entity.Action;

@Stateless

public class ActionByDateService extends PropertyCriteriaService<Action, Date> {

@Override

protected String getProperty() {

return "date";

}

@Override

protected Class<Action> getType() {

return Action.class;

}

}

CategoryService.java

package ru.ulstu.secretary.db;

import java.util.Arrays;

import javax.ejb.Stateless;

import javax.inject.Named;

import ru.ulstu.secretary.entity.Category;

@Named

@Stateless

public class CategoryService {

public Iterable<Category> getList() {

return Arrays.asList(Category.values());

}

}

DebtByDateService.java

package ru.ulstu.secretary.db;

import java.util.Date;

import javax.ejb.Stateless;

import ru.ulstu.secretary.criteria.UpperLimitCriteriaService;

import ru.ulstu.secretary.entity.Debt;

@Stateless

public class DebtByDateService extends UpperLimitCriteriaService<Date, Debt> {

@Override

protected String getProperty() {

return "date";

}

@Override

protected Class<Debt> getType() {

return Debt.class;

}

}

EntityService.java

package ru.ulstu.secretary.db;

import java.util.Collection;

import javax.ejb.Stateless;

import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

import javax.persistence.criteria.CriteriaBuilder;

import javax.persistence.criteria.CriteriaQuery;

@Stateless

public class EntityService {

@PersistenceContext

private EntityManager entityManager;

public <T> Collection<T> getList(Class<T> type) {

CriteriaBuilder builder = entityManager.getCriteriaBuilder();

CriteriaQuery<T> query = builder.createQuery(type);

query.from(type);

return entityManager.createQuery(query).getResultList();

}

public <T> T save(T entity) {

return entityManager.merge(entity);

}

public <T> void remove(T entity) {

entity = entityManager.merge(entity);

entityManager.remove(entity);

}

}

PayByDateService.java

package ru.ulstu.secretary.db;

import java.util.Date;

import javax.ejb.Stateless;

import ru.ulstu.secretary.criteria.PropertyCriteriaService;

import ru.ulstu.secretary.entity.Pay;

@Stateless

public class PayByDateService extends PropertyCriteriaService<Pay, Date> {

@Override

protected String getProperty() {

return "date";

}

@Override

protected Class<Pay> getType() {

return Pay.class;

}

}

RepayByDateService.java

package ru.ulstu.secretary.db;

import java.util.Date;

import javax.ejb.Stateless;

import ru.ulstu.secretary.criteria.PropertyCriteriaService;

import ru.ulstu.secretary.entity.Repay;

@Stateless

public class RepayByDateService extends PropertyCriteriaService<Repay, Date> {

@Override

protected String getProperty() {

return "date";

}

@Override

protected Class<Repay> getType() {

return Repay.class;

}

}

TaskByCategoryService.java

package ru.ulstu.secretary.db;

import javax.ejb.Stateless;

import ru.ulstu.secretary.criteria.PropertyCriteriaService;

import ru.ulstu.secretary.entity.Category;

import ru.ulstu.secretary.entity.Task;

@Stateless

public class TaskByCategoryService extends PropertyCriteriaService<Task, Category> {

@Override

protected String getProperty() {

return "category";

}

@Override

protected Class<Task> getType() {

return Task.class;

}

}

TaskByDateService.java

package ru.ulstu.secretary.db;

import java.util.Date;

import javax.ejb.Stateless;

import ru.ulstu.secretary.criteria.PropertyCriteriaService;

import ru.ulstu.secretary.entity.Task;

@Stateless

public class TaskByDateService extends PropertyCriteriaService<Task, Date> {

@Override

protected String getProperty() {

return "date";

}

@Override

protected Class<Task> getType() {

return Task.class;

}

}

UnitService.java

package ru.ulstu.secretary.db;

import javax.ejb.Stateless;

import javax.inject.Named;

import ru.ulstu.secretary.entity.Unit;

@Named

@Stateless

public class UnitService {

public Unit[] getList() {

return Unit.values();

}

}

Action.java

package ru.ulstu.secretary.entity;

import java.util.Date;

import javax.persistence.Entity;

@Entity

public class Action extends BaseEntity {

private Date date;

private Double balance;

private String comment;

private Category category;

private boolean complete;

public Date getDate() {

return date;

}

public void setDate(Date date) {

this.date = date;

}

public Double getBalance() {

return balance;

}

public void setBalance(Double money) {

this.balance = money;

}

public String getComment() {

return comment;

}

public void setComment(String comment) {

this.comment = comment;

}

public Category getCategory() {

return category;

}

public void setCategory(Category category) {

this.category = category;

}

public boolean isComplete() {

return complete;

}

public void setComplete(boolean complete) {

this.complete = complete;

}

}

BaseEntity.java

package ru.ulstu.secretary.entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.MappedSuperclass;

@MappedSuperclass

public class BaseEntity {

@Id

@GeneratedValue

private int id;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

}

Category.java

package ru.ulstu.secretary.entity;

public enum Category {

AUTO("auto"),

HOME("home");

private final String i18n;

private Category(String i18n) {

this.i18n = i18n;

}

public String toString() {

return i18n;

}

}

Debt.java

package ru.ulstu.secretary.entity;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

import javax.persistence.CascadeType;

import javax.persistence.Entity;

import javax.persistence.FetchType;

import javax.persistence.Inheritance;

import javax.persistence.InheritanceType;

import javax.persistence.OneToMany;

@Entity

@Inheritance(strategy = InheritanceType.JOINED)

public class Debt extends Action {

private Date deadline;

private Double repay;

private Integer frequency;

private Unit unit;

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)

private List<Repay> repays;

public Debt() {

unit = Unit.DAY;

repays = new ArrayList<>();

}

public Date getDeadline() {

return deadline;

}

public void setDeadline(Date deadline) {

this.deadline = deadline;

}

public Double getRepay() {

return repay;

}

public void setRepay(Double repay) {

this.repay = repay;

}

public Integer getFrequency() {

return frequency;

}

public void setFrequency(Integer frequency) {

this.frequency = frequency;

}

public Unit getUnit() {

return unit;

}

public void setUnit(Unit unit) {

this.unit = unit;

}

public List<Repay> getRepays() {

return repays;

}

public void setRepays(List<Repay> repays) {

this.repays = repays;

}

public double getUnpaid(Date moment) {

if (moment.before(getDate())) {

return 0;

}

double sum = repays.stream().filter(repay -> !repay.getDate().after(moment)).mapToDouble(repay -> repay.getBalance()).sum();

return Math.max(0, getBalance() + sum);

}

}

Pay.java

package ru.ulstu.secretary.entity;

import javax.persistence.Entity;

import javax.persistence.Inheritance;

import javax.persistence.InheritanceType;

@Entity

@Inheritance(strategy = InheritanceType.JOINED)

public class Pay extends Task {}

Repay.java

package ru.ulstu.secretary.entity;

import javax.persistence.CascadeType;

import javax.persistence.Entity;

import javax.persistence.Inheritance;

import javax.persistence.InheritanceType;

import javax.persistence.ManyToOne;

@Entity

@Inheritance(strategy = InheritanceType.JOINED)

public class Repay extends Task {

@ManyToOne(cascade = CascadeType.ALL)

private Debt debt;

public Debt getDebt() {

return debt;

}

public void setDebt(Debt debt) {

this.debt = debt;

}

}

Task.java

package ru.ulstu.secretary.entity;

import javax.persistence.Entity;

import javax.persistence.Inheritance;

import javax.persistence.InheritanceType;

@Entity

@Inheritance(strategy = InheritanceType.JOINED)

public class Task extends Action {}

Unit.java

package ru.ulstu.secretary.entity;

import java.util.Calendar;

public enum Unit {

YEAR("year", Calendar.YEAR),

MONTH("month", Calendar.MONTH),

WEEK("week", Calendar.WEEK_OF_MONTH),

DAY("day", Calendar.DAY_OF_WEEK);

private final String i18n;

private final int code;

private Unit(String i18n, int code) {

this.i18n = i18n;

this.code = code;

}

public int getCode() {

return code;

}

public String toString() {

return i18n;

}

}

DateBacking.java

package ru.ulstu.secretary.grid;

import java.io.Serializable;

import java.util.Date;

import javax.annotation.PostConstruct;

import javax.enterprise.context.SessionScoped;

import javax.inject.Named;

import ru.ulstu.secretary.utils.DateUtil;

@Named

@SessionScoped

public class DateBacking implements Serializable {

private static final long serialVersionUID = -7664901585738595118L;

private Date date;

@PostConstruct

private void init() {

date = DateUtil.getToday();

}

public Date getDate() {

return date;

}

public void setDate(Date date) {

this.date = date;

}

}

DebtBacking.java

package ru.ulstu.secretary.grid;

import java.util.Calendar;

import java.util.GregorianCalendar;

import javax.faces.view.ViewScoped;

import javax.inject.Named;

import ru.ulstu.secretary.entity.Debt;

import ru.ulstu.secretary.entity.Repay;

import ru.ulstu.secretary.utils.DateUtil;

@Named

@ViewScoped

public class DebtBacking extends GridBacking<Debt> {

private static final long serialVersionUID = 714120325390373523L;

private Debt debt;

@Override

protected Debt getNewBlank() {

Debt debt = new Debt();

debt.setDate(DateUtil.getToday());

return debt;

}

@Override

protected Class<Debt> getType() {

return Debt.class;

}

@Override

public void save() throws Exception {

Calendar calendar = new GregorianCalendar();

calendar.setTime(getBlank().getDate());

while (true) {

calendar.add(getBlank().getUnit().getCode(), 1);

if (calendar.getTime().after(getBlank().getDeadline())) {

break;

}

Repay repay = new Repay();

repay.setDate(calendar.getTime());

repay.setCategory(getBlank().getCategory());

repay.setBalance(-getBlank().getRepay());

getBlank().getRepays().add(repay);

}

debt = getBlank();

super.save();

}

public Debt getDebt() {

return debt;

}

public void setDebt(Debt debt) {

this.debt = debt;

}

}

DiaryPayBacking.java

package ru.ulstu.secretary.grid;

import java.util.Collection;

import javax.faces.view.ViewScoped;

import javax.inject.Inject;

import javax.inject.Named;

import ru.ulstu.secretary.db.ActionByDateService;

import ru.ulstu.secretary.db.PayByDateService;

import ru.ulstu.secretary.entity.Pay;

@Named

@ViewScoped

public class DiaryPayBacking extends GridBacking<Pay> {

private static final long serialVersionUID = -3370333139341916306L;

@Inject

private DateBacking dateBacking;

@Inject

private ActionByDateService actionByDateService;

@Inject

private PayByDateService payByDateService;

@Override

protected Class<Pay> getType() {

return Pay.class;

}

@Override

protected Pay getNewBlank() {

Pay pay = new Pay();

pay.setDate(dateBacking.getDate());

return pay;

}

@Override

public Collection<Pay> getList() {

return payByDateService.getList(dateBacking.getDate());

}

public double getBalance() {

return actionByDateService.getList(dateBacking.getDate()).stream().mapToDouble(task -> task.getBalance()).sum();

}

}

DiaryRepayBacking.java

package ru.ulstu.secretary.grid;

import java.util.Collection;

import javax.faces.view.ViewScoped;

import javax.inject.Inject;

import javax.inject.Named;

import ru.ulstu.secretary.db.RepayByDateService;

import ru.ulstu.secretary.entity.Repay;

@Named

@ViewScoped

public class DiaryRepayBacking extends GridBacking<Repay> {

private static final long serialVersionUID = 8966176107954231754L;

@Inject

private DateBacking dateBacking;

@Inject

private RepayByDateService repayByDateService;

@Override

protected Class<Repay> getType() {

return Repay.class;

}

public Collection<Repay> getList() {

return repayByDateService.getList(dateBacking.getDate());

}

}

GridBacking.java

package ru.ulstu.secretary.grid;

import java.io.Serializable;

import java.util.Collection;

import javax.annotation.PostConstruct;

import javax.inject.Inject;

import ru.ulstu.secretary.db.EntityService;

public abstract class GridBacking<Entity> implements Serializable {

private static final long serialVersionUID = -2639437488394357753L;

@Inject

private EntityService entityService;

private Entity blank;

@PostConstruct

private void init() throws Exception {

blank = getNewBlank();

}

protected abstract Class<Entity> getType();

protected Entity getNewBlank() throws Exception {

return getType().getConstructor().newInstance();

}

public Collection<Entity> getList() {

return entityService.getList(getType());

}

public Entity getBlank() {

return blank;

}

public void save() throws Exception {

entityService.save(blank);

blank = getNewBlank();

}

public void remove(Entity obj) {

entityService.remove(obj);

}

}

PayBacking.java

package ru.ulstu.secretary.grid;

import javax.faces.view.ViewScoped;

import javax.inject.Named;

import ru.ulstu.secretary.entity.Pay;

import static ru.ulstu.secretary.utils.DateUtil.getToday;

@Named

@ViewScoped

public class PayBacking extends GridBacking<Pay> {

private static final long serialVersionUID = -520158973748994729L;

@Override

protected Class<Pay> getType() {

return Pay.class;

}

protected Pay getNewBlank() {

Pay pay = new Pay();

pay.setDate(getToday());

return pay;

}

public int getCount() {

return getList().size();

}

public double getBalance() {

return getList().stream().mapToDouble(pay -> pay.getBalance()).sum();

}

}

RepayBacking.java

package ru.ulstu.secretary.grid;

import java.util.Collection;

import javax.faces.view.ViewScoped;

import javax.inject.Inject;

import javax.inject.Named;

import ru.ulstu.secretary.entity.Repay;

@Named

@ViewScoped

public class RepayBacking extends GridBacking<Repay> {

private static final long serialVersionUID = -5042825198701507477L;

@Inject

private DebtBacking debtBacking;

@Override

protected Class<Repay> getType() {

return Repay.class;

}

@Override

public Collection<Repay> getList() {

return debtBacking.getDebt() == null ? null : debtBacking.getDebt().getRepays();

}

}

TodayBacking.java

package ru.ulstu.secretary.grid;

import java.io.Serializable;

import javax.faces.view.ViewScoped;

import javax.inject.Inject;

import javax.inject.Named;

import ru.ulstu.secretary.db.TaskByDateService;

import ru.ulstu.secretary.utils.DateUtil;

@Named

@ViewScoped

public class TodayBacking implements Serializable {

private static final long serialVersionUID = -6983619217861517215L;

@Inject

private TaskByDateService taskByDateService;

public int getCount() {

return taskByDateService.getList(DateUtil.getToday()).size();

}

}

DateUtil.java

package ru.ulstu.secretary.utils;

import java.util.Calendar;

import java.util.Date;

import java.util.GregorianCalendar;

public class DateUtil {

public static Date getToday() {

Calendar calendar = new GregorianCalendar();

calendar.set(Calendar.HOUR_OF_DAY, 0);

calendar.set(Calendar.MINUTE, 0);

calendar.set(Calendar.SECOND, 0);

calendar.set(Calendar.MILLISECOND, 0);

return calendar.getTime();

}

}

Balance.xhtml

<ui:composition template="/WEB-INF/tpl/base.xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:s="http://java.sun.com/jsf/composite/secretary">

<ui:define name="title">#{i18n.balance}</ui:define>

<ui:define name="body">

<s:chart backing="#{balanceBacking}"/>

</ui:define>

</ui:composition>

Category.xhtml

<ui:composition template="/WEB-INF/tpl/base.xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:s="http://java.sun.com/jsf/composite/secretary">

<ui:define name="title">#{i18n.category}</ui:define>

<ui:define name="body">

<s:chart backing="#{categoryBalanceBacking}" hasPeriod="false"/>

</ui:define>

</ui:composition>

Day.xhtml

<ui:composition template="/WEB-INF/tpl/base.xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:s="http://java.sun.com/jsf/composite/secretary">

<ui:define name="title">#{i18n.day}</ui:define>

<ui:define name="body">

<s:chart backing="#{dayBacking}"/>

</ui:define>

</ui:composition>

Debt.xhtml

<ui:composition template="/WEB-INF/tpl/base.xhtml" xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:a="http://xmlns.jcp.org/jsf/passthrough" xmlns:s="http://java.sun.com/jsf/composite/secretary">

<ui:define name="title">Debt</ui:define>

<ui:define name="body">

<s:grid name="debt" backing="#{debtBacking}"/>

<s:grid name="repay" backing="#{repayBacking}" editable="false"/>

</ui:define>

</ui:composition>

Diary.xhtml

<ui:composition template="/WEB-INF/tpl/base.xhtml" xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:a="http://xmlns.jcp.org/jsf/passthrough" xmlns:s="http://java.sun.com/jsf/composite/secretary">

<ui:define name="title">#{i18n.diary}</ui:define>

<ui:define name="body">

<div class="panel panel-info">

<div class="panel-heading"><span class="glyphicon glyphicon-calendar"/> #{i18n.date}</div>

<div class="panel-body">

<div class="form-inline">

<h:inputText styleClass="form-control" value="#{dateBacking.date}">

<f:convertDateTime pattern="yyyy-MM-dd"/>

</h:inputText>

<h:commandButton styleClass="btn btn-primary" value="#{i18n.see}"/>

</div>

</div>

</div>

<s:grid name="diary" backing="#{diaryPayBacking}"/>

<s:grid name="repay" backing="#{diaryRepayBacking}" editable="false"/>

<div class="panel panel-info">

<div class="panel-heading"><span class="glyphicon glyphicon-ok"/> #{i18n.total}</div>

<div class="panel-body">

<p><strong>#{i18n.balance}</strong>: #{diaryPayBacking.balance}</p>

</div>

</div>

</ui:define>

</ui:composition>

Pay.xhtml

<ui:composition template="/WEB-INF/tpl/base.xhtml" xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:s="http://java.sun.com/jsf/composite/secretary">

<ui:define name="title">#{i18n.pay}</ui:define>

<ui:define name="body">

<s:grid name="pay" backing="#{payBacking}"/>

<div class="panel panel-info">

<div class="panel-heading"><span class="glyphicon glyphicon-ok"/> #{i18n.total}</div>

<div class="panel-body">

<p><strong>#{i18n.count}</strong>: #{payBacking.count}</p>

</div>

</div>

</ui:define>

</ui:composition>

Unpaid.xhtml

<ui:composition template="/WEB-INF/tpl/base.xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:s="http://java.sun.com/jsf/composite/secretary">

<ui:define name="title">#{i18n.unpaid}</ui:define>

<ui:define name="body">

<s:chart backing="#{unpaidBacking}"/>

</ui:define>

</ui:composition>

Chart.xhtml

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://java.sun.com/jsf/composite" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core">

<c:interface>

<c:attribute name="backing"/>

<c:attribute name="hasPeriod" default="true"/>

</c:interface>

<c:implementation>

<ui:fragment rendered="#{cc.attrs.hasPeriod}">

<div class="panel panel-info">

<div class="panel-heading"><span class="glyphicon glyphicon-calendar"/> #{i18n.date}</div>

<div class="panel-body">

<div class="form-inline">

<h:inputText styleClass="form-control" value="#{cc.attrs.backing.from}">

<f:convertDateTime pattern="yyyy-MM-dd"/>

</h:inputText>

<h:inputText styleClass="form-control" value="#{cc.attrs.backing.to}">

<f:convertDateTime pattern="yyyy-MM-dd"/>

</h:inputText>

<p:commandButton styleClass="btn btn-primary" ajax="none" value="#{i18n.see}"/>

</div>

</div>

</div>

</ui:fragment>

<div class="panel panel-info" style="overflow: hidden">

<div class="panel-heading"><span class="glyphicon glyphicon-th-list"/> #{i18n.graphics}</div>

<div class="panel-body">

<p:chart type="bar" model="#{cc.attrs.backing.model}"/>

</div>

</div>

<div class="panel panel-info">

<div class="panel-heading"><span class="glyphicon glyphicon-ok"/> #{i18n.total}</div>

<div class="panel-body">

<p><p:commandButton styleClass="btn btn-primary" action="#{cc.attrs.backing.redirect(cc.attrs.backing.min)}" value="#{i18n.see}"/> #{i18n.min}: #{cc.attrs.backing.minValue}</p>

<p><p:commandButton styleClass="btn btn-primary" action="#{cc.attrs.backing.redirect(cc.attrs.backing.max)}" value="#{i18n.see}"/> #{i18n.max}: #{cc.attrs.backing.maxValue}</p>

</div>

</div>

</c:implementation>

</html>

Grid.xhtml

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://java.sun.com/jsf/composite" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core">

<c:interface>

<c:attribute name="name"/>

<c:attribute name="backing"/>

<c:attribute name="icon" default="glyphicon glyphicon-th-list"/>

<c:attribute name="editable" default="true"/>

</c:interface>

<c:implementation>

<div class="panel panel-info">

<div class="panel-heading"><span class="#{cc.attrs.icon}"/> #{i18n[cc.attrs.name]}</div>

<p:dataTable tableStyleClass="table" value="#{cc.attrs.backing.list}" var="obj">

<ui:include src="/WEB-INF/grid/#{cc.attrs.name}.xhtml"/>

<p:column rendered="#{cc.attrs.editable}" style="width: 1%">

<p:commandButton style="display: inline-block" value="" ajax="none" icon="glyphicon glyphicon-remove" styleClass="btn btn-danger" action="#{cc.attrs.backing.remove(obj)}"/>

<f:facet name="footer">

<p:commandButton style="display: inline-block" value="" ajax="none" icon="glyphicon glyphicon-plus" styleClass="btn btn-primary" action="#{cc.attrs.backing.save}"/>

</f:facet>

</p:column>

</p:dataTable>

</div>

</c:implementation>

</html>

Debt.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:a="http://xmlns.jcp.org/jsf/passthrough" xmlns:f="http://java.sun.com/jsf/core">

<ui:include src="/WEB-INF/grid/pay.xhtml"/>

<p:column headerText="#{i18n.deadline}">

<h:outputText value="#{obj.deadline}">

<f:convertDateTime pattern="yyyy-MM-dd"/>

</h:outputText>

<f:facet name="footer">

<h:inputText styleClass="form-control" value="#{cc.attrs.backing.blank.deadline}" a:placeholder="#{i18n.deadline}">

<f:convertDateTime pattern="yyyy-MM-dd"/>

</h:inputText>

</f:facet>

</p:column>

<p:column headerText="#{i18n.repay}">

#{obj.repay}

<f:facet name="footer">

<h:inputText styleClass="form-control" value="#{cc.attrs.backing.blank.repay}" a:placeholder="#{i18n.repay}"/>

</f:facet>

</p:column>

<p:column headerText="#{i18n.frequency}">

#{obj.frequency}

<f:facet name="footer">

<h:inputText styleClass="form-control" value="#{cc.attrs.backing.blank.frequency}" a:placeholder="#{i18n.frequency}"/>

</f:facet>

</p:column>

<p:column headerText="#{i18n.unit}">

#{i18n[obj.unit]}

<f:facet name="footer">

<h:selectOneMenu styleClass="form-control" value="#{cc.attrs.backing.blank.unit}">

<f:selectItems value="#{unitService.list}" var="unit" itemLabel="#{i18n[unit]}"/>

</h:selectOneMenu>

</f:facet>

</p:column>

</ui:composition>

Diary.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:a="http://xmlns.jcp.org/jsf/passthrough" xmlns:f="http://java.sun.com/jsf/core">

<p:column headerText="#{i18n.balance}">

#{obj.balance}

<f:facet name="footer">

<h:inputText styleClass="form-control" value="#{cc.attrs.backing.blank.balance}" a:placeholder="#{i18n.balance}"/>

</f:facet>

</p:column>

<p:column headerText="#{i18n.category}">

#{i18n[obj.category]}

<f:facet name="footer">

<h:selectOneMenu styleClass="form-control" value="#{cc.attrs.backing.blank.category}">

<f:selectItems value="#{categoryService.list}" var="category" itemLabel="#{i18n[category]}"/>

</h:selectOneMenu>

</f:facet>

</p:column>

<p:column headerText="#{i18n.comment}">

#{obj.comment}

<f:facet name="footer">

<h:inputText styleClass="form-control" value="#{cc.attrs.backing.blank.comment}" a:placeholder="#{i18n.comment}"/>

</f:facet>

</p:column>

</ui:composition>

Pay.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:a="http://xmlns.jcp.org/jsf/passthrough" xmlns:f="http://java.sun.com/jsf/core">

<p:column headerText="#{i18n.date}">

<h:outputText value="#{obj.date}">

<f:convertDateTime pattern="yyyy-MM-dd"/>

</h:outputText>

<f:facet name="footer">

<h:inputText styleClass="form-control" value="#{cc.attrs.backing.blank.date}" a:placeholder="#{i18n.date}">

<f:convertDateTime pattern="yyyy-MM-dd"/>

</h:inputText>

</f:facet>

</p:column>

<ui:include src="/WEB-INF/grid/diary.xhtml"/>

</ui:composition>

Repay.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:a="http://xmlns.jcp.org/jsf/passthrough" xmlns:f="http://java.sun.com/jsf/core">

<p:column headerText="#{i18n.date}">

<h:outputText value="#{obj.date}">

<f:convertDateTime pattern="yyyy-MM-dd"/>

</h:outputText>

<ui:fragment rendered="#{cc.attrs.editable}">

<f:facet name="footer">

<h:inputText styleClass="form-control" value="#{cc.attrs.backing.blank.date}" a:placeholder="#{i18n.date}">

<f:convertDateTime pattern="yyyy-MM-dd"/>

</h:inputText>

</f:facet>

</ui:fragment>

</p:column>

<p:column headerText="#{i18n.balance}">

#{obj.balance}

<ui:fragment rendered="#{cc.attrs.editable}">

<f:facet name="footer">

<h:inputText rendered="#{cc.attrs.editable}" styleClass="form-control" value="#{cc.attrs.backing.blank.balance}" a:placeholder="#{i18n.balance}"/>

</f:facet>

</ui:fragment>

</p:column>

</ui:composition>

Base.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core">

<h:head>

<title>#{i18n.appTitle}</title>

<h:outputScript library="bootstrap" name="js/bootstrap.min.js" />

<link rel="stylesheet" href="#{request.contextPath}/resources/bootstrap/css/bootstrap.min.css"/>

</h:head>

<h:body>

<div class="container-fluid">

<div class="navbar navbar-default">

<ul class="nav navbar-nav">

<li>

<h:link outcome="diary" style="#{todayBacking.count > 0 ? 'color: white; background: #E74C3C' : ''}">

<span class="glyphicon glyphicon-exclamation-sign"/> #{todayBacking.count}

</h:link>

</li>

<li><h:link outcome="pay"><span class="glyphicon glyphicon-book"/> #{i18n.pay}</h:link></li>

<li><h:link outcome="debt"><span class="glyphicon glyphicon glyphicon-calendar"/> #{i18n.debt}</h:link></li>

<li class="dropdown">

<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-stats"/> #{i18n.graphics} <span class="caret"/></a>

<ul class="dropdown-menu" role="menu">

<li><h:link outcome="balance">#{i18n.balance}</h:link></li>

<li><h:link outcome="day">#{i18n.day}</h:link></li>

<li><h:link outcome="unpaid">#{i18n.unpaid}</h:link></li>

<li><h:link outcome="category">#{i18n.category}</h:link></li>

</ul>

</li>

</ul>

</div>

<div class="page-header">

<h1><ui:insert name="title"/></h1>

</div>

<h:form>

<p:messages/>

<ui:insert name="body"/>

</h:form>

</div>

</h:body>

</html>

Web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">

<servlet>

<servlet-name>Faces Servlet</servlet-name>

<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>Faces Servlet</servlet-name>

<url-pattern>*.xhtml</url-pattern>

</servlet-mapping>

<context-param>

<param-name>primefaces.THEME</param-name>

<param-value>none</param-value>

</context-param>

<context-param>

<param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</param-name>

<param-value>true</param-value>

</context-param>

</web-app>

Faces-config.xml

<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd" version="2.2">

<application>

<locale-config>

<default-locale>en</default-locale>

</locale-config>

<resource-bundle>

<base-name>ru.ulstu.secretary.i18n</base-name>

<var>i18n</var>

</resource-bundle>

</application>

</faces-config>

Persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

<persistence-unit name="secretaryPU" transaction-type="JTA">

<exclude-unlisted-classes>false</exclude-unlisted-classes>

<properties>

<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>

<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test"/>

<property name="javax.persistence.jdbc.user" value="sa"/>

<property name="javax.persistence.schema-generation.database.action" value="create" />

<property name="hibernate.show_sql" value="true"/>

</properties>

</persistence-unit>

</persistence>

I18n.properties

appTitle=Home Secretary

pay=Pay

diary=Diary

debt=Debt

repay=Repay

grid=Data

total=Total

date=Date

balance=Sum

category=Category

comment=Comment

action=Action

delete=Delete

complete=Complete

count=Count

graphics=Graphic

day=Day

deadline=Deadline

required=Required

frequency=Frequency

unit=Unit

year=Year

month=Month

week=Week

unpaid=Unpaid

add=Add

see=See

auto=Auto

home=Home

min=Min

max=Max