service.OrderService.java Source code

Java tutorial

Introduction

Here is the source code for service.OrderService.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package service;

import datastructure.OrderListData;
import datastructure.OrderSearchData;
import entity.Admin;
import entity.Author;
import entity.AuthorReject;
import entity.AuthorSalary;
import entity.Branch;
import entity.BranchSite;
import entity.Direction;
import entity.Order;
import entity.OrderFile;
import entity.OrderType;
import entity.Payment;
import entity.ReadyOrderFile;
import entity.User;
import entity.eventType.SystemEventType;
import entity.orderStatus.OrderStatus;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import mvc.formObjects.ReportFormData;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.multipart.MultipartFile;
import persistence.AuthorDao;
import persistence.AuthorRejectDao;
import persistence.AuthorSalaryDao;
import persistence.BranchDao;
import persistence.BranchSiteDao;
import persistence.DirectionDao;
import persistence.OrderDao;
import persistence.OrderFileDao;
import persistence.OrderTypeDao;
import persistence.PaymentDao;
import persistence.ReadyOrderFileDao;
import rights.Rights;
import rights.UserRightsUtil;
import service.actions.OrderSearch;
import service.actions.SystemNoticeRecorder;
import service.parent.PrimService;
import support.DateFormatter;
import support.ServiceResult;
import support.StringAdapter;
import support.ZipArchive;

/**
 * 
 *
 * @author Rice Pavel
 */
@Service
@Transactional
public class OrderService extends PrimService {

    @Autowired
    private FileService fileService;

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private PaymentDao paymentDao;

    @Autowired
    private OrderFileDao orderFileDao;

    @Autowired
    private ReadyOrderFileDao readyOrderFileDao;

    @Autowired
    private AuthorDao authorDao;

    @Autowired
    private DirectionDao directionDao;

    @Autowired
    private OrderTypeDao orderTypeDao;

    @Autowired
    private NoticeService noticeService;

    @Autowired
    private BranchDao branchDao;

    @Autowired
    private OrderLogService orderLogService;

    @Autowired
    private BranchSiteDao branchSiteDao;

    @Autowired
    private MessageService messageService;

    @Autowired
    private AuthorRejectDao authorRejectDao;

    @Autowired
    private OrderSearch orderSearch;

    @Autowired
    private SystemNoticeRecorder noticeRecorder;

    @Autowired
    private AuthorService authorService;

    @Autowired
    private AuthorSalaryDao authorSalaryDao;

    @Autowired
    private PlatformTransactionManager transactionManager;

    /**
     *  
     *
     * @param orderId
     * @param directionId
     */
    public void deleteDirection(Long orderId, Long directionId) {
        Order order = orderDao.find(orderId);
        List<Direction> directions = order.getDirections();
        for (Direction dir : directions) {
            if (dir.getDirectionId().equals(directionId)) {
                directions.remove(dir);
                break;
            }
        }
        orderDao.update(order);
    }

    public void delegate(Long orderId, Long branchId) throws IOException, FileNotFoundException {
        Order order = orderDao.find(orderId);
        Order newOrder = new Order();
        copyDataForDelegate(order, newOrder);
        setBranch(newOrder, branchId);
        orderDao.save(newOrder);
        noticeRecorder.saveNoticesAddOrder(newOrder);
    }

    private void setBranch(Order order, Long branchId) {
        Branch branch = branchDao.find(branchId);
        order.setBranch(branch);
    }

    private void copyDataForDelegate(Order order, Order newOrder) throws IOException, FileNotFoundException {
        newOrder.setAuthorComment(order.getAuthorComment());
        newOrder.setAuthorSubject(order.getAuthorSubject());
        newOrder.setAuthor_salary(order.getAuthor_salary());
        newOrder.setCity(order.getCity());
        newOrder.setClientEmail(order.getClientEmail());
        newOrder.setClientFio(order.getClientFio());
        newOrder.setClientPhone(order.getClientPhone());
        newOrder.setComment(order.getComment());
        newOrder.setCommentToAuthorSalary(order.getCommentToAuthorSalary());
        newOrder.setCost(order.getCost());
        newOrder.setDateUnloadingInShop(order.getDateUnloadingInShop());
        newOrder.setDeadlineDate(order.getDeadlineDate());
        List<Direction> newDirections = new ArrayList();
        for (Direction dir : order.getDirections()) {
            newDirections.add(dir);
        }
        newOrder.setDirections(newDirections);
        copyFiles(order, newOrder);
        newOrder.setFirstFlag(order.getFirstFlag());
        newOrder.setSecondFlag(order.getSecondFlag());
        newOrder.setNumberOfPages(order.getNumberOfPages());
        newOrder.setOrderDate(order.getOrderDate());
        newOrder.setOrderType(order.getOrderType());
        newOrder.setRate(order.getRate());
        newOrder.setReadyDate(order.getReadyDate());
        newOrder.setRealDate(order.getRealDate());
        newOrder.setReworkDate(order.getReworkDate());
        newOrder.setStatus(order.getStatus());
        newOrder.setSubject(order.getSubject());
        newOrder.setUnloadedInShop(order.getUnloadedInShop());
        newOrder.setParentOrder(order);
    }

    private void copyFiles(Order order, Order newOrder) throws FileNotFoundException, IOException {
        for (OrderFile fileEntity : order.getFiles()) {
            File file = fileService.getFile(fileEntity.getFileId());
            OrderFile newFileEntity = new OrderFile();
            newFileEntity.setOrder(newOrder);
            newFileEntity.setRusname(fileEntity.getRusname());
            newFileEntity.setUploadDate(fileEntity.getUploadDate());
            fileService.saveNewFile(newFileEntity, IOUtils.toByteArray(new FileInputStream(file)));
        }
    }

    public datastructure.CountOrders getCountOrders(Long authorIdForSearch, Long branchId,
            List<OrderStatus> rightStatusList) {
        return orderSearch.getCountForMenu(authorIdForSearch, branchId, rightStatusList);
    }

    public void refresh(Order order) {
        orderDao.refresh(order);
    }

    /**
     * ?  ? 
     *
     * @param order
     */
    public void setReadyDateByOrder(Order order) {
        setReadyDate(order);
    }

    public void setReadyDate(Order order) {
        if (order.getReadyDate() == null && isPaid(order) && order.getStatus().equals(OrderStatus.READY)) {
            order.setReadyDate(new Date());
            orderDao.update(order);
        }
    }

    private boolean isPaid(Order order) {
        return (order.getPaymentSum() != null && order.getCost() != null
                && order.getPaymentSum() >= order.getCost());
    }

    /**
     *  
     *
     * @param orderId
     * @param directionId
     * @throws IOException
     */
    public void addDirection(Long orderId, Long directionId) throws IOException {
        Order order = orderDao.find(orderId);
        List<Direction> directions = order.getDirections();
        Direction newDirection = directionDao.find(directionId);
        if (!directions.contains(newDirection)) {
            directions.add(newDirection);
            orderDao.update(order);
            noticeRecorder.saveNoticesAddDirection(order, newDirection);
        }
    }

    /**
     * 
     *
     * @param orderId
     * @param rate
     * @return
     */
    public ServiceResult rate(Long orderId, Integer rate) {
        ServiceResult res = new ServiceResult();
        //  ?? 
        if (allowRate(orderId)) {
            Order order = orderDao.find(orderId);
            order.setRate(rate);
            res = validateSaveOrUpdate(order, orderDao);
            if (!res.hasErrors()) {
                if (order.getAuthor() != null) {
                    authorService.calculateRating(order.getAuthor().getUserId());
                }
            }
        } else {
            res.addError("?   ? ");
        }
        return res;
    }

