/* * eGov suite of products aim to improve the internal efficiency,transparency, * accountability and the service delivery of the government organizations. * * Copyright (C) <2015> eGovernments Foundation * * The updated version of eGov suite of products as by eGovernments Foundation * is available at http://www.egovernments.org * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/ or * http://www.gnu.org/licenses/gpl.html . * * In addition to the terms of the GPL license to be adhered to in using this * program, the following additional terms are to be complied with: * * 1) All versions of this program, verbatim or modified must carry this * Legal Notice. * * 2) Any misrepresentation of the origin of the material is prohibited. It * is required that all modified versions of this material be marked in * reasonable ways as different from the original version. * * 3) This license does not grant any rights to any user of the program * with regards to rights under trademark law for use of the trade names * or trademarks of eGovernments Foundation. * * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. */ package org.egov.works.web.controller.contractorbill; import java.io.IOException; import java.math.BigDecimal; import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletRequest; import org.egov.commons.CChartOfAccounts; import org.egov.commons.dao.ChartOfAccountsHibernateDAO; import org.egov.egf.budget.model.BudgetControlType; import org.egov.egf.budget.service.BudgetControlTypeService; import org.egov.eis.web.contract.WorkflowContainer; import org.egov.eis.web.controller.workflow.GenericWorkFlowController; import org.egov.infra.exception.ApplicationRuntimeException; import org.egov.infra.utils.autonumber.AutonumberServiceBeanResolver; import org.egov.infra.validation.exception.ValidationException; import org.egov.model.bills.EgBilldetails; import org.egov.works.abstractestimate.entity.AbstractEstimate; import org.egov.works.abstractestimate.service.EstimateService; import org.egov.works.autonumber.ContractorBillNumberGenerator; import org.egov.works.contractorbill.entity.ContractorBillRegister; import org.egov.works.contractorbill.entity.enums.BillTypes; import org.egov.works.contractorbill.service.ContractorBillRegisterService; import org.egov.works.letterofacceptance.service.LetterOfAcceptanceService; import org.egov.works.lineestimate.entity.LineEstimateDetails; import org.egov.works.lineestimate.service.LineEstimateService; import org.egov.works.models.workorder.WorkOrder; import org.egov.works.models.workorder.WorkOrderEstimate; import org.egov.works.utils.WorksConstants; import org.egov.works.utils.WorksUtils; import org.egov.works.workorderestimate.service.WorkOrderEstimateService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.MessageSource; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; @Controller @RequestMapping(value = "/contractorbill") public class CreateContractorBillController extends GenericWorkFlowController { @Autowired private LineEstimateService lineEstimateService; @Autowired private LetterOfAcceptanceService letterOfAcceptanceService; @Autowired private ContractorBillRegisterService contractorBillRegisterService; @Autowired private AutonumberServiceBeanResolver beanResolver; @Autowired private WorksUtils worksUtils; @Autowired @Qualifier("messageSource") private MessageSource messageSource; @Autowired private ChartOfAccountsHibernateDAO chartOfAccountsHibernateDAO; @Autowired private WorkOrderEstimateService workOrderEstimateService; @Autowired private EstimateService estimateService; @Autowired private BudgetControlTypeService budgetControlTypeService; @RequestMapping(value = "/newform", method = RequestMethod.GET) public String showNewForm( @ModelAttribute("contractorBillRegister") final ContractorBillRegister contractorBillRegister, final Model model, final HttpServletRequest request) { final String loaNumber = request.getParameter("loaNumber"); final WorkOrder workOrder = letterOfAcceptanceService.getApprovedWorkOrder(loaNumber); final LineEstimateDetails lineEstimateDetails = lineEstimateService .findByEstimateNumber(workOrder.getEstimateNumber()); setDropDownValues(model); model.addAttribute("stateType", contractorBillRegister.getClass().getSimpleName()); prepareWorkflow(model, contractorBillRegister, new WorkflowContainer()); model.addAttribute("mode", "edit"); // TODO: remove this condition to check if spillover if (!lineEstimateDetails.getLineEstimate().isSpillOverFlag()) contractorBillRegister.setBilldate(new Date()); final WorkOrderEstimate workOrderEstimate = workOrderEstimateService.getWorkOrderEstimateByWorkOrderId(workOrder.getId()); model.addAttribute("workOrderEstimate", workOrderEstimate); model.addAttribute("workOrder", workOrder); model.addAttribute("lineEstimateDetails", lineEstimateDetails); model.addAttribute("contractorBillRegister", contractorBillRegister); return "contractorBill-form"; } private void setDropDownValues(final Model model) { final List<CChartOfAccounts> contractorPayableAccountList = chartOfAccountsHibernateDAO .getAccountCodeByPurposeName(WorksConstants.CONTRACTOR_NETPAYABLE_PURPOSE); final List<CChartOfAccounts> contractorRefundAccountList = chartOfAccountsHibernateDAO .getAccountCodeByListOfPurposeName(WorksConstants.CONTRACTOR_REFUND_PURPOSE); model.addAttribute("netPayableAccounCodes", contractorPayableAccountList); model.addAttribute("refundAccounCodes", contractorRefundAccountList); model.addAttribute("billTypes", BillTypes.values()); } @RequestMapping(value = "/contractorbill-save", method = RequestMethod.POST) public String create(@ModelAttribute("contractorBillRegister") ContractorBillRegister contractorBillRegister, final Model model, final BindingResult resultBinder, final HttpServletRequest request, @RequestParam String workFlowAction, @RequestParam("file") final MultipartFile[] files) throws IOException { final String loaNumber = request.getParameter("loaNumber"); final WorkOrder workOrder = letterOfAcceptanceService.getApprovedWorkOrder(loaNumber); final Date workCompletionDate = contractorBillRegister.getWorkOrderEstimate().getWorkCompletionDate(); final LineEstimateDetails lineEstimateDetails = lineEstimateService .findByEstimateNumber(workOrder.getEstimateNumber()); final AbstractEstimate abstractEstimate = estimateService .getAbstractEstimateByEstimateNumberAndStatus(lineEstimateDetails.getEstimateNumber()); final WorkOrderEstimate workOrderEstimate = workOrderEstimateService .getEstimateByWorkOrderAndEstimateAndStatus(workOrder.getId(), abstractEstimate.getId()); contractorBillRegister.setWorkOrder(workOrder); contractorBillRegister.setWorkOrderEstimate(workOrderEstimate); contractorBillRegister.getWorkOrderEstimate().setWorkCompletionDate(workCompletionDate); validateInput(contractorBillRegister, lineEstimateDetails, resultBinder, request); contractorBillRegister = addBillDetails(contractorBillRegister, lineEstimateDetails, resultBinder, request); contractorBillRegisterService.validateRefundAmount(contractorBillRegister, resultBinder); contractorBillRegisterService.validateMileStonePercentage(contractorBillRegister, resultBinder); if (!contractorBillRegisterService.checkForDuplicateAccountCodes(contractorBillRegister)) resultBinder.reject("error.contractorbill.duplicate.accountcodes", "error.contractorbill.duplicate.accountcodes"); if (!contractorBillRegisterService.validateDuplicateRefundAccountCodes(contractorBillRegister)) resultBinder.reject("error.contractorbill.duplicate.refund.accountcodes", "error.contractorbill.duplicate.refund.accountcodes"); contractorBillRegisterService.validateTotalDebitAndCreditAmount(contractorBillRegister, resultBinder); if (resultBinder.hasErrors()) { setDropDownValues(model); model.addAttribute("lineEstimateDetails", lineEstimateDetails); model.addAttribute("workOrder", workOrder); model.addAttribute("workOrderEstimate", workOrderEstimate); model.addAttribute("netPayableAmount", request.getParameter("netPayableAmount")); model.addAttribute("netPayableAccountCode", request.getParameter("netPayableAccountCode")); model.addAttribute("stateType", contractorBillRegister.getClass().getSimpleName()); model.addAttribute("approvalDesignation", request.getParameter("approvalDesignation")); model.addAttribute("approvalPosition", request.getParameter("approvalPosition")); prepareWorkflow(model, contractorBillRegister, new WorkflowContainer()); model.addAttribute("mode", "edit"); model.addAttribute("billDetailsMap", contractorBillRegisterService.getBillDetailsMap(contractorBillRegister, model)); return "contractorBill-form"; } else { Long approvalPosition = 0l; String approvalComment = ""; if (request.getParameter("approvalComment") != null) approvalComment = request.getParameter("approvalComent"); if (request.getParameter("workFlowAction") != null) workFlowAction = request.getParameter("workFlowAction"); if (request.getParameter("approvalPosition") != null && !request.getParameter("approvalPosition").isEmpty()) approvalPosition = Long.valueOf(request.getParameter("approvalPosition")); Integer partBillCount = contractorBillRegisterService.getMaxSequenceNumberByWorkOrder(workOrderEstimate); if (partBillCount == null || partBillCount == 0) partBillCount = 1; else partBillCount++; contractorBillRegister.setBillSequenceNumber(partBillCount); final ContractorBillNumberGenerator c = beanResolver.getAutoNumberServiceFor(ContractorBillNumberGenerator.class); final String contractorBillNumber = c.getNextNumber(contractorBillRegister); contractorBillRegister.setBillnumber(contractorBillNumber); contractorBillRegister.setPassedamount(contractorBillRegister.getBillamount()); ContractorBillRegister savedContractorBillRegister = null; try { savedContractorBillRegister = contractorBillRegisterService.create(contractorBillRegister, lineEstimateDetails, files, approvalPosition, approvalComment, null, workFlowAction); } catch (final ValidationException e) { // TODO: Used ApplicationRuntimeException for time being since // there is issue in session after // checkBudgetAndGenerateBANumber API call. Needs to replace // with errors.reject throw new ApplicationRuntimeException("error.contractorbill.budgetcheck.insufficient.amount"); /* * for (final ValidationError error : e.getErrors()) { if(error.getMessage().contains("Budget Check failed for ")) * { errors.reject(messageSource.getMessage( "error.contractorbill.budgetcheck.insufficient.amount",null, null)+ * ". " +error.getMessage()); } else errors.reject(error.getMessage()); } */ } final String pathVars = worksUtils.getPathVars(savedContractorBillRegister.getStatus(), savedContractorBillRegister.getState(), savedContractorBillRegister.getId(), approvalPosition); return "redirect:/contractorbill/contractorbill-success?pathVars=" + pathVars + "&billNumber=" + savedContractorBillRegister.getBillnumber(); } } @RequestMapping(value = "/contractorbill-success", method = RequestMethod.GET) public String showContractorBillSuccessPage(@RequestParam("billNumber") final String billNumber, final Model model, final HttpServletRequest request) { final String[] keyNameArray = request.getParameter("pathVars").split(","); Long id = 0L; String approverName = ""; String currentUserDesgn = ""; String nextDesign = ""; if (keyNameArray.length != 0 && keyNameArray.length > 0) if (keyNameArray.length == 1) id = Long.parseLong(keyNameArray[0]); else if (keyNameArray.length == 3) { id = Long.parseLong(keyNameArray[0]); approverName = keyNameArray[1]; currentUserDesgn = keyNameArray[2]; } else { id = Long.parseLong(keyNameArray[0]); approverName = keyNameArray[1]; currentUserDesgn = keyNameArray[2]; nextDesign = keyNameArray[3]; } if (id != null) model.addAttribute("approverName", approverName); model.addAttribute("currentUserDesgn", currentUserDesgn); model.addAttribute("nextDesign", nextDesign); final ContractorBillRegister contractorBillRegister = contractorBillRegisterService .getContractorBillByBillNumber(billNumber); final String message = getMessageByStatus(contractorBillRegister, approverName, nextDesign); model.addAttribute("message", message); model.addAttribute("contractorBillRegister", contractorBillRegister); return "contractorBill-success"; } private void validateInput(final ContractorBillRegister contractorBillRegister, final LineEstimateDetails lineEstimateDetails, final BindingResult resultBinder, final HttpServletRequest request) { final boolean validateBillInWorkflow = letterOfAcceptanceService .validateContractorBillInWorkflowForWorkorder(contractorBillRegister.getWorkOrder().getId()); if (!validateBillInWorkflow) resultBinder.reject("error.contractorbill.in.workflow.for.workorder", new String[] { contractorBillRegister.getWorkOrder().getWorkOrderNumber() }, null); BigDecimal totalBillAmountIncludingCurrentBill = contractorBillRegister.getBillamount(); final BigDecimal totalBillAmount = contractorBillRegisterService .getTotalBillAmountByWorkOrder(contractorBillRegister.getWorkOrder()); if (totalBillAmount != null) totalBillAmountIncludingCurrentBill = totalBillAmountIncludingCurrentBill.add(totalBillAmount); if (lineEstimateDetails.getLineEstimate().isBillsCreated() && lineEstimateDetails.getGrossAmountBilled() != null) totalBillAmountIncludingCurrentBill = totalBillAmountIncludingCurrentBill .add(lineEstimateDetails.getGrossAmountBilled()); if (totalBillAmountIncludingCurrentBill.doubleValue() > contractorBillRegister.getWorkOrder() .getWorkOrderAmount()) resultBinder.reject("error.contractorbill.totalbillamount.exceeds.workorderamount", new String[] { String.valueOf(totalBillAmountIncludingCurrentBill), String.valueOf(contractorBillRegister.getWorkOrder().getWorkOrderAmount()) }, null); if (org.apache.commons.lang.StringUtils.isBlank(contractorBillRegister.getBilltype())) resultBinder.rejectValue("billtype", "error.billtype.required"); if (contractorBillRegister.getEgBillregistermis() != null && contractorBillRegister.getEgBillregistermis().getPartyBillDate() != null && contractorBillRegister.getEgBillregistermis().getPartyBillDate() .before(contractorBillRegister.getWorkOrder().getWorkOrderDate())) resultBinder.rejectValue("egBillregistermis.partyBillDate", "error.validate.partybilldate.lessthan.loadate"); if (contractorBillRegister.getMbHeader() != null) { if (org.apache.commons.lang.StringUtils.isBlank(contractorBillRegister.getMbHeader().getMbRefNo())) resultBinder.rejectValue("mbHeader.mbRefNo", "error.mbrefno.required"); if (contractorBillRegister.getMbHeader().getMbDate() == null) resultBinder.rejectValue("mbHeader.mbDate", "error.mbdate.required"); if (contractorBillRegister.getMbHeader().getFromPageNo() == null) resultBinder.rejectValue("mbHeader.fromPageNo", "error.frompageno.required"); if (contractorBillRegister.getMbHeader().getToPageNo() == null) resultBinder.rejectValue("mbHeader.toPageNo", "error.topageno.required"); if (contractorBillRegister.getMbHeader().getFromPageNo() == 0 || contractorBillRegister.getMbHeader().getToPageNo() == 0) resultBinder.reject("error.validate.mb.pagenumbers.zero", "error.validate.mb.pagenumbers.zero"); if (contractorBillRegister.getMbHeader().getFromPageNo() != null && contractorBillRegister.getMbHeader().getToPageNo() != null && contractorBillRegister .getMbHeader().getFromPageNo() > contractorBillRegister.getMbHeader().getToPageNo()) resultBinder.reject("error.validate.mb.frompagenumber.greaterthan.topagenumber", "error.validate.mb.frompagenumber.greaterthan.topagenumber"); if (contractorBillRegister.getMbHeader().getMbDate() != null && contractorBillRegister.getMbHeader() .getMbDate().before(contractorBillRegister.getWorkOrder().getWorkOrderDate())) resultBinder.rejectValue("mbHeader.mbDate", "error.validate.mbdate.lessthan.loadate"); } if (org.apache.commons.lang.StringUtils.isBlank(request.getParameter("netPayableAccountCode"))) resultBinder.reject("error.netpayable.accountcode.required", "error.netpayable.accountcode.required"); if (org.apache.commons.lang.StringUtils.isBlank(request.getParameter("netPayableAmount")) || Double.valueOf(request.getParameter("netPayableAmount").toString()) <= 0) resultBinder.reject("error.netpayable.amount.required", "error.netpayable.amount.required"); // TODO: from this line code should be removed after user data entry is // finished. if (contractorBillRegister.getEgBillregistermis() != null && contractorBillRegister.getEgBillregistermis().getPartyBillDate() != null && contractorBillRegister .getEgBillregistermis().getPartyBillDate().after(contractorBillRegister.getBilldate())) resultBinder.rejectValue("egBillregistermis.partyBillDate", "error.partybilldate.billdate"); final Date workCompletionDate = contractorBillRegister.getWorkOrderEstimate().getWorkCompletionDate(); if (contractorBillRegister.getBilltype().equals(BillTypes.Final_Bill.toString()) && workCompletionDate == null) resultBinder.rejectValue("workOrderEstimate.workCompletionDate", "error.workcompletiondate.required"); final Date currentDate = new Date(); if (workCompletionDate != null) { if (workCompletionDate.after(currentDate)) resultBinder.rejectValue("workOrderEstimate.workCompletionDate", "error.workcompletiondate.futuredate"); if (workCompletionDate .before(contractorBillRegister.getWorkOrderEstimate().getWorkOrder().getWorkOrderDate())) resultBinder.rejectValue("workOrderEstimate.workCompletionDate", "error.workcompletiondate.workorderdate"); if (workCompletionDate.after(contractorBillRegister.getBilldate())) resultBinder.rejectValue("workOrderEstimate.workCompletionDate", "error.workcompletiondate.billdate"); } if (lineEstimateDetails.getLineEstimate().isSpillOverFlag()) { final Date currentFinYear = lineEstimateService.getCurrentFinancialYear(currentDate).getStartingDate(); if (contractorBillRegister.getBilldate().after(currentDate)) resultBinder.rejectValue("billdate", "error.billdate.futuredate"); if (contractorBillRegister.getBilldate().before(contractorBillRegister.getWorkOrder().getWorkOrderDate())) resultBinder.rejectValue("billdate", "error.billdate.workorderdate"); if (contractorBillRegister.getBilldate().before(currentFinYear)) resultBinder.rejectValue("billdate", "error.billdate.finyear"); } } private String getMessageByStatus(final ContractorBillRegister contractorBillRegister, final String approverName, final String nextDesign) { String message = ""; if (contractorBillRegister.getStatus().getCode().equals(ContractorBillRegister.BillStatus.CREATED.toString())) { if (org.apache.commons.lang.StringUtils .isNotBlank(contractorBillRegister.getEgBillregistermis().getBudgetaryAppnumber()) && !BudgetControlType.BudgetCheckOption.NONE.toString() .equalsIgnoreCase(budgetControlTypeService.getConfigValue())) message = messageSource.getMessage("msg.contractorbill.create.success.with.budgetappropriation", new String[] { contractorBillRegister.getBillnumber(), approverName, nextDesign, contractorBillRegister.getEgBillregistermis().getBudgetaryAppnumber() }, null); else message = messageSource.getMessage("msg.contractorbill.create.success", new String[] { contractorBillRegister.getBillnumber(), approverName, nextDesign }, null); } else if (contractorBillRegister.getStatus().getCode() .equals(ContractorBillRegister.BillStatus.APPROVED.toString())) message = messageSource.getMessage("msg.contractorbill.approved.success", new String[] { contractorBillRegister.getBillnumber() }, null); else if (contractorBillRegister.getState().getValue().equals(WorksConstants.WF_STATE_REJECTED)) message = messageSource.getMessage("msg.contractorbill.reject", new String[] { contractorBillRegister.getBillnumber(), approverName, nextDesign }, null); else if (contractorBillRegister.getState().getValue().equals(WorksConstants.WF_STATE_CANCELLED)) message = messageSource.getMessage("msg.contractorbill.cancel", new String[] { contractorBillRegister.getBillnumber() }, null); return message; } private ContractorBillRegister addBillDetails(final ContractorBillRegister contractorBillRegister, final LineEstimateDetails lineEstimateDetails, final BindingResult resultBinder, final HttpServletRequest request) { if (contractorBillRegister.getBillDetailes() == null || contractorBillRegister.getBillDetailes().isEmpty()) resultBinder.reject("error.contractorbill.accountdetails.required", "error.contractorbill.accountdetails.required"); for (final EgBilldetails egBilldetails : contractorBillRegister.getBillDetailes()) if (!contractorBillRegister.getEgBilldetailes().isEmpty() && contractorBillRegister.getEgBilldetailes().size() == 1) { for (final EgBilldetails refundBill : contractorBillRegister.getRefundBillDetails()) if (refundBill.getGlcodeid() != null) contractorBillRegister.addEgBilldetailes( contractorBillRegisterService.getBillDetails(contractorBillRegister, refundBill, lineEstimateDetails, resultBinder, request)); if (egBilldetails.getGlcodeid() != null) contractorBillRegister .addEgBilldetailes(contractorBillRegisterService.getBillDetails(contractorBillRegister, egBilldetails, lineEstimateDetails, resultBinder, request)); } else if (egBilldetails.getGlcodeid() != null) contractorBillRegister .addEgBilldetailes(contractorBillRegisterService.getBillDetails(contractorBillRegister, egBilldetails, lineEstimateDetails, resultBinder, request)); contractorBillRegisterService.validateZeroCreditAndDebitAmount(contractorBillRegister, resultBinder); final String netPayableAccountCodeId = request.getParameter("netPayableAccountCode"); final String netPayableAmount = request.getParameter("netPayableAmount"); if (org.apache.commons.lang.StringUtils.isNotBlank(netPayableAccountCodeId) && org.apache.commons.lang.StringUtils.isNotBlank(netPayableAmount)) { final EgBilldetails billdetails = new EgBilldetails(); billdetails.setGlcodeid(new BigDecimal(netPayableAccountCodeId)); billdetails.setCreditamount(new BigDecimal(netPayableAmount)); contractorBillRegister.addEgBilldetailes( contractorBillRegisterService.getBillDetails(contractorBillRegister, billdetails, lineEstimateDetails, resultBinder, request)); } return contractorBillRegister; } }