/*
* 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.tl.service;
import org.egov.commons.Installment;
import org.egov.commons.dao.EgwStatusHibernateDAO;
import org.egov.commons.dao.InstallmentHibDao;
import org.egov.demand.dao.DemandGenericHibDao;
import org.egov.demand.model.EgDemandDetails;
import org.egov.demand.model.EgDemandReason;
import org.egov.demand.model.EgDemandReasonMaster;
import org.egov.eis.entity.Assignment;
import org.egov.eis.service.AssignmentService;
import org.egov.eis.service.PositionMasterService;
import org.egov.infra.admin.master.entity.Module;
import org.egov.infra.admin.master.entity.User;
import org.egov.infra.filestore.entity.FileStoreMapper;
import org.egov.infra.filestore.service.FileStoreService;
import org.egov.infra.security.utils.SecurityUtils;
import org.egov.infra.validation.exception.ValidationException;
import org.egov.infra.workflow.matrix.entity.WorkFlowMatrix;
import org.egov.infra.workflow.service.SimpleWorkflowService;
import org.egov.infstr.services.PersistenceService;
import org.egov.pims.commons.Position;
import org.egov.tl.entity.FeeMatrixDetail;
import org.egov.tl.entity.License;
import org.egov.tl.entity.LicenseAppType;
import org.egov.tl.entity.LicenseDemand;
import org.egov.tl.entity.LicenseDocument;
import org.egov.tl.entity.LicenseDocumentType;
import org.egov.tl.entity.NatureOfBusiness;
import org.egov.tl.entity.WorkflowBean;
import org.egov.tl.entity.enums.ApplicationType;
import org.egov.tl.repository.LicenseRepository;
import org.egov.tl.utils.Constants;
import org.egov.tl.utils.LicenseNumberUtils;
import org.hibernate.CacheMode;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinType;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import static java.math.BigDecimal.ZERO;
import static org.egov.tl.utils.Constants.APPLICATION_STATUS_CREATED_CODE;
import static org.egov.tl.utils.Constants.BUTTONAPPROVE;
import static org.egov.tl.utils.Constants.BUTTONREJECT;
import static org.egov.tl.utils.Constants.GENERATECERTIFICATE;
import static org.egov.tl.utils.Constants.LICENSE_STATUS_ACKNOWLEDGED;
import static org.egov.tl.utils.Constants.LICENSE_STATUS_ACTIVE;
import static org.egov.tl.utils.Constants.TRADELICENSEMODULE;
import static org.egov.tl.utils.Constants.WF_STATE_SANITORY_INSPECTOR_APPROVAL_PENDING;
import static org.egov.tl.utils.Constants.WORKFLOW_STATE_REJECTED;
@Transactional(readOnly = true)
public abstract class AbstractLicenseService<T extends License> {
public static final String ARREAR = "arrear";
@Autowired
@Qualifier("entityQueryService")
protected PersistenceService entityQueryService;
@Autowired
protected InstallmentHibDao installmentDao;
@Autowired
protected LicenseNumberUtils licenseNumberUtils;
@Autowired
protected DocumentTypeService documentTypeService;
@Autowired
protected AssignmentService assignmentService;
@Autowired
protected FileStoreService fileStoreService;
@Autowired
protected FeeMatrixService feeMatrixService;
@Autowired
@Qualifier("licenseDocumentTypeService")
protected PersistenceService<LicenseDocumentType, Long> licenseDocumentTypeService;
@Autowired
protected TradeLicenseUpdateIndexService updateIndexService;
@Autowired
protected SecurityUtils securityUtils;
@Autowired
protected DemandGenericHibDao demandGenericDao;
@Autowired
protected ValidityService validityService;
protected SimpleWorkflowService<T> licenseWorkflowService;
@Autowired
protected LicenseRepository licenseRepository;
@Autowired
protected LicenseStatusService licenseStatusService;
@Autowired
private EgwStatusHibernateDAO egwStatusHibernateDAO;
@Autowired
protected LicenseAppTypeService licenseAppTypeService;
@Autowired
protected PositionMasterService positionMasterService;
@Autowired
protected NatureOfBusinessService natureOfBusinessService;
protected abstract LicenseAppType getLicenseApplicationTypeForRenew();
protected abstract LicenseAppType getLicenseApplicationType();
protected abstract Module getModuleName();
protected abstract NatureOfBusiness getNatureOfBusiness();
protected abstract void sendEmailAndSMS(T license, String currentAction);
public void setLicenseWorkflowService(SimpleWorkflowService<T> licenseWorkflowService) {
this.licenseWorkflowService = licenseWorkflowService;
}
public T getLicenseById(Long id) {
return (T) this.licenseRepository.findOne(id);
}
@Transactional
public void create(T license, WorkflowBean workflowBean) {
license.setLicenseAppType(getLicenseApplicationType());
raiseNewDemand(license);
license.getLicensee().setLicense(license);
license.setStatus(licenseStatusService.getLicenseStatusByName(LICENSE_STATUS_ACKNOWLEDGED));
license.setEgwStatus(egwStatusHibernateDAO.getStatusByModuleAndCode(TRADELICENSEMODULE, APPLICATION_STATUS_CREATED_CODE));
license.setApplicationNumber(licenseNumberUtils.generateApplicationNumber());
processAndStoreDocument(license.getDocuments(), license);
transitionWorkFlow(license, workflowBean);
licenseRepository.save(license);
sendEmailAndSMS(license, workflowBean.getWorkFlowAction());
updateIndexService.updateTradeLicenseIndexes(license);
}
private BigDecimal raiseNewDemand(T license) {
LicenseDemand ld = new LicenseDemand();
Module moduleName = this.getModuleName();
BigDecimal totalAmount = ZERO;
Installment installment = this.installmentDao.getInsatllmentByModuleForGivenDate(moduleName,
license.getApplicationDate());
ld.setIsHistory("N");
ld.setEgInstallmentMaster(installment);
ld.setLicense(license);
ld.setIsLateRenewal('0');
ld.setCreateDate(new Date());
List<FeeMatrixDetail> feeMatrixDetails = this.feeMatrixService.findFeeList(license);
for (FeeMatrixDetail fm : feeMatrixDetails) {
EgDemandReasonMaster reasonMaster = this.demandGenericDao
.getDemandReasonMasterByCode(fm.getFeeMatrix().getFeeType().getName(), moduleName);
EgDemandReason reason = this.demandGenericDao.getDmdReasonByDmdReasonMsterInstallAndMod(reasonMaster, installment,
moduleName);
if (fm.getFeeMatrix().getFeeType().getName().contains("Late"))
continue;
if (reason != null) {
ld.getEgDemandDetails().add(EgDemandDetails.fromReasonAndAmounts(fm.getAmount(), reason, ZERO));
totalAmount = totalAmount.add(fm.getAmount());
}
}
ld.setBaseDemand(totalAmount);
license.setLicenseDemand(ld);
return totalAmount;
}
public License updateDemandForChangeTradeArea(T license) {
LicenseDemand licenseDemand = license.getLicenseDemand();
Module moduleName = this.getModuleName();
Installment installment = this.installmentDao.getInsatllmentByModuleForGivenDate(moduleName,
license.getApplicationDate());
Set<EgDemandDetails> demandDetails = licenseDemand.getEgDemandDetails();
List<FeeMatrixDetail> feeList = this.feeMatrixService.findFeeList(license);
for (EgDemandDetails dmd : demandDetails)
for (FeeMatrixDetail fm : feeList)
if (installment.getId().equals(dmd.getEgDemandReason().getEgInstallmentMaster().getId()) &&
(dmd.getEgDemandReason().getEgDemandReasonMaster().getCode()
.equalsIgnoreCase(fm.getFeeMatrix().getFeeType().getName()))) {
dmd.setAmount(fm.getAmount());
dmd.setModifiedDate(new Date());
}
this.recalculateBaseDemand(licenseDemand);
return license;
}
@Transactional
public BigDecimal recalculateDemand(List<FeeMatrixDetail> feeList, T license) {
Installment installment = this.installmentDao.getInsatllmentByModuleForGivenDate(this.getModuleName(), new Date());
BigDecimal totalAmount = ZERO;
LicenseDemand licenseDemand = license.getCurrentDemand();
// Recalculating current demand detail according to fee matrix
for (EgDemandDetails dmd : licenseDemand.getEgDemandDetails())
for (FeeMatrixDetail fm : feeList)
if (installment.getId().equals(dmd.getEgDemandReason().getEgInstallmentMaster().getId()) &&
(dmd.getEgDemandReason().getEgDemandReasonMaster().getCode()
.equalsIgnoreCase(fm.getFeeMatrix().getFeeType().getName()))) {
dmd.setAmount(fm.getAmount());
dmd.setAmtCollected(ZERO);
totalAmount = totalAmount.add(fm.getAmount());
}
this.recalculateBaseDemand(licenseDemand);
return totalAmount;
}
@Transactional
public void createLegacyLicense(T license, Map<Integer, Integer> legacyInstallmentwiseFees,
Map<Integer, Boolean> legacyFeePayStatus) {
if (!licenseRepository.findByOldLicenseNumber(license.getOldLicenseNumber())
.isEmpty())
throw new ValidationException("TL-001", "TL-001", license.getOldLicenseNumber());
this.addLegacyDemand(legacyInstallmentwiseFees, legacyFeePayStatus, license);
processAndStoreDocument(license.getDocuments(), license);
license.setLicenseAppType(getLicenseApplicationType());
license.getLicensee().setLicense(license);
license.setStatus(licenseStatusService.getLicenseStatusByName(LICENSE_STATUS_ACTIVE));
license.setApplicationNumber(licenseNumberUtils.generateApplicationNumber());
license.setLegacy(true);
license.setActive(true);
license.setLicenseNumber(licenseNumberUtils.generateLicenseNumber());
this.validityService.applyLicenseValidity(license);
licenseRepository.save(license);
}
private void addLegacyDemand(Map<Integer, Integer> legacyInstallmentwiseFees,
Map<Integer, Boolean> legacyFeePayStatus,
T license) {
LicenseDemand licenseDemand = new LicenseDemand();
licenseDemand.setIsHistory("N");
licenseDemand.setCreateDate(new Date());
licenseDemand.setLicense(license);
licenseDemand.setIsLateRenewal('0');
Module module = this.getModuleName();
for (Entry<Integer, Integer> legacyInstallmentwiseFee : legacyInstallmentwiseFees.entrySet())
if (legacyInstallmentwiseFee.getValue() != null && legacyInstallmentwiseFee.getValue() > 0) {
Installment installment = this.installmentDao.fetchInstallmentByModuleAndInstallmentNumber(module,
legacyInstallmentwiseFee.getKey());
licenseDemand.setEgInstallmentMaster(installment);
BigDecimal demandAmount = BigDecimal.valueOf(legacyInstallmentwiseFee.getValue());
BigDecimal amtCollected = legacyFeePayStatus.get(legacyInstallmentwiseFee.getKey()) == null
|| !legacyFeePayStatus.get(legacyInstallmentwiseFee.getKey()) ? ZERO : demandAmount;
licenseDemand.getEgDemandDetails().add(
EgDemandDetails.fromReasonAndAmounts(demandAmount,
this.demandGenericDao.getDmdReasonByDmdReasonMsterInstallAndMod(
this.demandGenericDao.getDemandReasonMasterByCode("License Fee", module),
installment, module),
amtCollected));
licenseDemand.setBaseDemand(demandAmount.add(licenseDemand.getBaseDemand()));
licenseDemand.setAmtCollected(amtCollected.add(licenseDemand.getAmtCollected()));
}
license.setLicenseDemand(licenseDemand);
}
@Transactional
public void updateLegacyLicense(T license, Map<Integer, Integer> updatedInstallmentFees,
Map<Integer, Boolean> legacyFeePayStatus) {
this.updateLegacyDemand(license, updatedInstallmentFees, legacyFeePayStatus);
processAndStoreDocument(license.getDocuments(), license);
licenseRepository.save(license);
}
private void updateLegacyDemand(T license, Map<Integer, Integer> updatedInstallmentFees,
Map<Integer, Boolean> legacyFeePayStatus) {
LicenseDemand licenseDemand = license.getCurrentDemand();
// Update existing demand details
Iterator<EgDemandDetails> demandDetails = licenseDemand.getEgDemandDetails().iterator();
while (demandDetails.hasNext()) {
EgDemandDetails demandDetail = demandDetails.next();
Integer installmentNumber = demandDetail.getEgDemandReason().getEgInstallmentMaster()
.getInstallmentNumber();
Integer updatedFee = updatedInstallmentFees.get(installmentNumber);
Boolean feePaymentStatus = legacyFeePayStatus.get(installmentNumber);
if (updatedFee != null) {
BigDecimal updatedDemandAmt = BigDecimal.valueOf(updatedFee);
demandDetail.setAmount(updatedDemandAmt);
if (feePaymentStatus != null && feePaymentStatus)
demandDetail.setAmtCollected(updatedDemandAmt);
else
demandDetail.setAmtCollected(ZERO);
} else
demandDetails.remove();
updatedInstallmentFees.put(installmentNumber, 0);
}
// Create demand details which is newly entered
Module module = this.getModuleName();
for (Entry<Integer, Integer> updatedInstallmentFee : updatedInstallmentFees.entrySet())
if (updatedInstallmentFee.getValue() != null && updatedInstallmentFee.getValue() > 0) {
Installment installment = this.installmentDao.fetchInstallmentByModuleAndInstallmentNumber(module,
updatedInstallmentFee.getKey());
BigDecimal demandAmount = BigDecimal.valueOf(updatedInstallmentFee.getValue());
BigDecimal amtCollected = legacyFeePayStatus.get(updatedInstallmentFee.getKey()) == null
|| !legacyFeePayStatus.get(updatedInstallmentFee.getKey()) ? ZERO : demandAmount;
licenseDemand.getEgDemandDetails().add(
EgDemandDetails.fromReasonAndAmounts(demandAmount,
this.demandGenericDao.getDmdReasonByDmdReasonMsterInstallAndMod(
this.demandGenericDao.getDemandReasonMasterByCode("License Fee", module),
installment, module),
amtCollected));
}
// Recalculating BasedDemand
this.recalculateBaseDemand(licenseDemand);
}
public void recalculateBaseDemand(LicenseDemand licenseDemand) {
licenseDemand.setAmtCollected(ZERO);
licenseDemand.setBaseDemand(ZERO);
for (EgDemandDetails demandDetail : licenseDemand.getEgDemandDetails()) {
licenseDemand.setAmtCollected(licenseDemand.getAmtCollected().add(demandDetail.getAmtCollected()));
licenseDemand.setBaseDemand(licenseDemand.getBaseDemand().add(demandDetail.getAmount()));
}
}
@Transactional
public void renew(T license, WorkflowBean workflowBean) {
license.setApplicationNumber(licenseNumberUtils.generateApplicationNumber());
recalculateDemand(this.feeMatrixService.findFeeList(license), license);
license.setStatus(licenseStatusService.getLicenseStatusByName(LICENSE_STATUS_ACKNOWLEDGED));
license.setEgwStatus(egwStatusHibernateDAO.getStatusByModuleAndCode(TRADELICENSEMODULE, APPLICATION_STATUS_CREATED_CODE));
Position pos = null;
license.setLicenseAppType(this.getLicenseApplicationTypeForRenew());
User currentUser = this.securityUtils.getCurrentUser();
if (workflowBean.getApproverPositionId() != null && workflowBean.getApproverPositionId() != -1)
pos = positionMasterService.getPositionById(workflowBean.getApproverPositionId());
WorkFlowMatrix wfmatrix = this.licenseWorkflowService.getWfMatrix(license.getStateType(), null,
null, workflowBean.getAdditionaRule(), workflowBean.getCurrentState(), null);
license.reinitiateTransition().start().withSenderName(currentUser.getUsername() + "::" + currentUser.getName())
.withComments(workflowBean.getApproverComments())
.withStateValue(wfmatrix.getNextState()).withDateInfo(new DateTime().toDate()).withOwner(pos)
.withNextAction(wfmatrix.getNextAction());
this.licenseRepository.save(license);
sendEmailAndSMS(license, workflowBean.getWorkFlowAction());
updateIndexService.updateTradeLicenseIndexes(license);
}
@Transactional
public void transitionWorkFlow(T license, WorkflowBean workflowBean) {
DateTime currentDate = new DateTime();
User user = this.securityUtils.getCurrentUser();
Assignment userAssignment = this.assignmentService.getPrimaryAssignmentForUser(user.getId());
Position pos = null;
Assignment wfInitiator = null;
if (null != license.getId())
wfInitiator = this.getWorkflowInitiator(license);
if (wfInitiator != null && BUTTONREJECT.equalsIgnoreCase(workflowBean.getWorkFlowAction())) {
if ( wfInitiator.equals(userAssignment)) {
license.transition(true).end().withSenderName(user.getUsername() + "::" + user.getName())
.withComments(workflowBean.getApproverComments())
.withDateInfo(currentDate.toDate());
if (license.getLicenseAppType() != null
&& license.getLicenseAppType().getName().equals(Constants.RENEWAL_LIC_APPTYPE))
license.setLicenseAppType(this.getLicenseApplicationType());
} else {
String stateValue = license.getCurrentState().getValue().split(":")[0] + ":" + WORKFLOW_STATE_REJECTED;
license.transition(true).withSenderName(user.getUsername() + "::" + user.getName())
.withComments(workflowBean.getApproverComments())
.withStateValue(stateValue).withDateInfo(currentDate.toDate())
.withOwner(wfInitiator.getPosition()).withNextAction(WF_STATE_SANITORY_INSPECTOR_APPROVAL_PENDING);
}
} else if (GENERATECERTIFICATE.equalsIgnoreCase(workflowBean.getWorkFlowAction()))
license.transition(true).end().withSenderName(user.getUsername() + "::" + user.getName())
.withComments(workflowBean.getApproverComments())
.withDateInfo(currentDate.toDate());
else {
if (null != workflowBean.getApproverPositionId() && workflowBean.getApproverPositionId() != -1)
pos = positionMasterService.getPositionById(workflowBean.getApproverPositionId());
if (BUTTONAPPROVE.equalsIgnoreCase(workflowBean.getWorkFlowAction())) {
Assignment commissionerUsr = this.assignmentService.getPrimaryAssignmentForUser(user.getId());
pos = commissionerUsr.getPosition();
}
if (null == license.getState()) {
WorkFlowMatrix wfmatrix = this.licenseWorkflowService.getWfMatrix(license.getStateType(), null,
null, workflowBean.getAdditionaRule(), workflowBean.getCurrentState(), null);
license.transition().start().withSenderName(user.getUsername() + "::" + user.getName())
.withComments(workflowBean.getApproverComments())
.withStateValue(wfmatrix.getNextState()).withDateInfo(currentDate.toDate()).withOwner(pos)
.withNextAction(wfmatrix.getNextAction());
} else if ("END".equalsIgnoreCase(license.getCurrentState().getNextAction())) {
license.transition(true).end().withSenderName(user.getName()).withComments(workflowBean.getApproverComments())
.withDateInfo(currentDate.toDate());
} else {
WorkFlowMatrix wfmatrix = this.licenseWorkflowService.getWfMatrix(license.getStateType(), null,
null, workflowBean.getAdditionaRule(), license.getCurrentState().getValue(), null);
license.transition(true).withSenderName(user.getUsername() + "::" + user.getName())
.withComments(workflowBean.getApproverComments())
.withStateValue(wfmatrix.getNextState()).withDateInfo(currentDate.toDate()).withOwner(pos)
.withNextAction(wfmatrix.getNextAction());
}
}
}
protected Assignment getWorkflowInitiator(T license) {
return this.assignmentService.getPrimaryAssignmentForUser(license.getCreatedBy().getId());
}
@Transactional
public void processAndStoreDocument(List<LicenseDocument> documents, License license) {
documents.forEach(document -> {
document.setType(this.licenseDocumentTypeService.load(document.getType().getId(), LicenseDocumentType.class));
if (!(document.getUploads().isEmpty() || document.getUploadsContentType().isEmpty())) {
int fileCount = 0;
for (File file : document.getUploads()) {
FileStoreMapper fileStore = this.fileStoreService.store(file,
document.getUploadsFileName().get(fileCount),
document.getUploadsContentType().get(fileCount++), "EGTL");
document.getFiles().add(fileStore);
}
document.setEnclosed(true);
} else if (document.getType().isMandatory() && document.getFiles().isEmpty()) {
document.getFiles().clear();
throw new ValidationException("TL-004", "TL-004", document.getType().getName());
}
document.setDocDate(new Date());
document.setLicense(license);
});
}
public List<LicenseDocumentType> getDocumentTypesByApplicationType(ApplicationType applicationType) {
return this.documentTypeService.getDocumentTypesByApplicationType(applicationType);
}
public List<NatureOfBusiness> getAllNatureOfBusinesses() {
return natureOfBusinessService.findAll();
}
public T getLicenseByLicenseNumber(String licenseNumber) {
return (T)this.licenseRepository.findByLicenseNumber(licenseNumber);
}
public T getLicenseByApplicationNumber(String applicationNumber) {
return (T)this.licenseRepository.findByApplicationNumber(applicationNumber);
}
public List<Installment> getLastFiveYearInstallmentsForLicense() {
List<Installment> installmentList = this.installmentDao.fetchInstallments(this.getModuleName(), new Date(), 6);
Collections.reverse(installmentList);
return installmentList;
}
public Map<String, Map<String, BigDecimal>> getOutstandingFee(T license) {
Map<String, Map<String, BigDecimal>> outstandingFee = new HashMap<>();
Installment currentInstallmentYear = this.installmentDao.getInsatllmentByModuleForGivenDate(this.getModuleName(), new Date());
LicenseDemand licenseDemand = license.getCurrentDemand();
for (EgDemandDetails demandDetail : licenseDemand.getEgDemandDetails()) {
String demandReason = demandDetail.getEgDemandReason().getEgDemandReasonMaster().getReasonMaster();
Installment installmentYear = demandDetail.getEgDemandReason().getEgInstallmentMaster();
Map<String, BigDecimal> feeByTypes;
if (outstandingFee.containsKey(demandReason))
feeByTypes = outstandingFee.get(demandReason);
else {
feeByTypes = new HashMap<>();
feeByTypes.put(ARREAR, ZERO);
feeByTypes.put("current", ZERO);
}
BigDecimal demandAmount = demandDetail.getAmount().subtract(demandDetail.getAmtCollected());
if (installmentYear.equals(currentInstallmentYear))
feeByTypes.put("current", demandAmount);
else
feeByTypes.put(ARREAR, feeByTypes.get(ARREAR).add(demandAmount));
outstandingFee.put(demandReason, feeByTypes);
}
return outstandingFee;
}
public List<T> getAllLicensesByNatureOfBusiness(String natureOfBusiness) {
return this.entityQueryService.getSession().createCriteria(License.class)
.createAlias("natureOfBusiness", "nb", JoinType.LEFT_OUTER_JOIN).add(Restrictions.eq("nb.name", natureOfBusiness))
.setCacheMode(CacheMode.IGNORE).list();
}
@Transactional
public void save(License license) {
licenseRepository.save(license);
}
}