    /**
     *  ??
     *
     * @param orderId
     * @param cost
     * @return
     */
    public ServiceResult changeCost(Long orderId, Double cost) {
        Order order = orderDao.find(orderId);
        order.setCost(cost);
        return validateSaveOrUpdate(order, orderDao);
    }

    /**
     *   
     *
     * @param orderId
     * @param salary
     * @return
     */
    public ServiceResult changeSalary(Long orderId, Double salary, String commentToAuthorSalary) {
        Order order = orderDao.find(orderId);
        order.setAuthor_salary(salary);
        order.setCommentToAuthorSalary(commentToAuthorSalary);
        return validateSaveOrUpdate(order, orderDao);
    }

    /**
     *  ??
     *
     * @param dateFrom
     * @param dateTo
     * @param branchId
     * @return
     */
    public List<Map> getStatistics(Date dateFrom, Date dateTo, Long branchId, Set<Long> branchIds) {
        return orderDao.getStatistics(dateFrom, dateTo, branchId, branchIds);
    }

    /**
     *  ??  
     *
     * @param dateFrom
     * @param dateTo
     * @param branchId
     * @return
     */
    public List<Map> getStatisticsByDates(Date dateFrom, Date dateTo, Long branchId, Set<Long> branchIds) {
        return orderDao.getStatisticsByDates(dateFrom, dateTo, branchId, branchIds);
    }

    /**
     *  
     *
     * @param orderId
     * @param authorId
     */
    public void changeAuthor(Long orderId, Long authorId) throws IOException {
        Order order = orderDao.find(orderId);
        OrderStatus firstStatus = OrderStatus.NEW;
        OrderStatus secondStatus = OrderStatus.CONFIRMATION;
        Author author = authorDao.find(authorId);
        boolean changeStatus = false;
        if (order.getStatus().equals(firstStatus)) {
            order.setStatus(secondStatus);
            childOrdersToReject(order);
            changeStatusOfParentOrder(order, secondStatus);
            changeStatus = true;
            setAuthorSalary(order, author);
        }
        order.setAuthor(author);
        orderDao.update(order);
        recoverAuthorFromReject(orderId, authorId);
        noticeRecorder.addStandartNotices(order, entity.eventType.SystemEventType.AUTHOR_SELECTED);
        if (changeStatus) {
            orderLogService.logChangeStatus(order, firstStatus, secondStatus);
        }
    }

    /**
     * ?    
     */
    private void childOrdersToReject(Order order) {
        if (order.getChildOrders() != null) {
            for (Order childOrder : order.getChildOrders()) {
                childOrder.setStatus(OrderStatus.REJECTION);
                orderDao.update(childOrder);
            }
        }
    }

    private void changeStatusOfParentOrder(Order order, OrderStatus newStatus) {
        Order parentOrder = order.getParentOrder();
        if (parentOrder != null) {
            parentOrder.setStatus(newStatus);
            orderDao.update(parentOrder);
        }
    }

    private void setAuthorSalary(Order order, Author author) {
        List<AuthorSalary> salaryList = authorSalaryDao.find(author, order);
        if (!salaryList.isEmpty()) {
            AuthorSalary salary = salaryList.get(0);
            Double cost = salary.getCost();
            order.setAuthor_salary(cost);
        }
    }

    /**
     *   ?    
     *
     * @param dateFrom
     * @param dateTo
     * @return
     * @throws Exception
     */
    public byte[] getOrderFileArchive(Date dateFrom, Date dateTo) throws Exception {
        //  ?   ,   ? 
        List<Order> orderList = orderDao.getOrdersWithFilesReadyOrArchive(dateFrom, dateTo);
        ZipArchive archive = new ZipArchive();
        for (Order order : orderList) {
            String branchAbbr = order.getBranch().getAbbrevation();
            DateFormatter dateFormatter = new DateFormatter();
            String date = dateFormatter.date(order.getDeadlineDate());
            String orderId = order.getNumber().toString();
            String folderName = branchAbbr + "/" + date + "/" + orderId + "/";
            for (ReadyOrderFile fileEnt : order.getReadyFiles()) {
                File file = fileStorage.getFile(fileEnt.getFileId());
                String fileName = folderName + fileEnt.getRusname();
                archive.addFile(file.getPath(), fileName);
            }
        }
        return archive.doZip();
    }

    /**
     *    
     *
     * @param orderId
     * @return
     */
    public boolean allowRate(Long orderId) {
        Order order = orderDao.find(orderId);
        return allowRate(order);
    }

    /**
     * ? 
     *
     * @param orderId  
     * @param branchId  .   null
     */
    public void changeBranch(Long orderId, Long branchId) {
        // ?   
        //  ?  
        if (orderId != null && branchId != null) {
            Order order = orderDao.find(orderId);
            Branch branch = branchDao.find(branchId);
            order.setBranch(branch);
            orderDao.update(order);
        }
    }

    /**
     *  
     *
     * @param order
     * @param file
     * @param res
     * @return
     * @throws IOException
     */
    public Long addOrder(Order order, MultipartFile[] files, ServiceResult res) throws IOException {
        order.setStatus(OrderStatus.NEW);
        order.setOrderDate(new Date());
        setDeadlineDateToNewOrder(order);
        Long orderId = validateSave(order, orderDao, res);
        if (!res.hasErrors() && orderId != null) {
            if (files != null) {
                for (MultipartFile file : files) {
                    if (file != null && !file.isEmpty()) {
                        OrderFile orderFile = new OrderFile();
                        orderFile.setOrder(order);
                        orderFile.setRusname(file.getOriginalFilename());
                        saveFile(orderFile, file);
                        order.addFile(orderFile);
                    }
                }
            }
            noticeRecorder.saveNoticesAddOrder(order);
        }
        return orderId;
    }

    public Long addOrder(Long orderTypeId, String subject, Date realDate, List<Long> directionIds, String clientFio,
            String clientPhone, String clientEmail, String city, String comment, String siteName,
            MultipartFile[] files, ServiceResult result) throws IOException {
        Order order = new Order();
        if (orderTypeId != null) {
            OrderType type = orderTypeDao.find(orderTypeId);
            order.setOrderType(type);
        }
        List<Direction> directionsList = new ArrayList();
        if (directionIds != null) {
            for (Long directionId : directionIds) {
                Direction direction = directionDao.find(directionId);
                directionsList.add(direction);
            }
        }
        Branch branch = getBranchBySiteName(siteName);
        order.setBranch(branch);
        order.setOrderDate(new Date());
        order.setStatus(OrderStatus.NEW);
        order.setSubject(subject);
        order.setRealDate(realDate);
        order.setDirections(directionsList);
        order.setClientFio(clientFio);
        order.setClientPhone(clientPhone);
        order.setClientEmail(clientEmail);
        order.setCity(city);
        order.setComment(comment);
        setDeadlineDateToNewOrder(order);
        Long id = validateSave(order, orderDao, result);
        if (!result.hasErrors()) {
            if (files != null) {
                for (MultipartFile file : files) {
                    if (file != null && !file.isEmpty()) {
                        OrderFile orderFile = new OrderFile();
                        orderFile.setOrder(order);
                        saveFile(orderFile, file);
                        order.addFile(orderFile);
                    }
                }
            }
            noticeRecorder.saveNoticesAddOrder(order);
        }
        return id;
    }

    private Branch getBranchBySiteName(String site) {
        List<BranchSite> list = branchSiteDao.getByName(site);
        if (!list.isEmpty()) {
            return list.get(0).getBranch();
        }
        return null;
    }

    private void setDeadlineDateToNewOrder(Order order) {
        Date real = order.getRealDate();
        if (real != null) {
            Calendar cl = Calendar.getInstance();
            cl.setTime(real);
            cl.add(Calendar.DAY_OF_YEAR, -1);
            Date deadline = cl.getTime();
            order.setDeadlineDate(deadline);
        }
    }

    /**
     *  
     *
     * @param from
     * @param to
     * @return
     */
    public List<Order> getReport(Date from, Date to) {
        return orderDao.getReport(from, to);
    }

    /**
     *  
     *
     * @param orderTypeIds
     * @param directionIds
     * @param searchBrancheIds
     * @param from
     * @param to
     * @return
     */
    public List<Map> getReportNew(Set<Long> orderTypeIds, Set<Long> directionIds, Set<Long> searchBrancheIds,
            Date from, Date to) {
        return orderDao.getReportNew(orderTypeIds, directionIds, searchBrancheIds, from, to);
    }

    /**
     *    ?? 
     *
     * @param orderTypeIds
     * @param directionIds
     * @param searchBrancheIds
     * @param from
     * @param to
     * @return
     */
    public List<Payment> getReportAsPaymentList(Set<Long> orderTypeIds, Set<Long> directionIds,
            Set<Long> searchBrancheIds, Date from, Date to, Set<Long> branchIds) {
        return orderDao.getReportAsPaymentList(orderTypeIds, directionIds, searchBrancheIds, from, to, branchIds);
    }

    /**
     *   
     *
     * @param from
     * @param to
     * @param orderId
     * @return
     */
    public List<Payment> getDetailReport(Date from, Date to, Long orderId) {
        return orderDao.getDetailReport(from, to, orderId);
    }

    /**
     *  
     *
     * @param order
     * @param file
     * @throws IOException
     */
    public void addFile(Order order, MultipartFile file) throws IOException {
        if (file != null && !file.isEmpty()) {
            OrderFile orderFile = new OrderFile();
            orderFile.setOrder(order);
            orderFile.setRusname(file.getOriginalFilename());
            orderFileDao.save(orderFile);
            fileStorage.saveFile(orderFile.getId(), file);
        }
    }

    /**
     * ?  
     *
     * @param date
     * @param branchIds
     * @return
     */
    public List<OrderListData> searchFromCalendar(Date date, List<OrderStatus> rightStatusList) {
        return orderSearch.getFromCalendar(date, rightStatusList);
    }

    public List<Date> getDeadlineDatesForAuthor(List<OrderStatus> rightStatusList) {
        return orderSearch.getDeadlineDatesForAuthor(rightStatusList);
    }

    /**
     *  
     *
     * @param orderId
     */
    public ServiceResult reject(Long orderId) {
        ServiceResult result = new ServiceResult();
        Order order = orderDao.find(orderId);
        User user = authManager.getCurrentUser();
        if (order != null && user instanceof Author) {
            Author author = (Author) user;
            if (allowReject(order)) {
                saveAuthorReject(order, author);
                if (orderOnConfirmation(order, author)) {
                    orderToNew(order);
                }
            } else {
                result.addError(" ?    ,   ");
            }
        }
        return result;
    }

    public void recoverFromReject(Long orderId) {
        Order order = orderDao.find(orderId);
        User authUser = authManager.getCurrentUser();
        if (allowRecoverFromReject(order) && authUser instanceof Author) {
            Author author = (Author) authUser;
            for (AuthorReject reject : author.getRejectList()) {
                if (reject.getOrder().getOrderId().equals(order.getOrderId())) {
                    authorRejectDao.delete(reject);
                }
            }
        }
    }

    public void recoverAuthorFromReject(Long orderId, Long authorId) {
        Order order = orderDao.find(orderId);
        Author author = authorDao.find(authorId);
        if (order != null && author != null) {
            for (AuthorReject reject : author.getRejectList()) {
                if (reject.getOrder().getOrderId().equals(order.getOrderId())) {
                    authorRejectDao.delete(reject);
                }
            }
        }
    }

    public boolean allowRecoverFromReject(Order order) {
        User authUser = authManager.getCurrentUser();
        if (authUser instanceof Author) {
            Author author = (Author) authUser;
            List<AuthorReject> rejections = author.getRejectList();
            if (order.getStatus().equals(OrderStatus.NEW) && existsReject(rejections, order.getOrderId())) {
                return true;
            }
        }
        return false;
    }

    private void orderToNew(Order order) {
        OrderStatus oldStatus = order.getStatus();
        OrderStatus newStatus = OrderStatus.NEW;
        order.setAuthor(null);
        order.setStatus(newStatus);
        orderDao.update(order);
        orderLogService.logChangeStatus(order, oldStatus, newStatus);
    }

    private void saveAuthorReject(Order order, Author author) {
        AuthorReject reject = new AuthorReject();
        reject.setOrder(order);
        reject.setAuthor(author);
        authorRejectDao.save(reject);
    }

    /**
     *   ? -   
     *
     * @param order
     * @return
     */
    public boolean allowReject(Order order) {
        User authUser = authManager.getCurrentUser();
        if (authUser instanceof Author) {
            Author author = (Author) authUser;
            List<AuthorReject> rejections = author.getRejectList();
            if ((order.getStatus().equals(OrderStatus.NEW) && !existsReject(rejections, order.getOrderId()))
                    || orderOnConfirmation(order, author)) {
                return true;
            }
        }
        return false;
    }

    private boolean existsReject(List<AuthorReject> rejectionsOfCurrentUser, Long orderId) {
        if (rejectionsOfCurrentUser != null) {
            for (AuthorReject ar : rejectionsOfCurrentUser) {
                if (ar.getOrder() != null) {
                    if (ar.getOrder().getOrderId().equals(orderId)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private boolean orderOnConfirmation(Order order, Author authAuthor) {
        if (order != null) {
            if (authAuthor != null) {
                if (order.getStatus() != null) {
                    if (order.getStatus().equals(OrderStatus.CONFIRMATION)) {
                        if (order.getAuthor() != null && order.getAuthor().getUserId() != null) {
                            if (order.getAuthor().getUserId().equals(authAuthor.getUserId())) {
                                return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     *  
     *
     * @param orderId
     * @throws IOException
     */
    public void sendToClient(Long orderId, Set<Long> readyFilesIds) throws IOException {
        Order order = orderDao.find(orderId);
        if (order.getPaymentSum() < order.getCost()) {
            noticeService.addSystemClientNotices(SystemEventType.ORDER_READY, order, readyFilesIds);
        } else {
            noticeService.addSystemClientNotices(SystemEventType.ORDER_READY_PAID, order, readyFilesIds);
        }

    }

    /**
     *    
     *
     * @param order 
     * @param file 
     * @throws IOException
     */
    public void addReadyFile(Order order, MultipartFile file) throws IOException {
        if (file != null && !file.isEmpty()) {
            ReadyOrderFile orderFile = new ReadyOrderFile();
            orderFile.setOrder(order);
            orderFile.setRusname(file.getOriginalFilename());
            readyOrderFileDao.save(orderFile);
            fileStorage.saveFile(orderFile.getId(), file);
        }
    }

    /**
     * ? ??
     *
     * @param orderId
     * @param status
     * @return
     */
    public ServiceResult changeStatus(Long orderId, String status) {
        ServiceResult res = new ServiceResult();
        Order order = orderDao.find(orderId);
        if (order != null) {
            OrderStatus oldStatus = order.getStatus();
            OrderStatus newStatus = null;
            try {
                newStatus = OrderStatus.valueOf(status);
            } catch (Exception e) {
            }
            if (newStatus != null) {
                order.setStatus(newStatus);
                order.setStatusOfUser(true);
                changeStatusOfParentOrder(order, newStatus);
                if (newStatus.equals(OrderStatus.NEW)) {
                    order.setAuthor(null);
                }
                if (newStatus.equals(OrderStatus.REJECTION)) {
                    childOrdersToReject(order);
                }
                if (newStatus.equals(OrderStatus.READY)) {
                    order.setReadyDate(new Date());
                }
                validate(res, order);
                if (!res.hasErrors()) {
                    orderDao.update(order);
                    if (oldStatus != null && newStatus != null && !oldStatus.equals(newStatus)) {
                        ServiceResult res2 = orderLogService.logChangeStatus(order, oldStatus, newStatus);
                        if (res2.hasErrors()) {
                            res.addErrors(res2.getErrors());
                        }
                    }
                    if (newStatus.equals(OrderStatus.REWORK)) {
                        try {
                            noticeRecorder.addStandartNotices(order, entity.eventType.SystemEventType.ORDER_REWORK);
                        } catch (Exception e) {
                            log.warn("Warn notice rework", e);
                        }
                    }
                }

            } else {
                res.addError("  ??");
            }
        } else {
            res.addError("  ");
        }
        return res;
    }

    /**
     *      
     *
     * @param orderId
     * @return
     */
    public boolean allowToConfirmation(Long orderId) {
        Order order = orderDao.find(orderId);
        return allowToConfirmation(order);
    }

    public boolean allowToConfirmation(Order order) {
        if (order.getStatus().equals(OrderStatus.NEW) && order.getPaymentSum() > 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     *    
     *
     * @param orderId
     * @param authorId
     * @return
     */
    public ServiceResult toConfirmation(Long orderId, Long authorId) {
        ServiceResult res = new ServiceResult();
        if (allowToConfirmation(orderId)) {
            //  
            Order order = orderDao.find(orderId);
            OrderStatus oldStatus = order.getStatus();
            Author author = authorDao.find(authorId);
            // ? ??
            OrderStatus newStatus = OrderStatus.CONFIRMATION;
            order.setStatus(newStatus);
            changeStatusOfParentOrder(order, newStatus);
            order.setAuthor(author);
            orderDao.update(order);
            orderLogService.logChangeStatus(order, oldStatus, newStatus);
        } else {
            res.addError(" ?  ? ? ");
        }
        return res;
    }

    /**
     *  
     *
     * @param orderId
     * @return
     */
    public ServiceResult confirm(Long orderId) throws IOException {
        ServiceResult res = new ServiceResult();
        if (allowConfirm(orderId)) {
            //  ??
            Order order = orderDao.find(orderId);
            OrderStatus oldStatus = order.getStatus();
            OrderStatus newStatus = OrderStatus.WORKING;
            order.setStatus(newStatus);
            changeStatusOfParentOrder(order, newStatus);
            orderDao.update(order);
            orderLogService.logChangeStatus(order, oldStatus, newStatus);
        } else {
            res.addError(" ?  ? ? ");
        }
        return res;
    }

    /**
     * ?      1 -    ?
     *
     * @param orderId
     * @return
     */
    public ServiceResult toCheck(Long orderId) {
        ServiceResult res = new ServiceResult();
        if (allowToCheck(orderId)) {
            Order order = orderDao.find(orderId);
            /*if (order.getAuthorSubject() == null || order.getAuthorSubject().isEmpty()) {
             res.addError("   ?");
             res.setErrorCode(1);
             } else {*/
            OrderStatus oldStatus = order.getStatus();
            OrderStatus newStatus = OrderStatus.CHECK;
            order.setStatus(newStatus);
            changeStatusOfParentOrder(order, newStatus);
            orderDao.update(order);
            orderLogService.logChangeStatus(order, oldStatus, newStatus);
            //}
        } else {
            res.addError(" ?  ? ? ");
        }
        return res;
    }

    /**
     * ?   ?? - 
     *
     * @param orderId
     * @return
     * @throws IOException
     */
    public ServiceResult ready(Long orderId) throws IOException {
        ServiceResult res = new ServiceResult();
        if (allowReadyOrRework(orderId)) {
            Order order = orderDao.find(orderId);
            OrderStatus oldStatus = order.getStatus();
            OrderStatus newStatus = OrderStatus.READY;
            order.setStatus(newStatus);
            changeStatusOfParentOrder(order, newStatus);
            orderDao.update(order);
            noticeRecorder.addStandartNotices(order, entity.eventType.SystemEventType.ORDER_READY);
            orderLogService.logChangeStatus(order, oldStatus, newStatus);
        } else {
            res.addError(" ?  ? ? ");
        }
        return res;
    }

    public Long getOverdueCount() {
        return orderSearch.getOverdueCount();
    }

    /**
     * ?   ?? - 
     *
     * @param orderId
     * @return
     */
    public ServiceResult rework(Long orderId) throws IOException {
        ServiceResult res = new ServiceResult();
        if (allowReadyOrRework(orderId)) {
            Order order = orderDao.find(orderId);
            OrderStatus oldStatus = order.getStatus();
            OrderStatus newStatus = OrderStatus.REWORK;
            order.setStatus(newStatus);
            changeStatusOfParentOrder(order, newStatus);
            order.setReworkDate(new Date());
            orderDao.update(order);

            noticeRecorder.addStandartNotices(order, entity.eventType.SystemEventType.ORDER_REWORK);
            orderLogService.logChangeStatus(order, oldStatus, newStatus);
        } else {
            res.addError(" ?  ? ? ");
        }
        return res;
    }

    /**
     * ?   
     *
     * @param orderId
     * @return
     */
    public ServiceResult toArchive(Long orderId) {
        ServiceResult res = new ServiceResult();
        if (allowToArchive(orderId)) {
            Order order = orderDao.find(orderId);
            OrderStatus oldStatus = order.getStatus();
            OrderStatus newStatus = OrderStatus.ARCHIVE;
            order.setStatus(newStatus);
            changeStatusOfParentOrder(order, newStatus);
            orderDao.update(order);
            orderLogService.logChangeStatus(order, oldStatus, newStatus);
        } else {
            res.addError(" ?  ? ? ");
        }
        return res;
    }

    /**
     *     
     *
     * @param orderId
     * @return
     */
    public boolean allowConfirm(Long orderId) {
        Order order = orderDao.find(orderId);
        return allowConfirm(order);
    }

    /**
     *     
     *
     * @param order
     */
    public boolean allowConfirm(Order order) {
        if (order.getStatus().equals(OrderStatus.CONFIRMATION)) {
            //    .?
            User authUser = authManager.getCurrentUser();
            if (order.getAuthor() != null) {
                if (authUser.getUserId().equals(order.getAuthor().getUserId())) {
                    return true;
                }
            }
        }
        return false;
    }

    public boolean allowRate(Order order) {
        User authUser = authManager.getCurrentUser();
        OrderStatus status = order.getStatus();
        OrderStatus[] statusArr = { OrderStatus.WORKING, OrderStatus.CHECK, OrderStatus.READY, OrderStatus.ARCHIVE,
                OrderStatus.OTHER, OrderStatus.REWORK };
        List<OrderStatus> statusList = Arrays.asList(statusArr);
        return (authUser instanceof Admin && (status != null && (statusList.contains(status))));
    }

    /**
     *   ?   ?? - 
     *
     * @param orderId
     * @return
     */
    public boolean allowToCheck(Long orderId) {
        Order order = orderDao.find(orderId);
        return allowToCheck(order);
    }

    /**
     * ?   ? ,  ?   
     *
     * @param order
     * @return
     */
    public boolean allowToCheck(Order order) {
        OrderStatus status = order.getStatus();
        boolean hasReadyFiles = (order.getReadyFiles() != null && !order.getReadyFiles().isEmpty());
        return (hasReadyFiles && status != null
                && (status.equals(OrderStatus.WORKING) || status.equals(OrderStatus.REWORK)));
    }

    /**
     *        
     *
     * @param orderId
     * @return
     */
    public boolean allowReadyOrRework(Long orderId) {
        Order order = orderDao.find(orderId);
        return allowReadyOrRework(order);
    }

    public boolean allowReadyOrRework(Order order) {
        if (order.getStatus().equals(OrderStatus.CHECK) && !(authManager.getCurrentUser() instanceof Author)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     *   ?   
     *
     * @param orderId
     * @return
     */
    public boolean allowToArchive(Long orderId) {
        Order order = orderDao.find(orderId);
        return allowToArchive(order);
    }

    public boolean allowToArchive(Order order) {
        if (order.getStatus().equals(OrderStatus.READY)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * ??   ?  ?, ? ? 
     *
     * @param order
     * @return
     */
    public boolean existRejectForAuthUser(Order order) {
        User authUser = authManager.getCurrentUser();
        if (authUser != null && authUser instanceof Author) {
            Author author = (Author) authUser;
            List<AuthorReject> rejections = author.getRejectList();
            return existsReject(rejections, order.getOrderId());
        } else {
            return false;
        }
    }

    /**
     *  
     *
     * @param order
     * @return
     */
    public ServiceResult update(Order order) {
        Long orderId = order.getOrderId();
        Order oldOrder = orderDao.find(orderId);
        if (!oldOrder.getChildSelected()) {
            order.setStatus(oldOrder.getStatus());
            return validateUpdate(order, orderDao);
        } else {
            ServiceResult res = new ServiceResult();
            res.addError(
                    "  ? ?,   ? ?   ");
            return res;
        }
    }

    /**
     *  ? 
     *
     * @return
     */
    public List<Order> getAllOrders() {
        return authorFilter(orderDao.getAll());
    }

    /**
     *  
     *
     * @param rightBrancheIds  , ?   ?  
     * @param orderTypeIds   
     * @param directionIds  
     * @param searchBrancheIds  
     * @param from   
     * @param to  ? 
     * @param status ??
     * @param searchString ? ?
     * @return
     */
    public List<Order> getOrders(Set<Long> rightBrancheIds, Set<Long> orderTypeIds, Set<Long> directionIds,
            Set<Long> searchBrancheIds, Date from, Date to, OrderStatus status, String searchString) {
        OrderSearchData data = new OrderSearchData();
        data.orderTypeIds = orderTypeIds;
        data.directionIds = directionIds;
        data.branchIds = searchBrancheIds;
        data.from = from;
        data.to = to;
        data.searchString = searchString;
        List<Order> list = orderSearch.getOrderList(rightBrancheIds, status, data);
        return list;
    }

    /**
     *  ??    map.   map: 'order; - ?
     * , 'otherOrders' -     
     *
     * @param rightBrancheIds
     * @param orderTypeIds
     * @param directionIds
     * @param searchBrancheIds
     * @param from
     * @param to
     * @param status
     * @param searchString
     * @param authorId
     * @return
     */
    /*
     public List<OrderListData> getOrdersAsDataList(
     Set<Long> rightBrancheIds,
     Set<Long> orderTypeIds,
     Set<Long> directionIds,
     Set<Long> searchBrancheIds,
     Date from,
     Date to,
     OrderStatus status,
     String searchString,
     Long authorId
     ) {
     List<OrderListData> list = orderDao.getOrdersAsDataList(rightBrancheIds, orderTypeIds, directionIds, searchBrancheIds, from, to, status, searchString, authorId);
     setParams(list);
     return authorFilterByDataList(list);
     }
     */
    /**
     *  ??    ? 
     *
     * @param rightBrancheIds
     * @param orderTypeIds
     * @param directionIds
     * @param searchBrancheIds
     * @param from
     * @param to
     * @param status
     * @param searchString
     * @param authorId
     * @return
     */
    public List<OrderListData> getOrdersAsDataList(Set<Long> rightBrancheIds, OrderStatus status,
            OrderSearchData searchData, Integer start, Integer numberOfRecords, Boolean haveCost,
            List<OrderStatus> rightStatisList) {
        return orderSearch.getOrderDataList(rightBrancheIds, status, searchData, start, numberOfRecords,
                rightStatisList, false);
    }

    public List<List<String>> getOrdersAsTestDataList(Set<Long> rightBrancheIds, OrderStatus status,
            List<OrderStatus> commonAvailableStatusList, OrderSearchData searchData, Integer start,
            Integer numberOfRecords, Boolean haveCost, List<OrderStatus> rightStatisList, Boolean overdue) {
        return orderSearch.getOrderTestDataList(rightBrancheIds, status, commonAvailableStatusList, searchData,
                start, numberOfRecords, rightStatisList, overdue);
    }

    /*public List<List<String>> getOrdersAsOrderedDataList(Set<Long> rightBrancheIds, OrderStatus status,
        List<OrderStatus> commonAvailableStatusList, OrderSearchData searchData, Integer start,
        Integer numberOfRecords, Boolean haveCost, List<OrderStatus> rightStatisList,Boolean overdue) {
    return orderSearch.getOrderOrderedDataList(rightBrancheIds, status, commonAvailableStatusList,
            searchData, start, numberOfRecords, rightStatisList, overdue);
    }*/

    public List<OrderListData> getOrdersAsOverdueDataList(Set<Long> rightBrancheIds, OrderStatus status,
            OrderSearchData searchData, Integer start, Integer numberOfRecords, Boolean haveCost,
            List<OrderStatus> rightStatisList) {
        return orderSearch.getOrderDataList(rightBrancheIds, status, searchData, start, numberOfRecords,
                rightStatisList, true);
    }

    public List<Order> reportForUnloadInShop(Date dateFrom, Date dateTo) {
        return orderDao.reportForUnloadInShop(dateFrom, dateTo);
    }

    /**
     *    
     *
     * @param branchesId
     * @return
     */
    public List<Order> getOrders(Set<Long> branchesId) {
        return authorFilter(orderDao.getOrders(branchesId));
    }

    public List<Order> getAllOrdersForUser(Set<Long> rightBranchIds) {
        return getOrders(rightBranchIds, null, null, null, null, null, null, null);
    }

    public Order find(Long orderId) {
        return orderDao.find(orderId);
    }

    public void delete(Order order) {
        Author author = order.getAuthor();
        orderDao.delete(order);
        if (author != null) {
            authorService.calculateRating(author.getUserId());
        }
    }

    public Set<String> getPhones(Set<Long> rightBrancheIds, ReportFormData data) {
        Set<String> set = new HashSet();
        if (data.from != null && data.to != null) {
            List<Order> orders = orderDao.getOrders(rightBrancheIds, data);
            for (Order order : orders) {
                set.add(order.getClientPhone());
            }
        }
        return set;
    }

    public Set<String> getEmails(Set<Long> rightBrancheIds, ReportFormData data) {
        Set<String> set = new HashSet();
        if (data.from != null && data.to != null) {
            List<Order> orders = orderDao.getOrders(rightBrancheIds, data);
            for (Order order : orders) {
                set.add(order.getClientEmail());
            }
        }
        return set;
    }

    public List<Order> otherOrdersByClient(Order order) {
        // ? ? email
        List<Order> orders = new ArrayList();
        String email = order.getClientEmail();
        //  ?  ?   email, ?? ? 
        if (email != null && !email.isEmpty()) {
            orders = orderDao.getByEmail(email, order);
        }
        return orders;
    }

    public int countRejectionOrdersWithFiles() {
        return orderDao.getCountOrdersWithFiles(OrderStatus.REJECTION);
    }

    public void deleteRejectionFiles() {
        int count = 200;
        List<Order> orders = orderDao.getOrdersWithFiles(OrderStatus.REJECTION, count);
        for (Order order : orders) {
            for (OrderFile orderFile : order.getFiles()) {
                fileService.deleteFile(orderFile);
            }
            for (ReadyOrderFile orderFile : order.getReadyFiles()) {
                fileService.deleteFile(orderFile);
            }
        }
    }

    /**
     *  ??  
     *
     * @throws IOException
     */
    @Scheduled(cron = "0 1 * * * *")
    public void addNoticesOfPrepayment() throws IOException {
        //   ,    
        List<Order> orders = orderDao.getNewOrdersWithoutPayments();
        // ?   -  ? 
        for (Order order : orders) {
            noticeService.addSystemClientNotices(SystemEventType.REMINDER_OF_PREPAYMENT, order, null);
        }
    }

    @Scheduled(cron = "0 1 * * * *")
    public void addNoticesOfDeadline() throws IOException {
        //  ,   ? ,        
        List<Order> orders = orderDao.lessTheDayBeforeDeadline();
        for (Order order : orders) {
            noticeRecorder.addStandartNotices(order, SystemEventType.REMINDER_OF_DEADLINE);
        }
    }

    /**
     * ?  
     *
     * @param orderId  
     */
    public void changeFirstFlag(Long orderId) {
        Order order = orderDao.find(orderId);
        boolean flag;
        if (order.getFirstFlag()) {
            flag = false;
        } else {
            flag = true;
        }
        order.setFirstFlag(flag);
        orderDao.update(order);
    }

    /**
     *    ? ?
     *
     * @param orderId   ,    ? ?
     */
    public void selectChildOrderToPerform(Long orderId) {
        // ?  
        Order order = orderDao.find(orderId);
        order.setSelected(true);
        orderDao.update(order);
        // ? 
        Order parentOrder = order.getParentOrder();
        parentOrder.setChildSelected(true);
        parentOrder.setAuthor_salary(order.getDesiredCost());
        orderDao.update(parentOrder);
        // ?  ? ?  
        List<Order> childOrders = parentOrder.getChildOrders();
        for (Order childOrder : childOrders) {
            if (!Objects.equals(childOrder.getOrderId(), orderId)) {
                childOrder.setStatus(OrderStatus.REJECTION);
                orderDao.update(childOrder);
            }
        }
    }

    /**
     *      
     *
     * @param orderId
     * @param result
     */
    public void unloadInShop(Long orderId, ServiceResult result) throws Exception {
        Order order = orderDao.find(orderId);
        if (allowUnloadedInShop(order)) {
            String response = sendRequestForUnloadInShop(order, result);
            if (!result.hasErrors()) {
                checkResponse(response, result);
                if (!result.hasErrors()) {
                    order.setUnloadedInShop(true);
                    order.setDateUnloadingInShop(new Date());
                    orderDao.update(order);
                }
            }
        } else {
            result.addError(" ?     ?!");
        }
    }

    public void unloadMultipleInShop(Date dateFrom, Date dateTo) {
        List<Order> orderList = reportForUnloadInShop(dateFrom, dateTo);
        for (Order order : orderList) {
            if (!order.getAssignedUnloadedInShop() && !order.getUnloadedInShop()) {
                order.setAssignedUnloadedInShop(true);
                orderDao.update(order);
            }
        }
    }

    @Scheduled(fixedDelay = 60000)
    public void unloadInShopInCron() {
        final TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    List<Order> orders = orderDao.getAssignedUnloadedInShop();
                    for (Order order : orders) {
                        ServiceResult res = new ServiceResult();
                        unloadInShop(order, res);
                        if (res.hasErrors()) {
                            String error = res.getErrors().toString();
                            log.error("unloadInShop " + error);
                            order.setErrorUnloading(error);
                            orderDao.update(order);
                        } else {
                            order.setErrorUnloading("");
                            orderDao.update(order);
                        }
                    }
                } catch (Throwable e) {
                    log.error("unloadInShop " + StringAdapter.getStackExeption(e));
                }
            }
        });
    }

    /*
     @Scheduled(fixedDelay = 60000)
     public void unloadInShopInCron() {
     try {
     List<Order> orders = orderDao.getAssignedUnloadedInShop();
     for (Order order : orders) {
     ServiceResult res = new ServiceResult();
     unloadInShop(order, res);
     if (res.hasErrors()) {
     String error = res.getErrors().toString();
     log.error("unloadInShop " + error); 
     order.setErrorUnloading(error);
     orderDao.update(order);
     } else {
     order.setErrorUnloading("");
     orderDao.update(order); 
     }
     }
     } catch (Throwable e) {
     log.error("unloadInShop " + StringAdapter.getStackExeption(e));
     }
     }
     */
    private void unloadInShop(Order order, ServiceResult result) {
        try {
            String response = sendRequestForUnloadInShop(order, result);
            if (!result.hasErrors()) {
                checkResponse(response, result);
                if (!result.hasErrors()) {
                    order.setUnloadedInShop(true);
                    order.setDateUnloadingInShop(new Date());
                    orderDao.update(order);
                }
            }
        } catch (Exception e) {
            result.addError(StringAdapter.getStackExeption(e));
        }
    }

    private void checkResponse(String response, ServiceResult result) {
        if (response.contains("Upload file") && response.contains("Write to Database")) {
            return;
        } else {
            result.addError(
                    "  . ,  ?: "
                            + response);
        }
    }

    private String sendRequestForUnloadInShop(Order order, ServiceResult result) throws Exception {
        List<String> missing = new ArrayList();
        List<String> directionNames = new ArrayList();
        for (Direction dir : order.getDirections()) {
            String dirName = (dir.getNameForShop() != null ? dir.getNameForShop() : "");
            if (dirName.isEmpty()) {
                missing.add(
                        "? ?    ? ? "
                                + dir.getName());
            }
            directionNames.add(dirName);
        }
        String orderName = "";
        if (order.getOrderType() != null && order.getOrderType().getNameForShop() != null) {
            orderName = order.getOrderType().getNameForShop();
        }
        if (orderName.isEmpty()) {
            missing.add(
                    "? ?    ?  ");
        }
        String subject = (order.getSubject() != null ? order.getSubject() : "");
        if (subject.isEmpty()) {
            missing.add(" ");
        }
        String price = (order.getCost() != null ? order.getCost().toString() : "0");
        String numberOfPages = (order.getNumberOfPages() != null ? order.getNumberOfPages() : "");
        if (numberOfPages.isEmpty()) {
            missing.add("? ?");
        }
        String fileName = "order" + order.getOrderId() + ".zip";

        if (missing.isEmpty()) {
            String url = "http://zaochnik5.ru/up/uploadfile.php";
            HttpPost post = new HttpPost(url);
            MultipartEntityBuilder multipart = MultipartEntityBuilder.create();
            multipart.addTextBody("type_work", orderName);
            multipart.addTextBody("name_work", subject);
            multipart.addTextBody("price", price);
            multipart.addTextBody("table_of_contents", "-");
            for (String dirName : directionNames) {
                multipart.addTextBody("napravlenie", dirName);
            }
            multipart.addTextBody("kol-vo_str", numberOfPages);
            multipart.addTextBody("fail", fileName);
            multipart.addTextBody("order_number", order.getOrderId().toString());
            multipart.addTextBody("kol-vo_order", "1");
            multipart.addTextBody("published", "0");
            multipart.addTextBody("srvkey", "8D9ucTqL4Ga2ZkLCmctR");
            byte[] zipBytes = getZipAllReadyFiles(order);
            multipart.addPart("upload", new ByteArrayBody(zipBytes, fileName));
            HttpEntity ent = multipart.build();
            post.setEntity(ent);
            HttpClient client = HttpClients.createDefault();
            HttpResponse response = client.execute(post);
            return IOUtils.toString(response.getEntity().getContent());
        } else {
            String missingStr = "";
            for (String str : missing) {
                missingStr += str + ", ";
            }
            result.addError(
                    "?  ,  ?  :"
                            + missingStr);
            return "";
        }
    }

    private byte[] getZipAllReadyFiles(Order order) throws Exception {
        List<Long> fileIds = new ArrayList();
        for (ReadyOrderFile file : order.getReadyFiles()) {
            fileIds.add(file.getFileId());
        }
        Long[] fileArray = fileIds.toArray(new Long[0]);
        return fileService.getZipFile(fileArray);
    }

    /**
     *        
     *
     * @param order
     * @return
     */
    public boolean allowUnloadedInShop(Order order) {
        User authUser = authManager.getCurrentUser();
        return (authUser instanceof Admin && order.getStatus() != null
                && order.getStatus().equals(OrderStatus.READY)
                && (order.getUnloadedInShop() == null || order.getUnloadedInShop() == false));
    }

    /**
     *      
     *
     * @param order
     * @return
     */
    public boolean allowsReadyFiles(Order order) {
        OrderStatus status = order.getStatus();
        return (status != null && (status.equals(OrderStatus.WORKING) || status.equals(OrderStatus.REWORK)
                || status.equals(OrderStatus.CHECK) || status.equals(OrderStatus.READY)
                || status.equals(OrderStatus.ARCHIVE) || status.equals(OrderStatus.OTHER)));
    }

    /**
     * ?  
     *
     * @param orderId  
     */
    public void changeSecondFlag(Long orderId) {
        Order order = orderDao.find(orderId);
        boolean flag;
        if (order.getSecondFlag()) {
            flag = false;
        } else {
            flag = true;
        }
        order.setSecondFlag(flag);
        orderDao.update(order);
    }

    public Set<Long> getDelegatedBranchList(Long orderId) {
        List<Order> orders = orderDao.getDelegatedOrders(orderId);
        Set<Long> branchIds = new HashSet();
        for (Order order : orders) {
            if (order.getBranch() != null) {
                branchIds.add(order.getBranch().getBranchId());
            }
        }
        return branchIds;
    }

    /**
     *  ??.  ? ,     ?
     * ??.
     *
     * @param orders
     * @return
     */
    private List<Order> authorFilter(List<Order> orders) {
        User user = authManager.getCurrentUser();
        if (user instanceof Author) {
            Author author = (Author) user;
            List<Order> newOrders = new ArrayList();
            for (Order order : orders) {
                if (showOrderForAuthor(order, author)) {
                    newOrders.add(order);
                }
            }
            return newOrders;
        } else {
            return orders;
        }
    }

    private void setAllowReject(List<OrderListData> list) {
        for (OrderListData data : list) {
            data.allowReject = allowReject(data.order);
        }
    }

    private List<OrderListData> authorFilterByDataList(List<OrderListData> list) {
        User user = authManager.getCurrentUser();
        if (user instanceof Author) {
            Author author = (Author) user;
            List<OrderListData> newOrders = new ArrayList();
            for (OrderListData data : list) {
                Order order = data.order;
                if (showOrderForAuthor(order, author)) {
                    newOrders.add(data);
                }
            }
            return newOrders;
        } else {
            return list;
        }
    }

    private boolean showOrderForAuthor(Order order, Author author) {
        if (order.getAuthor() != null && order.getAuthor().getUserId().equals(author.getUserId())) {
            return true;
        } else if (order.getAuthor() == null) {
            if (existDirection(order, author)) {
                return true;
            }
        }
        return false;
    }

    private boolean existDirection(Order order, Author author) {
        List<Direction> authorDirs = author.getDirections();
        for (Direction orderDir : order.getDirections()) {
            if (authorDirs.contains(orderDir)) {
                return true;
            }
        }

        return false;
    }

    class OrderComparator implements Comparator<datastructure.OrderListData> {

        @Override
        public int compare(datastructure.OrderListData o1, datastructure.OrderListData o2) {
            if (o1.countNotReadyAuthorMessages > 0 && o2.countNotReadyAuthorMessages > 0) {
                return 0;
            } else if (o1.countNotReadyAuthorMessages == 0 && o2.countNotReadyAuthorMessages == 0) {
                return 0;
            } else if (o1.countNotReadyAuthorMessages > 0 && o2.countNotReadyAuthorMessages <= 0) {
                return -1;
            } else {
                return 1;
            }
        }

    }

    /**
     *  ?     ? 
     *
     * @return
     */
    public List<String> getOrderListHeaders(List<String> directionNames, List<Direction> allDirectionsList,
            List<String> orderTypeNames, List<OrderType> allOrderTypeList) {
        User authUser = authManager.getCurrentUser();
        if (authUser instanceof Admin) {
            return getAdminOrderListHeaders(directionNames, allDirectionsList, orderTypeNames, allOrderTypeList);
        } else if (authUser instanceof Author) {
            return getAuthorOrderListHeaders(directionNames, allDirectionsList, orderTypeNames, allOrderTypeList);
        }
        return new ArrayList();
    }

    public List<String> getAdminOrderListHeaders(List<String> directionNames, List<Direction> allDirectionsList,
            List<String> orderTypeNames, List<OrderType> allOrderTypeList) {
        List<String> res = new ArrayList();

        HashMap<Rights, Boolean> cr = new HashMap();
        for (Rights r : Rights.values()) {
            cr.put(r, UserRightsUtil.isRight(r));
        }

        res.add("<tr>");

        if (cr.get(Rights.TABLE_FLAGS)) {
            res.add("<th> </th>");
        }
        if (cr.get(Rights.TABLE_NUMBER)) {
            res.add("<th>?</th>");
        }

        if (cr.get(Rights.TABLE_DIRECTIONS)) {
            String header = "<th><div class='headDirectionDiv' >";
            if (directionNames.isEmpty()) {
                header += "?";
            } else {
                for (String name : directionNames) {
                    header += name + "<br/>";
                }
            }
            header += "</div><div class='headDirectionSelectDiv' style='display: none;' >";
            header += "<select name='directionId' multiple class='searchOrderdirectionSelect' ><option value='0'>-----</option>";
            for (Direction d : allDirectionsList) {
                header += "<option value=" + d.getId() + " "
                        + (directionNames.contains(d.getName()) ? "selected" : "") + ">" + d.getName()
                        + "</option>";
            }
            header += ">/select></div></th>";
            res.add(header);
        }

        if (cr.get(Rights.TABLE_TYPE)) {
            String header = "<th><div class='headOrderTypeDiv' >";
            if (directionNames.isEmpty()) {
                header += "  ";
            } else {
                for (String name : orderTypeNames) {
                    header += name + "<br/>";
                }
            }
            header += "</div><div class='headOrderTypeSelectDiv' style='display: none;' >";
            header += "<select name='orderTypeId' multiple class='searchOrderOrderTypesSelect' ><option value='0'>-----</option>";
            for (OrderType ot : allOrderTypeList) {
                header += "<option value=" + ot.getId() + " "
                        + (orderTypeNames.contains(ot.getName()) ? "selected" : "") + ">" + ot.getName()
                        + "</option>";
            }
            header += ">/select></div></th>";
            res.add(header);
        }

        if (cr.get(Rights.TABLE_SUBJECT)) {
            res.add("<th style='max-width: 200px !Important' ></th>");
        }
        if (cr.get(Rights.TABLE_DATE)) {
            res.add("<th></th>");
        }
        if (cr.get(Rights.TABLE_CLIENT)) {
            res.add("<th></th>");
        }
        if (cr.get(Rights.TABLE_PRICE)) {
            res.add("<th style='width: 100px;' >&nbsp;&nbsp;</th>");
        }
        if (cr.get(Rights.TABLE_PREPAYMENT)) {
            res.add("<th style='width: 100px;' >.</th>");
        }
        if (cr.get(Rights.TABLE_AUTHOR_SALARY)) {
            res.add("<th style='width: 100px;' >/ <br> </th>");
        }
        if (cr.get(Rights.TABLE_STATUS)) {
            res.add("<th>?</th>");
        }
        if (cr.get(Rights.TABLE_AUTHOR)) {
            res.add("<th>?</th>");
        }
        if (cr.get(Rights.TABLE_AUTHOR_MESSAGE)) {
            res.add("<th>. <br> </th>");
        }
        if (cr.get(Rights.TABLE_ADMIN_MESSAGE)) {
            res.add("<th>. <br> </th>");
        }
        res.add("</tr>");

        return res;
    }

    public List<String> getAuthorOrderListHeaders(List<String> directionNames, List<Direction> allDirectionsList,
            List<String> orderTypeNames, List<OrderType> allOrderTypeList) {
        List<String> res = new ArrayList();

        HashMap<Rights, Boolean> cr = new HashMap();
        for (Rights r : Rights.values()) {
            cr.put(r, UserRightsUtil.isRight(r));
        }

        res.add("<tr>");

        if (cr.get(Rights.TABLE_NUMBER)) {
            res.add("<th>?</th>");
        }

        if (cr.get(Rights.TABLE_DIRECTIONS)) {
            String header = "<th><div class='headDirectionDiv' >";
            if (directionNames.isEmpty()) {
                header += "?";
            } else {
                for (String name : directionNames) {
                    header += name + "<br/>";
                }
            }
            header += "</div><div class='headDirectionSelectDiv' style='display: none;' >";
            header += "<select name='directionId' multiple class='searchOrderdirectionSelect' ><option value='0'>-----</option>";
            for (Direction d : allDirectionsList) {
                header += "<option value=" + d.getId() + " "
                        + (directionNames.contains(d.getName()) ? "selected" : "") + ">" + d.getName()
                        + "</option>";
            }
            header += ">/select></div></th>";
            res.add(header);
        }

        if (cr.get(Rights.TABLE_TYPE)) {
            String header = "<th><div class='headOrderTypeDiv' >";
            if (directionNames.isEmpty()) {
                header += "  ";
            } else {
                for (String name : orderTypeNames) {
                    header += name + "<br/>";
                }
            }
            header += "</div><div class='headOrderTypeSelectDiv' style='display: none;' >";
            header += "<select name='orderTypeId' multiple class='searchOrderOrderTypesSelect' ><option value='0'>-----</option>";
            for (OrderType ot : allOrderTypeList) {
                header += "<option value=" + ot.getId() + " "
                        + (orderTypeNames.contains(ot.getName()) ? "selected" : "") + ">" + ot.getName()
                        + "</option>";
            }
            header += ">/select></div></th>";
            res.add(header);
        }

        if (cr.get(Rights.TABLE_SUBJECT)) {
            res.add("<th style='max-width: 200px !Important' ></th>");
        }
        if (cr.get(Rights.TABLE_DATE)) {
            res.add("<th></th>");
        }

        if (cr.get(Rights.TABLE_AUTHOR_SALARY)) {
            res.add("<th style='width: 100px;' ></th>");
        }

        if (cr.get(Rights.TABLE_STATUS)) {
            res.add("<th>?</th>");
        }
        if (cr.get(Rights.TABLE_AUTHOR_MESSAGE)) {
            res.add("<th>. <br> </th>");
        }
        res.add("<th>??</th>");
        res.add("</tr>");

        return res;
    }

    public String getAdminOrderListHeadersAsString(List<String> directionNames, List<Direction> allDirectionsList,
            List<String> orderTypeNames, List<OrderType> allOrderTypeList) {
        String res = "";

        HashMap<Rights, Boolean> cr = new HashMap();
        for (Rights r : Rights.values()) {
            cr.put(r, UserRightsUtil.isRight(r));
        }

        res = res.concat("<tr>");

        if (cr.get(Rights.TABLE_FLAGS)) {
            res = res.concat("<th> </th>");
        }
        if (cr.get(Rights.TABLE_NUMBER)) {
            res = res.concat("<th>?</th>");
        }

        if (cr.get(Rights.TABLE_DIRECTIONS)) {
            String header = "<th><div class='headDirectionDiv' >";
            if (directionNames.isEmpty()) {
                header += "?";
            } else {
                for (String name : directionNames) {
                    header += name + "<br/>";
                }
            }
            header += "</div><div class='headDirectionSelectDiv' style='display: none;' >";
            header += "<select name='directionId' multiple class='searchOrderdirectionSelect' ><option value='0'>-----</option>";
            for (Direction d : allDirectionsList) {
                header += "<option value=" + d.getId() + " "
                        + (directionNames.contains(d.getName()) ? "selected" : "") + ">" + d.getName()
                        + "</option>";
            }
            header += ">/select></div></th>";
            res = res.concat(header);
        }

        if (cr.get(Rights.TABLE_TYPE)) {
            String header = "<th><div class='headOrderTypeDiv' >";
            if (orderTypeNames.isEmpty()) {
                header += "  ";
            } else {
                for (String name : orderTypeNames) {
                    header += name + "<br/>";
                }
            }
            header += "</div><div class='headOrderTypeSelectDiv' style='display: none;' >";
            header += "<select name='orderTypeId' multiple class='searchOrderOrderTypesSelect' ><option value='0'>-----</option>";
            for (OrderType ot : allOrderTypeList) {
                header += "<option value=" + ot.getId() + " "
                        + (orderTypeNames.contains(ot.getName()) ? "selected" : "") + ">" + ot.getName()
                        + "</option>";
            }
            header += ">/select></div></th>";
            res = res.concat(header);
        }

        if (cr.get(Rights.TABLE_SUBJECT)) {
            res = res.concat("<th style='max-width: 200px !Important' ></th>");
        }
        if (cr.get(Rights.TABLE_DATE)) {
            res = res.concat("<th></th>");
        }
        if (cr.get(Rights.TABLE_CLIENT)) {
            res = res.concat("<th></th>");
        }
        if (cr.get(Rights.TABLE_PRICE)) {
            res = res.concat("<th style='width: 100px;' >&nbsp;&nbsp;</th>");
        }
        if (cr.get(Rights.TABLE_PREPAYMENT)) {
            res = res.concat("<th style='width: 100px;' >.</th>");
        }
        if (cr.get(Rights.TABLE_AUTHOR_SALARY)) {
            res = res.concat("<th style='width: 100px;' >/ <br> </th>");
        }
        if (cr.get(Rights.TABLE_STATUS)) {
            res = res.concat("<th>?</th>");
        }
        if (cr.get(Rights.TABLE_AUTHOR)) {
            res = res.concat("<th>?</th>");
        }
        if (cr.get(Rights.TABLE_AUTHOR_MESSAGE)) {
            res = res.concat("<th>. <br> </th>");
        }
        if (cr.get(Rights.TABLE_ADMIN_MESSAGE)) {
            res = res.concat("<th>. <br> </th>");
        }
        res = res.concat("</tr>");

        return res;
    }

}